diff --git a/DiscImageChef.Filesystems/LisaFS/Dir.cs b/DiscImageChef.Filesystems/LisaFS/Dir.cs index 7623c2a00..01e47785d 100644 --- a/DiscImageChef.Filesystems/LisaFS/Dir.cs +++ b/DiscImageChef.Filesystems/LisaFS/Dir.cs @@ -97,17 +97,16 @@ namespace DiscImageChef.Filesystems.LisaFS for(ulong i = 0; i < device.GetSectors(); i++) { - byte[] tag = device.ReadSectorTag(i, SectorTagType.AppleSectorTag); - UInt16 id = BigEndianBitConverter.ToUInt16(tag, 0x04); - UInt16 pos = BigEndianBitConverter.ToUInt16(tag, 0x06); + Tag catTag; + DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out catTag); - if(id == fileId && pos == 0) + if(catTag.fileID == fileId && catTag.relBlock == 0) { firstCatalogBlock = device.ReadSectors(i, 4); break; } - if(id == -fileId) + if(catTag.fileID == -fileId) return Errno.NotDirectory; } @@ -119,13 +118,13 @@ namespace DiscImageChef.Filesystems.LisaFS while(prevCatalogPointer != 0xFFFFFFFF) { - byte[] tag = device.ReadSectorTag(prevCatalogPointer + mddf.mddf_block, SectorTagType.AppleSectorTag); - UInt16 id = BigEndianBitConverter.ToUInt16(tag, 0x04); + Tag prevTag; + DecodeTag(device.ReadSectorTag(prevCatalogPointer + mddf.mddf_block + volumePrefix, SectorTagType.AppleSectorTag), out prevTag); - if(id != fileId) + if(prevTag.fileID != fileId) return Errno.InvalidArgument; - firstCatalogBlock = device.ReadSectors(prevCatalogPointer + mddf.mddf_block, 4); + firstCatalogBlock = device.ReadSectors(prevCatalogPointer + mddf.mddf_block + volumePrefix, 4); prevCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7F6); } @@ -137,13 +136,13 @@ namespace DiscImageChef.Filesystems.LisaFS while(nextCatalogPointer != 0xFFFFFFFF) { - byte[] tag = device.ReadSectorTag(nextCatalogPointer + mddf.mddf_block, SectorTagType.AppleSectorTag); - UInt16 id = BigEndianBitConverter.ToUInt16(tag, 0x04); + Tag nextTag; + DecodeTag(device.ReadSectorTag(nextCatalogPointer + mddf.mddf_block + volumePrefix, SectorTagType.AppleSectorTag), out nextTag); - if(id != fileId) + if(nextTag.fileID != fileId) return Errno.InvalidArgument; - byte[] nextCatalogBlock = device.ReadSectors(nextCatalogPointer + mddf.mddf_block, 4); + byte[] nextCatalogBlock = device.ReadSectors(nextCatalogPointer + mddf.mddf_block + volumePrefix, 4); nextCatalogPointer = BigEndianBitConverter.ToUInt32(nextCatalogBlock, 0x7FA); catalogBlocks.Add(nextCatalogBlock); } diff --git a/DiscImageChef.Filesystems/LisaFS/Extent.cs b/DiscImageChef.Filesystems/LisaFS/Extent.cs index fff037d1e..acd0a642e 100644 --- a/DiscImageChef.Filesystems/LisaFS/Extent.cs +++ b/DiscImageChef.Filesystems/LisaFS/Extent.cs @@ -73,13 +73,13 @@ namespace DiscImageChef.Filesystems.LisaFS for(ulong i = 0; i < device.GetSectors(); i++) { - byte[] tag = device.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - Int16 foundid = BigEndianBitConverter.ToInt16(tag, 0x04); + Tag extTag; + DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out extTag); - if(foundid == fileId) + if(extTag.fileID == fileId) fileFound = true; - if(foundid == ((short)(-1 * fileId))) + if(extTag.fileID == ((short)(-1 * fileId))) { byte[] sector = device.ReadSector((ulong)i); diff --git a/DiscImageChef.Filesystems/LisaFS/File.cs b/DiscImageChef.Filesystems/LisaFS/File.cs index 9d7e7ba04..a7a4dd49c 100644 --- a/DiscImageChef.Filesystems/LisaFS/File.cs +++ b/DiscImageChef.Filesystems/LisaFS/File.cs @@ -204,13 +204,14 @@ namespace DiscImageChef.Filesystems.LisaFS int count = 0; + Tag sysTag; + // Should be enough to check 100 sectors? for(ulong i = 0; i < 100; i++) { - byte[] tag = device.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - Int16 id = BigEndianBitConverter.ToInt16(tag, 0x04); + DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out sysTag); - if(id == fileId) + if(sysTag.fileID == fileId) count++; } @@ -220,25 +221,27 @@ namespace DiscImageChef.Filesystems.LisaFS if(!tags) buf = new byte[count * device.GetSectorSize()]; else - buf = new byte[count * 12]; + buf = new byte[count * devTagSize]; // Should be enough to check 100 sectors? for(ulong i = 0; i < 100; i++) { - byte[] tag = device.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - UInt16 id = BigEndianBitConverter.ToUInt16(tag, 0x04); + DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out sysTag); - if(id == fileId) + if(sysTag.fileID == fileId) { - UInt16 pos = BigEndianBitConverter.ToUInt16(tag, 0x06); byte[] sector; if(!tags) sector = device.ReadSector(i); else sector = device.ReadSectorTag(i, SectorTagType.AppleSectorTag); - - Array.Copy(sector, 0, buf, sector.Length * pos, sector.Length); + + // Relative block for $Loader starts at $Boot block + if(sysTag.fileID == FILEID_LOADER_SIGNED) + sysTag.relBlock--; + + Array.Copy(sector, 0, buf, sector.Length * sysTag.relBlock, sector.Length); } } @@ -387,7 +390,7 @@ namespace DiscImageChef.Filesystems.LisaFS int sectorSize; if(tags) - sectorSize = 12; + sectorSize = devTagSize; else sectorSize = (int)device.GetSectorSize(); @@ -399,9 +402,9 @@ namespace DiscImageChef.Filesystems.LisaFS byte[] sector; if(!tags) - sector = device.ReadSectors((ulong)(file.extents[i].start + mddf.mddf_block), (uint)file.extents[i].length); + sector = device.ReadSectors(((ulong)file.extents[i].start + mddf.mddf_block + volumePrefix), (uint)file.extents[i].length); else - sector = device.ReadSectorsTag((ulong)(file.extents[i].start + mddf.mddf_block), (uint)file.extents[i].length, SectorTagType.AppleSectorTag); + sector = device.ReadSectorsTag(((ulong)file.extents[i].start + mddf.mddf_block + volumePrefix), (uint)file.extents[i].length, SectorTagType.AppleSectorTag); Array.Copy(sector, 0, temp, offset, sector.Length); offset += sector.Length; diff --git a/DiscImageChef.Filesystems/LisaFS/Info.cs b/DiscImageChef.Filesystems/LisaFS/Info.cs index dfb9d2b3e..abcd69c8b 100644 --- a/DiscImageChef.Filesystems/LisaFS/Info.cs +++ b/DiscImageChef.Filesystems/LisaFS/Info.cs @@ -39,6 +39,7 @@ using System; using System.Text; using DiscImageChef.Console; using DiscImageChef.ImagePlugins; +using System.Runtime.InteropServices; namespace DiscImageChef.Filesystems.LisaFS { @@ -61,15 +62,20 @@ namespace DiscImageChef.Filesystems.LisaFS if(imagePlugin.GetSectors() < 800) return false; + int before_mddf = -1; + // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors for(int i = 0; i < 100; i++) { - byte[] tag = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - UInt16 fileid = BigEndianBitConverter.ToUInt16(tag, 0x04); + Tag searchTag; + DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag), out searchTag); - DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, fileid); + DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.fileID); - if(fileid == FILEID_MDDF) + if(before_mddf == -1 && searchTag.fileID == FILEID_LOADER_SIGNED) + before_mddf = i - 1; + + if(searchTag.fileID == FILEID_MDDF) { byte[] sector = imagePlugin.ReadSector((ulong)i); MDDF mddf = new MDDF(); @@ -91,7 +97,7 @@ namespace DiscImageChef.Filesystems.LisaFS DicConsole.DebugWriteLine("LisaFS plugin", "mddf.blocksize = {0} bytes", mddf.blocksize); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.datasize = {0} bytes", mddf.datasize); - if(mddf.mddf_block != i) + if(mddf.mddf_block != i - before_mddf) return false; if(mddf.vol_size > imagePlugin.GetSectors()) @@ -100,7 +106,7 @@ namespace DiscImageChef.Filesystems.LisaFS if(mddf.vol_size - 1 != mddf.volsize_minus_one) return false; - if(mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one) + if(mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one - before_mddf) return false; if(mddf.datasize > mddf.blocksize) @@ -145,15 +151,20 @@ namespace DiscImageChef.Filesystems.LisaFS if(imagePlugin.GetSectors() < 800) return; + int before_mddf = -1; + // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors for(int i = 0; i < 100; i++) { - byte[] tag = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - UInt16 fileid = BigEndianBitConverter.ToUInt16(tag, 0x04); + Tag searchTag; + DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag), out searchTag); - DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, fileid); + DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.fileID); - if(fileid == FILEID_MDDF) + if(before_mddf == -1 && searchTag.fileID == FILEID_LOADER_SIGNED) + before_mddf = i - 1; + + if(searchTag.fileID == FILEID_MDDF) { byte[] sector = imagePlugin.ReadSector((ulong)i); MDDF mddf = new MDDF(); @@ -281,7 +292,7 @@ namespace DiscImageChef.Filesystems.LisaFS DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown38 = 0x{0:X8} ({0})", mddf.unknown38); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})", mddf.unknown_timestamp, DateHandlers.LisaToDateTime(mddf.unknown_timestamp)); - if(mddf.mddf_block != i) + if(mddf.mddf_block != i - before_mddf) return; if(mddf.vol_size > imagePlugin.GetSectors()) @@ -290,7 +301,7 @@ namespace DiscImageChef.Filesystems.LisaFS if(mddf.vol_size - 1 != mddf.volsize_minus_one) return; - if(mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one) + if(mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one - before_mddf) return; if(mddf.datasize > mddf.blocksize) @@ -334,7 +345,8 @@ namespace DiscImageChef.Filesystems.LisaFS sb.AppendFormat("Some timestamp, says {0}", mddf.dtcc).AppendLine(); sb.AppendFormat("Volume backed up on {0}", mddf.dtvb).AppendLine(); sb.AppendFormat("Volume scavenged on {0}", mddf.dtvs).AppendLine(); - sb.AppendFormat("MDDF is in block {0}", mddf.mddf_block).AppendLine(); + sb.AppendFormat("MDDF is in block {0}", mddf.mddf_block + before_mddf).AppendLine(); + sb.AppendFormat("There are {0} reserved blocks before volume", before_mddf).AppendLine(); sb.AppendFormat("{0} blocks minus one", mddf.volsize_minus_one).AppendLine(); sb.AppendFormat("{0} blocks minus one minus MDDF offset", mddf.volsize_minus_mddf_minus_one).AppendLine(); sb.AppendFormat("{0} blocks in volume", mddf.vol_size).AppendLine(); diff --git a/DiscImageChef.Filesystems/LisaFS/LisaFS.cs b/DiscImageChef.Filesystems/LisaFS/LisaFS.cs index dc41abefe..98bb23cfd 100644 --- a/DiscImageChef.Filesystems/LisaFS/LisaFS.cs +++ b/DiscImageChef.Filesystems/LisaFS/LisaFS.cs @@ -52,6 +52,8 @@ namespace DiscImageChef.Filesystems.LisaFS readonly ImagePlugin device; MDDF mddf; + ulong volumePrefix; + int devTagSize; #region Caches Dictionary extentCache; diff --git a/DiscImageChef.Filesystems/LisaFS/Structs.cs b/DiscImageChef.Filesystems/LisaFS/Structs.cs index a2084d576..dde286920 100644 --- a/DiscImageChef.Filesystems/LisaFS/Structs.cs +++ b/DiscImageChef.Filesystems/LisaFS/Structs.cs @@ -205,20 +205,37 @@ namespace DiscImageChef.Filesystems.LisaFS struct Tag { - /// 0x00 Unknown + /// 0x00 version + public UInt16 version; + /// 0x02 unknown public UInt16 unknown; - /// 0x02 File type - public byte fileType; - /// Seems to be always zero - public byte zero; /// 0x04 File ID. Negative numbers are extents for the file with same absolute value number public Int16 fileID; - /// 0x06 Relative block + /// Only in 20 bytes tag at 0x06, mask 0x8000 if valid tag + public UInt16 usedBytes; + /// Only in 20 bytes tag at 0x08, 3 bytes + public UInt32 absoluteBlock; + /// Only in 20 bytes tag at 0x0B, checksum byte + public byte checksum; + /// 0x06 in 12 bytes tag, 0x0C in 20 bytes tag, relative block public UInt16 relBlock; - /// 0x08 Next block for this file. 0x8000 bit seems always set, 0x07FF means this is last block - public UInt16 nextBlock; - /// 0x0A Previous block for this file. 0x07FF means this is first block. - public UInt16 prevBlock; + /// + /// Next block for this file. + /// In 12 bytes tag at 0x08, 2 bytes, 0x8000 bit seems always set, 0x07FF means this is last block. + /// In 20 bytes tag at 0x0E, 3 bytes, 0xFFFFFF means this is last block. + /// + public UInt32 nextBlock; + /// + /// Previous block for this file. + /// In 12 bytes tag at 0x0A, 2 bytes, 0x07FF means this is first block. + /// In 20 bytes tag at 0x11, 3 bytes, 0xFFFFFF means this is first block. + /// + public UInt32 prevBlock; + + /// On-memory value for easy first block search. + public bool isFirst; + /// On-memory value for easy last block search. + public bool isLast; } struct CatalogEntry diff --git a/DiscImageChef.Filesystems/LisaFS/Super.cs b/DiscImageChef.Filesystems/LisaFS/Super.cs index 7fa5336ff..e72f05cc0 100644 --- a/DiscImageChef.Filesystems/LisaFS/Super.cs +++ b/DiscImageChef.Filesystems/LisaFS/Super.cs @@ -71,16 +71,24 @@ namespace DiscImageChef.Filesystems.LisaFS return Errno.InOutError; } + // MDDF cannot be at end of device, of course + volumePrefix = device.ImageInfo.sectors; + // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors - for(int i = 0; i < 100; i++) + for(ulong i = 0; i < 100; i++) { - byte[] tag = device.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag); - UInt16 fileid = BigEndianBitConverter.ToUInt16(tag, 0x04); + Tag searchTag; + DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out searchTag); - DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, fileid); + DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.fileID); - if(fileid == FILEID_MDDF) + if(volumePrefix == device.ImageInfo.sectors && searchTag.fileID == FILEID_LOADER_SIGNED) + volumePrefix = i - 1; + + if(searchTag.fileID == FILEID_MDDF) { + devTagSize = device.ReadSectorTag(i, SectorTagType.AppleSectorTag).Length; + byte[] sector = device.ReadSector((ulong)i); mddf = new MDDF(); byte[] pString = new byte[33]; @@ -167,10 +175,10 @@ namespace DiscImageChef.Filesystems.LisaFS mddf.vol_sequence = BigEndianBitConverter.ToUInt16(sector, 0x136); mddf.vol_left_mounted = sector[0x138]; - if(mddf.mddf_block != i || + if(mddf.mddf_block != i - volumePrefix || mddf.vol_size > device.GetSectors() || mddf.vol_size - 1 != mddf.volsize_minus_one || - mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one || + mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one - volumePrefix || mddf.datasize > mddf.blocksize || mddf.blocksize < device.GetSectorSize() || mddf.datasize != device.GetSectorSize()) diff --git a/DiscImageChef.Filesystems/LisaFS/Xattr.cs b/DiscImageChef.Filesystems/LisaFS/Xattr.cs index 703f9857d..09984890f 100644 --- a/DiscImageChef.Filesystems/LisaFS/Xattr.cs +++ b/DiscImageChef.Filesystems/LisaFS/Xattr.cs @@ -177,6 +177,50 @@ namespace DiscImageChef.Filesystems.LisaFS return Errno.NoSuchExtendedAttribute; } + + Errno DecodeTag(byte[] tag, out Tag decoded) + { + decoded = new Tag(); + + if(tag.Length == 12) + { + decoded.version = BigEndianBitConverter.ToUInt16(tag, 0x00); + decoded.unknown = BigEndianBitConverter.ToUInt16(tag, 0x02); + decoded.fileID = BigEndianBitConverter.ToInt16(tag, 0x04); + decoded.relBlock = BigEndianBitConverter.ToUInt16(tag, 0x06); + decoded.nextBlock = BigEndianBitConverter.ToUInt16(tag, 0x08); + decoded.nextBlock &= 0x7FF; + decoded.prevBlock = BigEndianBitConverter.ToUInt16(tag, 0x0A); + decoded.prevBlock &= 0x7FF; + + if(decoded.nextBlock == 0x7FF) + decoded.isLast = true; + if(decoded.prevBlock == 0x7FF) + decoded.isFirst = true; + } + else + { + decoded.version = BigEndianBitConverter.ToUInt16(tag, 0x00); + decoded.unknown = BigEndianBitConverter.ToUInt16(tag, 0x02); + decoded.fileID = BigEndianBitConverter.ToInt16(tag, 0x04); + decoded.usedBytes = BigEndianBitConverter.ToUInt16(tag, 0x06); + decoded.absoluteBlock = BigEndianBitConverter.ToUInt32(tag, 0x07); + decoded.absoluteBlock &= 0xFFFFFF; + decoded.checksum = tag[0x0B]; + decoded.relBlock = BigEndianBitConverter.ToUInt16(tag, 0x0C); + decoded.nextBlock = BigEndianBitConverter.ToUInt32(tag, 0x0D); + decoded.nextBlock &= 0xFFFFFF; + decoded.prevBlock = BigEndianBitConverter.ToUInt32(tag, 0x10); + decoded.prevBlock &= 0xFFFFFF; + + if(decoded.nextBlock == 0xFFFFFF) + decoded.isLast = true; + if(decoded.prevBlock == 0xFFFFFF) + decoded.isFirst = true; + } + + return Errno.NoError; + } } }