// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : RDB.cs // Author(s) : Natalia Portillo // // Component : Partitioning scheme plugins. // // --[ Description ] ---------------------------------------------------------- // // Manages Amiga Rigid Disk Block. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2018 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using DiscImageChef.Checksums; using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.DiscImages; namespace DiscImageChef.Partitions { public class AmigaRigidDiskBlock : PartitionPlugin { /// /// RDB magic number "RDSK" /// const uint RIGID_DISK_BLOCK_MAGIC = 0x5244534B; /// /// Bad block list magic number "BADB" /// const uint BAD_BLOCK_LIST_MAGIC = 0x42414442; /// /// Partition entry magic number "PART" /// const uint PARTITION_BLOCK_MAGIC = 0x50415254; /// /// Filesystem header magic number "FSHD" /// const uint FILESYSTEM_HEADER_MAGIC = 0x46534844; /// /// LoadSeg block magic number "LSEG" /// const uint LOAD_SEG_MAGIC = 0x4C534547; /// /// Type ID for Amiga Original File System, "DOS\0" /// const uint TYPEID_OFS = 0x444F5300; /// /// Type ID for Amiga Fast File System, "DOS\1" /// const uint TYPEID_FFS = 0x444F5301; /// /// Type ID for Amiga Original File System with international characters, "DOS\2" /// const uint TYPEID_OFS_INTL = 0x444F5302; /// /// Type ID for Amiga Fast File System with international characters, "DOS\3" /// const uint TYPEID_FFS_INTL = 0x444F5303; /// /// Type ID for Amiga Original File System with directory cache, "DOS\4" /// const uint TYPEID_OFS_CACHE = 0x444F5304; /// /// Type ID for Amiga Fast File System with directory cache, "DOS\5" /// const uint TYPEID_FFS_CACHE = 0x444F5305; /// /// Type ID for Amiga Original File System with long filenames, "DOS\6" /// const uint TYPEID_OFS2 = 0x444F5306; /// /// Type ID for Amiga Fast File System with long filenames, "DOS\7" /// const uint TYPEID_FFS2 = 0x444F5307; /// /// Type ID for Amiga UNIX boot filesystem /// const uint TYPEID_AMIX_BOOT = 0x554E4900; /// /// Type ID for Amiga UNIX System V filesystem /// const uint TYPEID_AMIX_SYSV = 0x554E4901; /// /// Type ID for Amiga UNIX BSD filesystem /// const uint TYPEID_AMIX_FFS = 0x554E4902; /// /// Type ID for Amiga UNIX Reserved partition (swap) /// const uint TYPEID_AMIX_RESERVED = 0x72657376; /// /// Type ID for ProfessionalFileSystem, "PFS\1" /// const uint TYPEID_PFS = 0x50465301; /// /// Type ID for ProfessionalFileSystem, "PFS\2" /// const uint TYPEID_PFS2 = 0x50465302; /// /// Type ID for ProfessionalFileSystem, "muAF" /// const uint TYPEID_PFS_MUSER = 0x6D754146; /// /// Type ID for ProfessionalFileSystem, "AFS\1" /// const uint TYPEID_AFS = 0x41465301; /// /// Type ID for SmartFileSystem v1, "SFS\0" /// const uint TYPEID_SFS = 0x53465300; /// /// Type ID for SmartFileSystem v2, "SFS\2" /// const uint TYPEID_SFS2 = 0x53465302; /// /// Type ID for JXFS, "JXF\4" /// const uint TYPEID_JXFS = 0x4A584604; /// /// Type ID for FAT, as set by CrossDOS, "MSD\0" /// const uint TYPEID_CROSS_DOS = 0x4D534400; /// /// Type ID for HFS, as set by CrossMac, "MAC\0" /// const uint TYPEID_CROSS_MAC = 0x4D414300; /// /// Type ID for 4.2UFS, for BFFS, "BFFS" /// const uint TYPEID_BFFS = 0x42464653; /// /// Type ID for Amiga Original File System with multi-user patches, "muF\0" /// const uint TYPEID_OFS_MUSER = 0x6D754600; /// /// Type ID for Amiga Fast File System with multi-user patches, "muF\1" /// const uint TYPEID_FFS_MUSER = 0x6D754601; /// /// Type ID for Amiga Original File System with international characters and multi-user patches, "muF\2" /// const uint TYPEID_OFS_INTL_MUSER = 0x6D754602; /// /// Type ID for Amiga Fast File System with international characters and multi-user patches, "muF\3" /// const uint TYPEID_FFS_INTL_MUSER = 0x6D754603; /// /// Type ID for Amiga Original File System with directory cache and multi-user patches, "muF\4" /// const uint TYPEID_OFS_CACHE_MUSER = 0x6D754604; /// /// Type ID for Amiga Fast File System with directory cache and multi-user patches, "muF\5" /// const uint TYPEID_FFS_CACHE_MUSER = 0x6D754605; /// /// Type ID for BSD unused, "BSD\0" /// const uint TYPEID_OLD_BSD_UNUSED = 0x42534400; /// /// Type ID for BSD swap, "BSD\1" /// const uint TYPEID_OLD_BSD_SWAP = 0x42534401; /// /// Type ID for BSD 4.2 FFS, "BSD\7" /// const uint TYPEID_OLD_BSD42_FFS = 0x42534407; /// /// Type ID for BSD 4.4 LFS, "BSD\9" /// const uint TYPEID_OLD_BSD44_LFS = 0x42534409; /// /// Type ID for NetBSD unused root partition, "NBR\0" /// const uint TYPEID_NETBSD_ROOT_UNUSED = 0x4E425200; /// /// Type ID for NetBSD 4.2 FFS root partition, "NBR\7" /// const uint TYPEID_NETBSD_ROOT_42FFS = 0x4E425207; /// /// Type ID for NetBSD 4.4 LFS root partition, "NBR\9" /// const uint TYPEID_NETBSD_ROOT_44LFS = 0x4E425209; /// /// Type ID for NetBSD unused user partition, "NBR\0" /// const uint TYPEID_NETBSD_USER_UNUSED = 0x4E425500; /// /// Type ID for NetBSD 4.2 FFS user partition, "NBR\7" /// const uint TYPEID_NETBSD_USER_42FFS = 0x4E425507; /// /// Type ID for NetBSD 4.4 LFS user partition, "NBR\9" /// const uint TYPEID_NETBSD_USER_44LFS = 0x4E425509; /// /// Type ID for NetBSD swap partition /// const uint TYPEID_NETBSD_SWAP = 0x4E425300; /// /// Type ID for Linux filesystem partition, "LNX\0" /// const uint TYPEID_LINUX = 0x4C4E5800; /// /// Type ID for Linux swap partition, "SWP\0" /// const uint TYPEID_LINUX_SWAP = 0x53575000; /// /// Type ID for RaidFrame partition, "RAID" /// const uint TYPEID_RAID_FRAME = 0x52414944; /// /// Type ID for RaidFrame partition, "RAI\0" /// const uint TYPEID_RAID_FRAME0 = 0x52414900; /// /// No disks to be configured after this one /// const uint FLAGS_NO_DISKS = 0x00000001; /// /// No LUNs to be configured after this one /// const uint FLAGS_NO_LUNS = 0x00000002; /// /// No target IDs to be configured after this one /// const uint FLAGS_NO_TARGETS = 0x00000004; /// /// Don't try to perform reselection with this drive /// const uint FLAGS_NO_RESELECTION = 0x00000008; /// /// Disk identification is valid /// const uint FLAGS_VALID_DISK_ID = 0x00000010; /// /// Controller identification is valid /// const uint FLAGS_VALID_CONTROLLER_ID = 0x00000020; /// /// Drive supports synchronous SCSI mode /// const uint FLAGS_SYNCH_SCSI = 0x00000040; /// /// Partition is bootable /// const uint FLAGS_BOOTABLE = 0x00000001; /// /// Partition should not be mounted automatically /// const uint FLAGS_NO_AUTOMOUNT = 0x00000002; public AmigaRigidDiskBlock() { Name = "Amiga Rigid Disk Block"; PluginUuid = new Guid("8D72ED97-1854-4170-9CE4-6E8446FD9863"); } public override bool GetInformation(ImagePlugin imagePlugin, out List partitions, ulong sectorOffset) { partitions = new List(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; ulong rdbBlock = 0; bool foundRdb = false; while(rdbBlock < 16) { if(imagePlugin.GetSectors() <= rdbBlock) return false; if(rdbBlock + sectorOffset >= imagePlugin.GetSectors()) break; byte[] tmpSector = imagePlugin.ReadSector(rdbBlock + sectorOffset); uint magic = BigEndianBitConverter.ToUInt32(tmpSector, 0); DicConsole.DebugWriteLine("Amiga RDB plugin", "Possible magic at block {0} is 0x{1:X8}", rdbBlock, magic); if(magic == RIGID_DISK_BLOCK_MAGIC) { DicConsole.DebugWriteLine("Amiga RDB plugin", "Found RDB magic at block {0}", rdbBlock); foundRdb = true; break; } rdbBlock++; } if(!foundRdb) return false; rdbBlock += sectorOffset; RigidDiskBlock rdb = new RigidDiskBlock(); byte[] sector = imagePlugin.ReadSector(rdbBlock); rdb.Magic = BigEndianBitConverter.ToUInt32(sector, 0x00); rdb.Size = BigEndianBitConverter.ToUInt32(sector, 0x04); rdb.Checksum = BigEndianBitConverter.ToInt32(sector, 0x08); rdb.TargetId = BigEndianBitConverter.ToUInt32(sector, 0x0C); rdb.BlockSize = BigEndianBitConverter.ToUInt32(sector, 0x10); rdb.Flags = BigEndianBitConverter.ToUInt32(sector, 0x04); rdb.BadblockPtr = BigEndianBitConverter.ToUInt32(sector, 0x18); rdb.PartitionPtr = BigEndianBitConverter.ToUInt32(sector, 0x1C); rdb.FsheaderPtr = BigEndianBitConverter.ToUInt32(sector, 0x20); rdb.Driveinitcode = BigEndianBitConverter.ToUInt32(sector, 0x24); rdb.Reserved1 = BigEndianBitConverter.ToUInt32(sector, 0x28); rdb.Reserved2 = BigEndianBitConverter.ToUInt32(sector, 0x2C); rdb.Reserved3 = BigEndianBitConverter.ToUInt32(sector, 0x30); rdb.Reserved4 = BigEndianBitConverter.ToUInt32(sector, 0x34); rdb.Reserved5 = BigEndianBitConverter.ToUInt32(sector, 0x38); rdb.Reserved6 = BigEndianBitConverter.ToUInt32(sector, 0x3C); rdb.Cylinders = BigEndianBitConverter.ToUInt32(sector, 0x40); rdb.Spt = BigEndianBitConverter.ToUInt32(sector, 0x44); rdb.Heads = BigEndianBitConverter.ToUInt32(sector, 0x48); rdb.Interleave = BigEndianBitConverter.ToUInt32(sector, 0x4C); rdb.Parking = BigEndianBitConverter.ToUInt32(sector, 0x50); rdb.Reserved7 = BigEndianBitConverter.ToUInt32(sector, 0x54); rdb.Reserved8 = BigEndianBitConverter.ToUInt32(sector, 0x58); rdb.Reserved9 = BigEndianBitConverter.ToUInt32(sector, 0x5C); rdb.Writeprecomp = BigEndianBitConverter.ToUInt32(sector, 0x60); rdb.Reducedwrite = BigEndianBitConverter.ToUInt32(sector, 0x64); rdb.Steprate = BigEndianBitConverter.ToUInt32(sector, 0x68); rdb.Reserved10 = BigEndianBitConverter.ToUInt32(sector, 0x6C); rdb.Reserved11 = BigEndianBitConverter.ToUInt32(sector, 0x70); rdb.Reserved12 = BigEndianBitConverter.ToUInt32(sector, 0x74); rdb.Reserved13 = BigEndianBitConverter.ToUInt32(sector, 0x78); rdb.Reserved14 = BigEndianBitConverter.ToUInt32(sector, 0x7C); rdb.RdbBlockLow = BigEndianBitConverter.ToUInt32(sector, 0x80); rdb.RdbBlockHigh = BigEndianBitConverter.ToUInt32(sector, 0x84); rdb.LowCylinder = BigEndianBitConverter.ToUInt32(sector, 0x88); rdb.HighCylinder = BigEndianBitConverter.ToUInt32(sector, 0x8C); rdb.CylBlocks = BigEndianBitConverter.ToUInt32(sector, 0x90); rdb.AutoParkSeconds = BigEndianBitConverter.ToUInt32(sector, 0x94); rdb.HighCylinder = BigEndianBitConverter.ToUInt32(sector, 0x98); rdb.Reserved15 = BigEndianBitConverter.ToUInt32(sector, 0x9C); byte[] tmpString = new byte[8]; Array.Copy(sector, 0xA0, tmpString, 0, 8); rdb.DiskVendor = StringHandlers.SpacePaddedToString(tmpString); tmpString = new byte[16]; Array.Copy(sector, 0xA8, tmpString, 0, 16); rdb.DiskProduct = StringHandlers.SpacePaddedToString(tmpString); tmpString = new byte[4]; Array.Copy(sector, 0xB8, tmpString, 0, 4); rdb.DiskRevision = StringHandlers.SpacePaddedToString(tmpString); tmpString = new byte[8]; Array.Copy(sector, 0xBC, tmpString, 0, 8); rdb.ControllerVendor = StringHandlers.SpacePaddedToString(tmpString); tmpString = new byte[16]; Array.Copy(sector, 0xC4, tmpString, 0, 16); rdb.ControllerProduct = StringHandlers.SpacePaddedToString(tmpString); tmpString = new byte[4]; Array.Copy(sector, 0xD4, tmpString, 0, 4); rdb.ControllerRevision = StringHandlers.SpacePaddedToString(tmpString); rdb.Reserved16 = BigEndianBitConverter.ToUInt32(sector, 0xD8); rdb.Reserved17 = BigEndianBitConverter.ToUInt32(sector, 0xDC); rdb.Reserved18 = BigEndianBitConverter.ToUInt32(sector, 0xE0); rdb.Reserved19 = BigEndianBitConverter.ToUInt32(sector, 0xE4); rdb.Reserved20 = BigEndianBitConverter.ToUInt32(sector, 0xE8); rdb.Reserved21 = BigEndianBitConverter.ToUInt32(sector, 0xEC); rdb.Reserved22 = BigEndianBitConverter.ToUInt32(sector, 0xF0); rdb.Reserved23 = BigEndianBitConverter.ToUInt32(sector, 0xF4); rdb.Reserved24 = BigEndianBitConverter.ToUInt32(sector, 0xF8); rdb.Reserved25 = BigEndianBitConverter.ToUInt32(sector, 0xFC); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.magic = 0x{0:X8}", rdb.Magic); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.size = {0} longs, {1} bytes", rdb.Size, rdb.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.checksum = 0x{0:X8}", rdb.Checksum); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.targetID = {0}", rdb.TargetId); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.block_size = {0}", rdb.BlockSize); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.badblock_ptr = {0}", rdb.BadblockPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.partition_ptr = {0}", rdb.PartitionPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.fsheader_ptr = {0}", rdb.FsheaderPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.driveinitcode = {0}", rdb.Driveinitcode); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved1 = 0x{0:X8}", rdb.Reserved1); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved2 = 0x{0:X8}", rdb.Reserved2); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved3 = 0x{0:X8}", rdb.Reserved3); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved4 = 0x{0:X8}", rdb.Reserved4); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved5 = 0x{0:X8}", rdb.Reserved5); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved6 = 0x{0:X8}", rdb.Reserved6); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.cylinders = {0}", rdb.Cylinders); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.spt = {0}", rdb.Spt); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.heads = {0}", rdb.Heads); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.interleave = {0}", rdb.Interleave); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.parking = {0}", rdb.Parking); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved7 = 0x{0:X8}", rdb.Reserved7); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved8 = 0x{0:X8}", rdb.Reserved8); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved9 = 0x{0:X8}", rdb.Reserved9); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.writeprecomp = {0}", rdb.Writeprecomp); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reducedwrite = {0}", rdb.Reducedwrite); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.steprate = {0}", rdb.Steprate); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved10 = 0x{0:X8}", rdb.Reserved10); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved11 = 0x{0:X8}", rdb.Reserved11); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved12 = 0x{0:X8}", rdb.Reserved12); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved13 = 0x{0:X8}", rdb.Reserved13); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved14 = 0x{0:X8}", rdb.Reserved14); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.RDBBlockLow = {0}", rdb.RdbBlockLow); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.RDBBlockHigh = {0}", rdb.RdbBlockHigh); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.LowCylinder = {0}", rdb.LowCylinder); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.HighCylinder = {0}", rdb.HighCylinder); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.CylBlocks = {0}", rdb.CylBlocks); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.AutoParkSeconds = {0}", rdb.AutoParkSeconds); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.HighCylinder = {0}", rdb.HighCylinder); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved15 = 0x{0:X8}", rdb.Reserved15); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.diskVendor = \"{0}\"", rdb.DiskVendor); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.diskProduct = \"{0}\"", rdb.DiskProduct); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.diskRevision = \"{0}\"", rdb.DiskRevision); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.controllerVendor = \"{0}\"", rdb.ControllerVendor); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.controllerProduct = \"{0}\"", rdb.ControllerProduct); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.controllerRevision = \"{0}\"", rdb.ControllerRevision); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved16 = 0x{0:X8}", rdb.Reserved16); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved17 = 0x{0:X8}", rdb.Reserved17); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved18 = 0x{0:X8}", rdb.Reserved18); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved19 = 0x{0:X8}", rdb.Reserved19); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved20 = 0x{0:X8}", rdb.Reserved20); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved21 = 0x{0:X8}", rdb.Reserved21); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved22 = 0x{0:X8}", rdb.Reserved22); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved23 = 0x{0:X8}", rdb.Reserved23); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved24 = 0x{0:X8}", rdb.Reserved24); DicConsole.DebugWriteLine("Amiga RDB plugin", "RDB.reserved25 = 0x{0:X8}", rdb.Reserved25); ulong nextBlock; // Reading BadBlock list List badBlockChain = new List(); nextBlock = rdb.BadblockPtr; while(nextBlock != 0xFFFFFFFF) { DicConsole.DebugWriteLine("Amiga RDB plugin", "Going to block {0} in search of a BadBlock block", nextBlock); sector = imagePlugin.ReadSector(nextBlock); uint magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != BAD_BLOCK_LIST_MAGIC) break; DicConsole.DebugWriteLine("Amiga RDB plugin", "Found BadBlock block"); BadBlockList chainEntry = new BadBlockList { Magic = BigEndianBitConverter.ToUInt32(sector, 0x00), Size = BigEndianBitConverter.ToUInt32(sector, 0x04), Checksum = BigEndianBitConverter.ToInt32(sector, 0x08), TargetId = BigEndianBitConverter.ToUInt32(sector, 0x0C), NextPtr = BigEndianBitConverter.ToUInt32(sector, 0x10), Reserved = BigEndianBitConverter.ToUInt32(sector, 0x14) }; ulong entries = (chainEntry.Size - 6) / 2; chainEntry.BlockPairs = new BadBlockEntry[entries]; DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.magic = 0x{0:X8}", chainEntry.Magic); DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.size = {0} longs, {1} bytes", chainEntry.Size, chainEntry.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.checksum = 0x{0:X8}", chainEntry.Checksum); DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.targetID = {0}", chainEntry.TargetId); DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.next_ptr = {0}", chainEntry.NextPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "chainEntry.reserved = 0x{0:X8}", chainEntry.Reserved); for(ulong i = 0; i < entries; i++) { chainEntry.BlockPairs[i].BadBlock = BigEndianBitConverter.ToUInt32(sector, (int)(0x18 + i * 8 + 0)); chainEntry.BlockPairs[i].GoodBlock = BigEndianBitConverter.ToUInt32(sector, (int)(0x18 + i * 8 + 4)); DicConsole.DebugWriteLine("Amiga RDB plugin", "Bad block at {0} replaced with good block at {1}", chainEntry.BlockPairs[i].BadBlock, chainEntry.BlockPairs[i].GoodBlock); } badBlockChain.Add(chainEntry); nextBlock = chainEntry.NextPtr; } // Reading BadBlock list List partitionEntries = new List(); nextBlock = rdb.PartitionPtr; while(nextBlock != 0xFFFFFFFF) { DicConsole.DebugWriteLine("Amiga RDB plugin", "Going to block {0} in search of a PartitionEntry block", nextBlock + sectorOffset); sector = imagePlugin.ReadSector(nextBlock + sectorOffset); uint magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != PARTITION_BLOCK_MAGIC) break; DicConsole.DebugWriteLine("Amiga RDB plugin", "Found PartitionEntry block"); PartitionEntry partEntry = new PartitionEntry { Magic = BigEndianBitConverter.ToUInt32(sector, 0x00), Size = BigEndianBitConverter.ToUInt32(sector, 0x04), Checksum = BigEndianBitConverter.ToInt32(sector, 0x08), TargetId = BigEndianBitConverter.ToUInt32(sector, 0x0C), NextPtr = BigEndianBitConverter.ToUInt32(sector, 0x10), Flags = BigEndianBitConverter.ToUInt32(sector, 0x14), Reserved1 = BigEndianBitConverter.ToUInt32(sector, 0x18), Reserved2 = BigEndianBitConverter.ToUInt32(sector, 0x1C), DevFlags = BigEndianBitConverter.ToUInt32(sector, 0x20), DriveNameLen = sector[0x24], Reserved3 = BigEndianBitConverter.ToUInt32(sector, 0x44), Reserved4 = BigEndianBitConverter.ToUInt32(sector, 0x48), Reserved5 = BigEndianBitConverter.ToUInt32(sector, 0x4C), Reserved6 = BigEndianBitConverter.ToUInt32(sector, 0x50), Reserved7 = BigEndianBitConverter.ToUInt32(sector, 0x54), Reserved8 = BigEndianBitConverter.ToUInt32(sector, 0x58), Reserved9 = BigEndianBitConverter.ToUInt32(sector, 0x5C), Reserved10 = BigEndianBitConverter.ToUInt32(sector, 0x60), Reserved11 = BigEndianBitConverter.ToUInt32(sector, 0x64), Reserved12 = BigEndianBitConverter.ToUInt32(sector, 0x68), Reserved13 = BigEndianBitConverter.ToUInt32(sector, 0x6C), Reserved14 = BigEndianBitConverter.ToUInt32(sector, 0x70), Reserved15 = BigEndianBitConverter.ToUInt32(sector, 0x74), Reserved16 = BigEndianBitConverter.ToUInt32(sector, 0x78), Reserved17 = BigEndianBitConverter.ToUInt32(sector, 0x7C), DosEnvVec = new DosEnvironmentVector { Size = BigEndianBitConverter.ToUInt32(sector, 0x80), BlockSize = BigEndianBitConverter.ToUInt32(sector, 0x84), SecOrg = BigEndianBitConverter.ToUInt32(sector, 0x88), Surfaces = BigEndianBitConverter.ToUInt32(sector, 0x8C), Spb = BigEndianBitConverter.ToUInt32(sector, 0x90), Bpt = BigEndianBitConverter.ToUInt32(sector, 0x94), Reservedblocks = BigEndianBitConverter.ToUInt32(sector, 0x98), Prealloc = BigEndianBitConverter.ToUInt32(sector, 0x9C), Interleave = BigEndianBitConverter.ToUInt32(sector, 0xA0), LowCylinder = BigEndianBitConverter.ToUInt32(sector, 0xA4), HighCylinder = BigEndianBitConverter.ToUInt32(sector, 0xA8), NumBuffer = BigEndianBitConverter.ToUInt32(sector, 0xAC), BufMemType = BigEndianBitConverter.ToUInt32(sector, 0xB0), MaxTransfer = BigEndianBitConverter.ToUInt32(sector, 0xB4), Mask = BigEndianBitConverter.ToUInt32(sector, 0xB8), BootPriority = BigEndianBitConverter.ToUInt32(sector, 0xBC), DosType = BigEndianBitConverter.ToUInt32(sector, 0xC0), Baud = BigEndianBitConverter.ToUInt32(sector, 0xC4), Control = BigEndianBitConverter.ToUInt32(sector, 0xC8), BootBlocks = BigEndianBitConverter.ToUInt32(sector, 0xCC) } }; byte[] driveName = new byte[32]; Array.Copy(sector, 0x24, driveName, 0, 32); partEntry.DriveName = StringHandlers.PascalToString(driveName, Encoding.GetEncoding("iso-8859-1")); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.magic = 0x{0:X8}", partEntry.Magic); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.size = {0} longs, {1} bytes", partEntry.Size, partEntry.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.checksum = 0x{0:X8}", partEntry.Checksum); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.targetID = {0}", partEntry.TargetId); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.next_ptr = {0}", partEntry.NextPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.flags = 0x{0:X8}", partEntry.Flags); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved1 = 0x{0:X8}", partEntry.Reserved1); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved2 = 0x{0:X8}", partEntry.Reserved2); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.devFlags = 0x{0:X8}", partEntry.DevFlags); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.driveNameLen = {0}", partEntry.DriveNameLen); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.driveName = \"{0}\"", partEntry.DriveName); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved3 = 0x{0:X8}", partEntry.Reserved3); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved4 = 0x{0:X8}", partEntry.Reserved4); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved5 = 0x{0:X8}", partEntry.Reserved5); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved6 = 0x{0:X8}", partEntry.Reserved6); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved7 = 0x{0:X8}", partEntry.Reserved7); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved8 = 0x{0:X8}", partEntry.Reserved8); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved9 = 0x{0:X8}", partEntry.Reserved9); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved10 = 0x{0:X8}", partEntry.Reserved10); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved11 = 0x{0:X8}", partEntry.Reserved11); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved12 = 0x{0:X8}", partEntry.Reserved12); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved13 = 0x{0:X8}", partEntry.Reserved13); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved14 = 0x{0:X8}", partEntry.Reserved14); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved15 = 0x{0:X8}", partEntry.Reserved15); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved16 = 0x{0:X8}", partEntry.Reserved16); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.reserved17 = 0x{0:X8}", partEntry.Reserved17); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.size = {0} longs, {1} bytes", partEntry.DosEnvVec.Size, partEntry.DosEnvVec.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.block_size = {0} longs, {1} bytes", partEntry.DosEnvVec.BlockSize, partEntry.DosEnvVec.BlockSize * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.sec_org = 0x{0:X8}", partEntry.DosEnvVec.SecOrg); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.surfaces = {0}", partEntry.DosEnvVec.Surfaces); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.spb = {0}", partEntry.DosEnvVec.Spb); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.bpt = {0}", partEntry.DosEnvVec.Bpt); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.reservedblocks = {0}", partEntry.DosEnvVec.Reservedblocks); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.prealloc = {0}", partEntry.DosEnvVec.Prealloc); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.interleave = {0}", partEntry.DosEnvVec.Interleave); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.lowCylinder = {0}", partEntry.DosEnvVec.LowCylinder); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.highCylinder = {0}", partEntry.DosEnvVec.HighCylinder); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.numBuffer = {0}", partEntry.DosEnvVec.NumBuffer); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.bufMemType = {0}", partEntry.DosEnvVec.BufMemType); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.maxTransfer = {0}", partEntry.DosEnvVec.MaxTransfer); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.Mask = 0x{0:X8}", partEntry.DosEnvVec.Mask); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.bootPriority = {0}", partEntry.DosEnvVec.BootPriority); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.dosType = {0}", AmigaDosTypeToString(partEntry.DosEnvVec.DosType, true)); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.baud = {0}", partEntry.DosEnvVec.Baud); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.control = 0x{0:X8}", partEntry.DosEnvVec.Control); DicConsole.DebugWriteLine("Amiga RDB plugin", "partEntry.dosEnvVec.bootBlocks = {0}", partEntry.DosEnvVec.BootBlocks); partitionEntries.Add(partEntry); nextBlock = partEntry.NextPtr; } // Reading BadBlock list List fshdEntries = new List(); List segmentEntries = new List(); nextBlock = rdb.FsheaderPtr; while(nextBlock != 0xFFFFFFFF) { DicConsole.DebugWriteLine("Amiga RDB plugin", "Going to block {0} in search of a FileSystemHeader block", nextBlock); sector = imagePlugin.ReadSector(nextBlock); uint magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != FILESYSTEM_HEADER_MAGIC) break; DicConsole.DebugWriteLine("Amiga RDB plugin", "Found FileSystemHeader block"); FileSystemHeader fshd = new FileSystemHeader { Magic = BigEndianBitConverter.ToUInt32(sector, 0x00), Size = BigEndianBitConverter.ToUInt32(sector, 0x04), Checksum = BigEndianBitConverter.ToInt32(sector, 0x08), TargetId = BigEndianBitConverter.ToUInt32(sector, 0x0C), NextPtr = BigEndianBitConverter.ToUInt32(sector, 0x10), Flags = BigEndianBitConverter.ToUInt32(sector, 0x14), Reserved1 = BigEndianBitConverter.ToUInt32(sector, 0x18), Reserved2 = BigEndianBitConverter.ToUInt32(sector, 0x1C), DosType = BigEndianBitConverter.ToUInt32(sector, 0x20), Version = BigEndianBitConverter.ToUInt32(sector, 0x24), PatchFlags = BigEndianBitConverter.ToUInt32(sector, 0x28), Dnode = new DeviceNode { Type = BigEndianBitConverter.ToUInt32(sector, 0x2C), Task = BigEndianBitConverter.ToUInt32(sector, 0x30), Locked = BigEndianBitConverter.ToUInt32(sector, 0x34), Handler = BigEndianBitConverter.ToUInt32(sector, 0x38), StackSize = BigEndianBitConverter.ToUInt32(sector, 0x3C), Priority = BigEndianBitConverter.ToUInt32(sector, 0x40), Startup = BigEndianBitConverter.ToUInt32(sector, 0x44), SeglistPtr = BigEndianBitConverter.ToUInt32(sector, 0x48), GlobalVec = BigEndianBitConverter.ToUInt32(sector, 0x4C) } }; DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.magic = 0x{0:X8}", fshd.Magic); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.size = {0} longs, {1} bytes", fshd.Size, fshd.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.checksum = 0x{0:X8}", fshd.Checksum); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.targetID = {0}", fshd.TargetId); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.next_ptr = {0}", fshd.NextPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.flags = 0x{0:X8}", fshd.Flags); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.reserved1 = 0x{0:X8}", fshd.Reserved1); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.reserved2 = 0x{0:X8}", fshd.Reserved2); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dosType = {0}", AmigaDosTypeToString(fshd.DosType)); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.version = {0:D2}.{1:D2} (0x{2:X8})", (fshd.Version & 0xFFFF0000) >> 16, fshd.Version & 0xFFFF, fshd.Version); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.patchFlags = 0x{0:X8}", fshd.PatchFlags); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.type = {0}", fshd.Dnode.Type); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.task = {0}", fshd.Dnode.Task); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.locked = {0}", fshd.Dnode.Locked); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.handler = {0}", fshd.Dnode.Handler); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.stackSize = {0}", fshd.Dnode.StackSize); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.priority = {0}", fshd.Dnode.Priority); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.startup = {0}", fshd.Dnode.Startup); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.seglist_ptr = {0}", fshd.Dnode.SeglistPtr); DicConsole.DebugWriteLine("Amiga RDB plugin", "FSHD.dnode.global_vec = 0x{0:X8}", fshd.Dnode.GlobalVec); nextBlock = fshd.Dnode.SeglistPtr; bool thereAreLoadSegments = false; Sha1Context sha1Ctx = new Sha1Context(); sha1Ctx.Init(); while(nextBlock != 0xFFFFFFFF) { DicConsole.DebugWriteLine("Amiga RDB plugin", "Going to block {0} in search of a LoadSegment block", nextBlock); sector = imagePlugin.ReadSector(nextBlock); uint magicSeg = BigEndianBitConverter.ToUInt32(sector, 0); if(magicSeg != LOAD_SEG_MAGIC) break; DicConsole.DebugWriteLine("Amiga RDB plugin", "Found LoadSegment block"); thereAreLoadSegments = true; LoadSegment loadSeg = new LoadSegment { Magic = BigEndianBitConverter.ToUInt32(sector, 0x00), Size = BigEndianBitConverter.ToUInt32(sector, 0x04), Checksum = BigEndianBitConverter.ToInt32(sector, 0x08), TargetId = BigEndianBitConverter.ToUInt32(sector, 0x0C), NextPtr = BigEndianBitConverter.ToUInt32(sector, 0x10) }; loadSeg.LoadData = new byte[(loadSeg.Size - 5) * 4]; Array.Copy(sector, 0x14, loadSeg.LoadData, 0, (loadSeg.Size - 5) * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "loadSeg.magic = 0x{0:X8}", loadSeg.Magic); DicConsole.DebugWriteLine("Amiga RDB plugin", "loadSeg.size = {0} longs, {1} bytes", loadSeg.Size, loadSeg.Size * 4); DicConsole.DebugWriteLine("Amiga RDB plugin", "loadSeg.checksum = 0x{0:X8}", loadSeg.Checksum); DicConsole.DebugWriteLine("Amiga RDB plugin", "loadSeg.targetID = {0}", loadSeg.TargetId); DicConsole.DebugWriteLine("Amiga RDB plugin", "loadSeg.next_ptr = {0}", loadSeg.NextPtr); segmentEntries.Add(loadSeg); nextBlock = loadSeg.NextPtr; sha1Ctx.Update(loadSeg.LoadData); } if(thereAreLoadSegments) { string loadSegSha1 = sha1Ctx.End(); DicConsole.DebugWriteLine("Amiga RDB plugin", "LoadSegment data SHA1: {0}", loadSegSha1); } fshdEntries.Add(fshd); nextBlock = fshd.NextPtr; } ulong sequence = 0; foreach(Partition entry in partitionEntries.Select(rdbEntry => new Partition { Description = AmigaDosTypeToDescriptionString(rdbEntry.DosEnvVec.DosType), Name = rdbEntry.DriveName, Sequence = sequence, Length = (rdbEntry.DosEnvVec.HighCylinder + 1 - rdbEntry.DosEnvVec.LowCylinder) * rdbEntry.DosEnvVec.Surfaces * rdbEntry.DosEnvVec.Bpt, Start = rdbEntry.DosEnvVec.LowCylinder * rdbEntry.DosEnvVec.Surfaces * rdbEntry.DosEnvVec.Bpt + sectorOffset, Type = AmigaDosTypeToString(rdbEntry.DosEnvVec.DosType), Scheme = Name, Offset = (rdbEntry.DosEnvVec.LowCylinder * rdbEntry.DosEnvVec.Surfaces * rdbEntry.DosEnvVec.Bpt + sectorOffset) * rdb.BlockSize, Size = (rdbEntry.DosEnvVec.HighCylinder + 1 - rdbEntry.DosEnvVec.LowCylinder) * rdbEntry.DosEnvVec.Surfaces * rdbEntry.DosEnvVec.Bpt * rdb.BlockSize })) { partitions.Add(entry); sequence++; } return true; } static string AmigaDosTypeToDescriptionString(uint amigaDosType) { switch(amigaDosType) { case TYPEID_OFS: return "Amiga Original File System"; case TYPEID_FFS: return "Amiga Fast File System"; case TYPEID_OFS_INTL: return "Amiga Original File System with international characters"; case TYPEID_FFS_INTL: return "Amiga Fast File System with international characters"; case TYPEID_OFS_CACHE: return "Amiga Original File System with directory cache"; case TYPEID_FFS_CACHE: return "Amiga Fast File System with directory cache"; case TYPEID_OFS2: return "Amiga Original File System with long filenames"; case TYPEID_FFS2: return "Amiga Fast File System with long filenames"; case TYPEID_AMIX_SYSV: return "Amiga UNIX System V filesystem"; case TYPEID_AMIX_BOOT: return "Amiga UNIX boot filesystem"; case TYPEID_AMIX_FFS: return "Amiga UNIX BSD filesystem"; case TYPEID_AMIX_RESERVED: return "Amiga UNIX Reserved partition (swap)"; case TYPEID_PFS: case TYPEID_PFS2: case TYPEID_PFS_MUSER: case TYPEID_AFS: return "ProfessionalFileSystem"; case TYPEID_SFS: return "SmartFileSystem v1"; case TYPEID_SFS2: return "SmartFileSystem v2"; case TYPEID_JXFS: return "JXFS"; case TYPEID_CROSS_DOS: return "FAT, as set by CrossDOS"; case TYPEID_CROSS_MAC: return "HFS, as set by CrossMac"; case TYPEID_BFFS: return "4.2UFS, for BFFS"; case TYPEID_OFS_MUSER: return "Amiga Original File System with multi-user patches"; case TYPEID_FFS_MUSER: return "Amiga Fast File System with multi-user patches"; case TYPEID_OFS_INTL_MUSER: return "Amiga Original File System with international characters and multi-user patches"; case TYPEID_FFS_INTL_MUSER: return "Amiga Fast File System with international characters and multi-user patches"; case TYPEID_OFS_CACHE_MUSER: return "Amiga Original File System with directory cache and multi-user patches"; case TYPEID_FFS_CACHE_MUSER: return "Amiga Fast File System with directory cache and multi-user patches"; case TYPEID_OLD_BSD_UNUSED: return "BSD unused"; case TYPEID_OLD_BSD_SWAP: return "BSD swap"; case TYPEID_OLD_BSD42_FFS: return "BSD 4.2 FFS"; case TYPEID_OLD_BSD44_LFS: return "BSD 4.4 LFS"; case TYPEID_NETBSD_ROOT_UNUSED: return "NetBSD unused root partition"; case TYPEID_NETBSD_ROOT_42FFS: return "NetBSD 4.2 FFS root partition"; case TYPEID_NETBSD_ROOT_44LFS: return "NetBSD 4.4 LFS root partition"; case TYPEID_NETBSD_USER_UNUSED: return "NetBSD unused user partition"; case TYPEID_NETBSD_USER_42FFS: return "NetBSD 4.2 FFS user partition"; case TYPEID_NETBSD_USER_44LFS: return "NetBSD 4.4 LFS user partition"; case TYPEID_NETBSD_SWAP: return "NetBSD swap partition"; case TYPEID_LINUX: return "Linux filesystem partition"; case TYPEID_LINUX_SWAP: return "Linux swap partition"; case TYPEID_RAID_FRAME: case TYPEID_RAID_FRAME0: return "RaidFrame partition"; default: { if((amigaDosType & TYPEID_OFS) == TYPEID_OFS) return $"Unknown Amiga DOS filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_AMIX_SYSV) == TYPEID_AMIX_SYSV) return $"Unknown Amiga UNIX filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & 0x50465300) == 0x50465300 || (amigaDosType & 0x41465300) == 0x41465300) return $"Unknown ProfessionalFileSystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_SFS) == TYPEID_SFS) return $"Unknown SmartFileSystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_OFS_MUSER) == TYPEID_OFS_MUSER) return $"Unknown Amiga DOS multi-user filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_OLD_BSD_UNUSED) == TYPEID_OLD_BSD_UNUSED) return $"Unknown BSD filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_NETBSD_ROOT_UNUSED) == TYPEID_NETBSD_ROOT_UNUSED) return $"Unknown NetBSD root filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_NETBSD_USER_UNUSED) == TYPEID_NETBSD_USER_UNUSED) return $"Unknown NetBSD user filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_NETBSD_SWAP) == TYPEID_NETBSD_SWAP) return $"Unknown NetBSD swap filesystem type {AmigaDosTypeToString(amigaDosType)}"; if((amigaDosType & TYPEID_LINUX) == TYPEID_LINUX || (amigaDosType & TYPEID_LINUX_SWAP) == TYPEID_LINUX_SWAP) return $"Unknown Linux filesystem type {AmigaDosTypeToString(amigaDosType)}"; return $"Unknown partition type {AmigaDosTypeToString(amigaDosType)}"; } } } static string AmigaDosTypeToString(uint amigaDosType, bool quoted = true) { byte[] textPart = new byte[3]; textPart[0] = (byte)((amigaDosType & 0xFF000000) >> 24); textPart[1] = (byte)((amigaDosType & 0x00FF0000) >> 16); textPart[2] = (byte)((amigaDosType & 0x0000FF00) >> 8); string textPartString = Encoding.ASCII.GetString(textPart); return quoted ? $"\"{textPartString}\\{amigaDosType & 0xFF}\"" : $"{textPartString}\\{amigaDosType & 0xFF}"; } /// /// Amiga Rigid Disk Block, header for partitioning scheme /// Can be in any sector from 0 to 15, inclusive /// struct RigidDiskBlock { /// /// "RDSK" /// public uint Magic; /// /// Size in longs /// public uint Size; /// /// Checksum /// public int Checksum; /// /// SCSI target ID, 7 for non-SCSI /// public uint TargetId; /// /// Block size in bytes /// public uint BlockSize; /// /// Flags /// public uint Flags; /// /// Pointer to first BadBlockList, 0xFFFFFFFF means last block in device /// public uint BadblockPtr; /// /// Pointer to first PartitionEntry, 0xFFFFFFFF means last block in device /// public uint PartitionPtr; /// /// Pointer to first FileSystemHeader, 0xFFFFFFFF means last block in device /// public uint FsheaderPtr; /// /// Optional drive specific init code /// public uint Driveinitcode; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved1; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved2; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved3; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved4; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved5; /// /// Reserved, should be 0xFFFFFFFF /// public uint Reserved6; /// /// Cylinders in drive /// public uint Cylinders; /// /// Sectors per track /// public uint Spt; /// /// Heads in drive /// public uint Heads; /// /// Drive interleave /// public uint Interleave; /// /// Cylinder for parking heads /// public uint Parking; /// /// Reserved, should be zero /// public uint Reserved7; /// /// Reserved, should be zero /// public uint Reserved8; /// /// Reserved, should be zero /// public uint Reserved9; /// /// Starting cylinder for write precompensation /// public uint Writeprecomp; /// /// Starting cylinder for reduced write current /// public uint Reducedwrite; /// /// Drive step rate /// public uint Steprate; /// /// Reserved, should be zero /// public uint Reserved10; /// /// Reserved, should be zero /// public uint Reserved11; /// /// Reserved, should be zero /// public uint Reserved12; /// /// Reserved, should be zero /// public uint Reserved13; /// /// Reserved, should be zero /// public uint Reserved14; /// /// Low block of RDB reserved blocks /// public uint RdbBlockLow; /// /// High block of RDB reserved blocks /// public uint RdbBlockHigh; /// /// Low cylinder for partitionable area /// public uint LowCylinder; /// /// High cylinder for partitionable area /// public uint HighCylinder; /// /// Blocks per cylinder /// public uint CylBlocks; /// /// Seconds for head autoparking /// public uint AutoParkSeconds; /// /// Highest block used by RDB /// public uint HighRdskBlock; /// /// Reserved, should be zero /// public uint Reserved15; /// /// Disk vendor, 8 bytes /// public string DiskVendor; /// /// Disk product, 16 bytes /// public string DiskProduct; /// /// Disk revision, 4 bytes /// public string DiskRevision; /// /// Controller vendor, 8 bytes /// public string ControllerVendor; /// /// Controller product, 16 bytes /// public string ControllerProduct; /// /// Controller revision, 4 bytes /// public string ControllerRevision; /// /// Reserved, should be zero /// public uint Reserved16; /// /// Reserved, should be zero /// public uint Reserved17; /// /// Reserved, should be zero /// public uint Reserved18; /// /// Reserved, should be zero /// public uint Reserved19; /// /// Reserved, should be zero /// public uint Reserved20; /// /// Reserved, should be zero /// public uint Reserved21; /// /// Reserved, should be zero /// public uint Reserved22; /// /// Reserved, should be zero /// public uint Reserved23; /// /// Reserved, should be zero /// public uint Reserved24; /// /// Reserved, should be zero /// public uint Reserved25; } /// /// Pair for spare blocks /// struct BadBlockEntry { /// /// Bad block pointer /// public uint BadBlock; /// /// Replacement block pointer /// public uint GoodBlock; } /// /// List of bad blocks and spares /// struct BadBlockList { /// /// "BADB" /// public uint Magic; /// /// Size in longs /// public uint Size; /// /// Checksum /// public int Checksum; /// /// SCSI target ID, 7 for non-SCSI /// public uint TargetId; /// /// Pointer for next BadBlockList /// public uint NextPtr; /// /// Reserved /// public uint Reserved; /// /// Bad block entries, up to block filling, 8 bytes each /// public BadBlockEntry[] BlockPairs; } /// /// DOSEnvVec, used by AmigaDOS /// struct DosEnvironmentVector { /// /// Size in longs, should be 16, minimum 11 /// public uint Size; /// /// Block size in longs /// public uint BlockSize; /// /// Unknown, 0 /// public uint SecOrg; /// /// Heads in drive /// public uint Surfaces; /// /// Sectors per block /// public uint Spb; /// /// Blocks per track /// public uint Bpt; /// /// DOS reserved blocks at start of partition /// public uint Reservedblocks; /// /// DOS reserved blocks at end of partition /// public uint Prealloc; /// /// Interleave /// public uint Interleave; /// /// First cylinder of a partition, inclusive /// public uint LowCylinder; /// /// Last cylinder of a partition, inclusive /// public uint HighCylinder; /// /// Buffers, usually 30 /// public uint NumBuffer; /// /// Type of memory to allocate for buffers /// public uint BufMemType; /// /// Maximum transfer, usually 0x7FFFFFFF /// public uint MaxTransfer; /// /// Address mask to block out certain memory, usually 0xFFFFFFFE /// public uint Mask; /// /// Boot priority /// public uint BootPriority; /// /// Partition type, and filesystem driver identification for AmigaDOS /// public uint DosType; /// /// Default baud rate for SER and AUX handlers /// public uint Baud; /// /// Flow control values for SER and AUX handlers /// public uint Control; /// /// Since Kickstart 2, how many boot blocks are to be loaded /// public uint BootBlocks; } struct PartitionEntry { /// /// "PART" /// public uint Magic; /// /// Size in longs /// public uint Size; /// /// Checksum /// public int Checksum; /// /// SCSI target ID, 7 for non-SCSI /// public uint TargetId; /// /// Pointer to next PartitionEntry /// public uint NextPtr; /// /// Partition flags /// public uint Flags; /// /// Reserved /// public uint Reserved1; /// /// Reserved /// public uint Reserved2; /// /// Preferred flags for OpenDevice() /// public uint DevFlags; /// /// Length of drive name /// public uint DriveNameLen; /// /// Drive name, 31 bytes /// public string DriveName; /// /// Reserved /// public uint Reserved3; /// /// Reserved /// public uint Reserved4; /// /// Reserved /// public uint Reserved5; /// /// Reserved /// public uint Reserved6; /// /// Reserved /// public uint Reserved7; /// /// Reserved /// public uint Reserved8; /// /// Reserved /// public uint Reserved9; /// /// Reserved /// public uint Reserved10; /// /// Reserved /// public uint Reserved11; /// /// Reserved /// public uint Reserved12; /// /// Reserved /// public uint Reserved13; /// /// Reserved /// public uint Reserved14; /// /// Reserved /// public uint Reserved15; /// /// Reserved /// public uint Reserved16; /// /// Reserved /// public uint Reserved17; /// /// DOSEnvVec, more information about partition /// public DosEnvironmentVector DosEnvVec; } /// /// Device node, mostly useless, except for pointer to first LoadSegment block /// struct DeviceNode { /// /// Device node type, =0 /// public uint Type; /// /// DOS task field, =0 /// public uint Task; /// /// Unused, =0 /// public uint Locked; /// /// Filename handler to LoadSegment, =0 /// public uint Handler; /// /// Stack size when starting task, =0 /// public uint StackSize; /// /// Task priority, =0 /// public uint Priority; /// /// Startup message, =0 /// public uint Startup; /// /// Pointer to first LoadSegment block /// public uint SeglistPtr; /// /// BCPL globabl vector when starting task, =0xFFFFFFFF /// public uint GlobalVec; } /// /// File system header /// struct FileSystemHeader { /// /// "FSHD" /// public uint Magic; /// /// Size in longs, 64 /// public uint Size; /// /// Checksum /// public int Checksum; /// /// SCSI target ID, 7 for non-SCSI /// public uint TargetId; /// /// Pointer to next FileSystemHeader block /// public uint NextPtr; /// /// Flags, unknown /// public uint Flags; /// /// Reserved /// public uint Reserved1; /// /// Reserved /// public uint Reserved2; /// /// Partition type, and filesystem driver identification for AmigaDOS /// public uint DosType; /// /// Filesystem version /// Mask 0xFFFF0000, >>16, major version /// Mask 0x0000FFFF, minor version /// public uint Version; /// /// Bits for DeviceNode fields that should be substituted into a standard device node /// public uint PatchFlags; /// /// Device node /// public DeviceNode Dnode; } /// /// Filesystem code /// struct LoadSegment { /// /// "LSEG" /// public uint Magic; /// /// Size in longs /// public uint Size; /// /// Checksum /// public int Checksum; /// /// SCSI target ID, 7 for non-SCSI /// public uint TargetId; /// /// Pointer to next LoadSegment /// public uint NextPtr; /// /// Executable code, with relocation hunks, til end of sector /// public byte[] LoadData; } } }