Implement support for the Twiggy spare bad block sector track, allowing to read disks with remapped sectors.

Fixes reading currently on-the-wild dump of LOS 1.2.
This commit is contained in:
2026-06-19 10:55:42 +01:00
parent 35ba3780fb
commit 3c04ceda2a
5 changed files with 70 additions and 70 deletions

View File

@@ -127,7 +127,7 @@ public sealed partial class LisaFS
// If root catalog is not pointed in MDDF (unchecked) maybe it's always following S-Records File?
for(ulong i = 0; i < _device.Info.Sectors; i++)
{
errno = _device.ReadSectorTag(i, false, SectorTagType.AppleSonyTag, out byte[] tag);
errno = ReadLisaSectorTag(i, out byte[] tag);
if(errno != ErrorNumber.NoError) continue;
@@ -135,7 +135,7 @@ public sealed partial class LisaFS
if(catTag.FileId != FILEID_CATALOG || catTag.RelPage != 0) continue;
errno = _device.ReadSectors(i, false, 4, out firstCatalogBlock, out _);
errno = ReadLisaSectors(i, 4, out firstCatalogBlock);
if(errno != ErrorNumber.NoError) return errno;
@@ -150,10 +150,7 @@ public sealed partial class LisaFS
// Traverse double-linked list until first catalog block
while(prevCatalogPointer != 0xFFFFFFFF)
{
errno = _device.ReadSectorTag(prevCatalogPointer + _mddf.mddf_block + _volumePrefix,
false,
SectorTagType.AppleSonyTag,
out byte[] tag);
errno = ReadLisaSectorTag(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, out byte[] tag);
if(errno != ErrorNumber.NoError) return errno;
@@ -161,11 +158,7 @@ public sealed partial class LisaFS
if(prevTag.FileId != FILEID_CATALOG) return ErrorNumber.InvalidArgument;
errno = _device.ReadSectors(prevCatalogPointer + _mddf.mddf_block + _volumePrefix,
false,
4,
out firstCatalogBlock,
out _);
errno = ReadLisaSectors(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, 4, out firstCatalogBlock);
if(errno != ErrorNumber.NoError) return errno;
@@ -179,10 +172,7 @@ public sealed partial class LisaFS
// Traverse double-linked list to read full catalog
while(nextCatalogPointer != 0xFFFFFFFF)
{
errno = _device.ReadSectorTag(nextCatalogPointer + _mddf.mddf_block + _volumePrefix,
false,
SectorTagType.AppleSonyTag,
out byte[] tag);
errno = ReadLisaSectorTag(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, out byte[] tag);
if(errno != ErrorNumber.NoError) return errno;
@@ -190,11 +180,9 @@ public sealed partial class LisaFS
if(nextTag.FileId != FILEID_CATALOG) return ErrorNumber.InvalidArgument;
errno = _device.ReadSectors(nextCatalogPointer + _mddf.mddf_block + _volumePrefix,
false,
4,
out byte[] nextCatalogBlock,
out _);
errno = ReadLisaSectors(nextCatalogPointer + _mddf.mddf_block + _volumePrefix,
4,
out byte[] nextCatalogBlock);
if(errno != ErrorNumber.NoError) return errno;
@@ -401,4 +389,4 @@ public sealed partial class LisaFS
}
#endregion
}
}

View File

@@ -57,11 +57,16 @@ public sealed partial class LisaFS
ulong ptr = _srecords[fileId].extent_ptr;
// An invalid pointer denotes file does not exist
if(ptr is 0xFFFFFFFF or 0x00000000) return ErrorNumber.NoSuchFile;
var searchExtentByTag = false;
// Pointers are relative to MDDF
ptr += _mddf.mddf_block + _volumePrefix;
if(ptr is not 0xFFFFFFFF and not 0x00000000) ptr += _mddf.mddf_block + _volumePrefix;
else
{
if(_srecords[fileId].filesize == 0) return ErrorNumber.NoSuchFile;
searchExtentByTag = true;
}
LisaTag.PriamTag extTag;
byte[] tag;
@@ -69,19 +74,19 @@ public sealed partial class LisaFS
// This happens on some disks.
// This is a filesystem corruption that makes LisaOS crash on scavenge.
// This code just allow to ignore that corruption by searching the Extents File using sector tags
if(ptr >= _device.Info.Sectors)
if(searchExtentByTag || ptr >= _device.Info.Sectors)
{
var found = false;
for(ulong i = 0; i < _device.Info.Sectors; i++)
{
errno = _device.ReadSectorTag(i, false, SectorTagType.AppleSonyTag, out tag);
errno = ReadLisaSectorTag(i, out tag);
if(errno != ErrorNumber.NoError) continue;
DecodeTag(tag, out extTag);
if(extTag.FileId != fileId * -1) continue;
if(extTag.FileId != fileId * -1 || extTag.RelPage != 0) continue;
ptr = i;
found = true;
@@ -93,17 +98,36 @@ public sealed partial class LisaFS
}
// Checks that the sector tag indicates its the Extents File we are searching for
errno = _device.ReadSectorTag(ptr, false, SectorTagType.AppleSonyTag, out tag);
errno = ReadLisaSectorTag(ptr, out tag);
if(errno != ErrorNumber.NoError) return errno;
DecodeTag(tag, out extTag);
if(extTag.FileId != (short)(-1 * fileId)) return ErrorNumber.NoSuchFile;
if(extTag.FileId != (short)(-1 * fileId) || extTag.RelPage != 0)
{
var found = false;
errno = _mddf.fsversion == LISA_V1
? _device.ReadSectors(ptr, false, 2, out byte[] sector, out _)
: _device.ReadSector(ptr, false, out sector, out _);
for(ulong i = 0; i < _device.Info.Sectors; i++)
{
errno = ReadLisaSectorTag(i, out tag);
if(errno != ErrorNumber.NoError) continue;
DecodeTag(tag, out extTag);
if(extTag.FileId != fileId * -1 || extTag.RelPage != 0) continue;
ptr = i;
found = true;
break;
}
if(!found) return ErrorNumber.NoSuchFile;
}
errno = _mddf.fsversion == LISA_V1 ? ReadLisaSectors(ptr, 2, out byte[] sector) : ReadLisaSector(ptr, out sector);
if(errno != ErrorNumber.NoError) return errno;
@@ -306,11 +330,8 @@ public sealed partial class LisaFS
if(!_mounted) return ErrorNumber.AccessDenied;
// Searches the S-Records place using MDDF pointers
ErrorNumber errno = _device.ReadSectors(_mddf.srec_ptr + _mddf.mddf_block + _volumePrefix,
false,
_mddf.srec_len,
out byte[] sectors,
out _);
ErrorNumber errno =
ReadLisaSectors(_mddf.srec_ptr + _mddf.mddf_block + _volumePrefix, _mddf.srec_len, out byte[] sectors);
if(errno != ErrorNumber.NoError) return errno;
@@ -330,4 +351,4 @@ public sealed partial class LisaFS
return ErrorNumber.NoError;
}
}
}

View File

@@ -117,11 +117,7 @@ public sealed partial class LisaFS
{
if(!tags)
{
errno = _device.ReadSectors(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr,
false,
_mddf.srec_len,
out buf,
out _);
errno = ReadLisaSectors(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr, _mddf.srec_len, out buf);
if(errno != ErrorNumber.NoError) return errno;
@@ -130,11 +126,7 @@ public sealed partial class LisaFS
return ErrorNumber.NoError;
}
errno = _device.ReadSectorsTag(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr,
false,
_mddf.srec_len,
SectorTagType.AppleSonyTag,
out buf);
errno = ReadLisaSectorsTag(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr, _mddf.srec_len, out buf);
return errno != ErrorNumber.NoError ? errno : ErrorNumber.NoError;
}
@@ -144,7 +136,7 @@ public sealed partial class LisaFS
// Should be enough to check 100 sectors?
for(ulong i = 0; i < 100; i++)
{
errno = _device.ReadSectorTag(i, false, SectorTagType.AppleSonyTag, out byte[] tag);
errno = ReadLisaSectorTag(i, out byte[] tag);
if(errno != ErrorNumber.NoError) continue;
@@ -160,7 +152,7 @@ public sealed partial class LisaFS
// Should be enough to check 100 sectors?
for(ulong i = 0; i < 100; i++)
{
errno = _device.ReadSectorTag(i, false, SectorTagType.AppleSonyTag, out byte[] tag);
errno = ReadLisaSectorTag(i, out byte[] tag);
if(errno != ErrorNumber.NoError) continue;
@@ -168,9 +160,7 @@ public sealed partial class LisaFS
if(sysTag.FileId != fileId) continue;
errno = !tags
? _device.ReadSector(i, false, out byte[] sector, out _)
: _device.ReadSectorTag(i, false, SectorTagType.AppleSonyTag, out sector);
errno = !tags ? ReadLisaSector(i, out byte[] sector) : ReadLisaSectorTag(i, out sector);
if(errno != ErrorNumber.NoError) continue;
@@ -306,20 +296,16 @@ public sealed partial class LisaFS
for(var i = 0; i < file.extents.Length; i++)
{
ErrorNumber errno = !tags
? _device.ReadSectors((ulong)file.extents[i].start +
_mddf.mddf_block +
_volumePrefix,
false,
(uint)file.extents[i].length,
out byte[] sector,
out _)
: _device.ReadSectorsTag((ulong)file.extents[i].start +
_mddf.mddf_block +
_volumePrefix,
false,
(uint)file.extents[i].length,
SectorTagType.AppleSonyTag,
out sector);
? ReadLisaSectors((ulong)file.extents[i].start +
_mddf.mddf_block +
_volumePrefix,
(uint)file.extents[i].length,
out byte[] sector)
: ReadLisaSectorsTag((ulong)file.extents[i].start +
_mddf.mddf_block +
_volumePrefix,
(uint)file.extents[i].length,
out sector);
if(errno != ErrorNumber.NoError) return errno;
@@ -537,4 +523,4 @@ public sealed partial class LisaFS
}
#endregion
}
}

View File

@@ -30,6 +30,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using Aaru.CommonTypes.AaruMetadata;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -48,6 +49,7 @@ public sealed partial class LisaFS : IReadOnlyFilesystem
MDDF _mddf;
bool _mounted;
SRecord[] _srecords;
Dictionary<ulong, ulong> _twiggyBadBlockMap;
ulong _volumePrefix;
static Dictionary<string, string> GetDefaultOptions() => new()
@@ -106,4 +108,4 @@ public sealed partial class LisaFS : IReadOnlyFilesystem
Dictionary<short, DateTime> _directoryDtcCache;
#endregion Caches
}
}

View File

@@ -230,6 +230,8 @@ public sealed partial class LisaFS
if(_debug) _printedExtents = [];
InitializeTwiggyBadBlockMap();
// Read the S-Records file
ErrorNumber error = ReadSRecords();
@@ -356,6 +358,7 @@ public sealed partial class LisaFS
_fileSizeCache = null;
_printedExtents = null;
_mddf = new MDDF();
_twiggyBadBlockMap = null;
_volumePrefix = 0;
_devTagSize = 0;
_srecords = null;
@@ -398,4 +401,4 @@ public sealed partial class LisaFS
}
#endregion
}
}