// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // 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-2025 Natalia Portillo // ****************************************************************************/ // ReSharper disable NotAccessedField.Local using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Aaru.Checksums; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; using Aaru.Logging; namespace Aaru.Partitions; /// /// Implements decoding of the Amiga Rigid Disk Block [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed class AmigaRigidDiskBlock : IPartition { /// 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" // ReSharper disable once InconsistentNaming const uint TYPEID_NETBSD_ROOT_42FFS = 0x4E425207; /// Type ID for NetBSD 4.4 LFS root partition, "NBR\9" // ReSharper disable once InconsistentNaming 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" // ReSharper disable once InconsistentNaming const uint TYPEID_NETBSD_USER_42FFS = 0x4E425507; /// Type ID for NetBSD 4.4 LFS user partition, "NBR\9" // ReSharper disable once InconsistentNaming 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; const string MODULE_NAME = "Amiga Rigid Disk Block (RDB) plugin"; #region IPartition Members /// public string Name => Localization.AmigaRigidDiskBlock_Name; /// public Guid Id => new("8D72ED97-1854-4170-9CE4-6E8446FD9863"); /// public string Author => Authors.NATALIA_PORTILLO; /// public bool GetInformation(IMediaImage imagePlugin, out List partitions, ulong sectorOffset) { partitions = []; ulong rdbBlock = 0; var foundRdb = false; ErrorNumber errno; while(rdbBlock < 16) { if(imagePlugin.Info.Sectors <= rdbBlock) return false; if(rdbBlock + sectorOffset >= imagePlugin.Info.Sectors) break; errno = imagePlugin.ReadSector(rdbBlock + sectorOffset, false, out byte[] tmpSector, out _); if(errno != ErrorNumber.NoError) { rdbBlock++; continue; } var magic = BigEndianBitConverter.ToUInt32(tmpSector, 0); AaruLogging.Debug(MODULE_NAME, Localization.Possible_magic_at_block_0_is_1_X8, rdbBlock, magic); if(magic == RIGID_DISK_BLOCK_MAGIC) { AaruLogging.Debug(MODULE_NAME, Localization.Found_RDB_magic_at_block_0, rdbBlock); foundRdb = true; break; } rdbBlock++; } if(!foundRdb) return false; rdbBlock += sectorOffset; var rdb = new RigidDiskBlock(); errno = imagePlugin.ReadSector(rdbBlock, false, out byte[] sector, out _); if(errno != ErrorNumber.NoError) return false; 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); var 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); AaruLogging.Debug(MODULE_NAME, "RDB.magic = 0x{0:X8}", rdb.Magic); AaruLogging.Debug(MODULE_NAME, "RDB.size = {0} longs, {1} bytes", rdb.Size, rdb.Size * 4); AaruLogging.Debug(MODULE_NAME, "RDB.checksum = 0x{0:X8}", rdb.Checksum); AaruLogging.Debug(MODULE_NAME, "RDB.targetID = {0}", rdb.TargetId); AaruLogging.Debug(MODULE_NAME, "RDB.block_size = {0}", rdb.BlockSize); AaruLogging.Debug(MODULE_NAME, "RDB.badblock_ptr = {0}", rdb.BadblockPtr); AaruLogging.Debug(MODULE_NAME, "RDB.partition_ptr = {0}", rdb.PartitionPtr); AaruLogging.Debug(MODULE_NAME, "RDB.fsheader_ptr = {0}", rdb.FsheaderPtr); AaruLogging.Debug(MODULE_NAME, "RDB.driveinitcode = {0}", rdb.Driveinitcode); AaruLogging.Debug(MODULE_NAME, "RDB.reserved1 = 0x{0:X8}", rdb.Reserved1); AaruLogging.Debug(MODULE_NAME, "RDB.reserved2 = 0x{0:X8}", rdb.Reserved2); AaruLogging.Debug(MODULE_NAME, "RDB.reserved3 = 0x{0:X8}", rdb.Reserved3); AaruLogging.Debug(MODULE_NAME, "RDB.reserved4 = 0x{0:X8}", rdb.Reserved4); AaruLogging.Debug(MODULE_NAME, "RDB.reserved5 = 0x{0:X8}", rdb.Reserved5); AaruLogging.Debug(MODULE_NAME, "RDB.reserved6 = 0x{0:X8}", rdb.Reserved6); AaruLogging.Debug(MODULE_NAME, "RDB.cylinders = {0}", rdb.Cylinders); AaruLogging.Debug(MODULE_NAME, "RDB.spt = {0}", rdb.Spt); AaruLogging.Debug(MODULE_NAME, "RDB.heads = {0}", rdb.Heads); AaruLogging.Debug(MODULE_NAME, "RDB.interleave = {0}", rdb.Interleave); AaruLogging.Debug(MODULE_NAME, "RDB.parking = {0}", rdb.Parking); AaruLogging.Debug(MODULE_NAME, "RDB.reserved7 = 0x{0:X8}", rdb.Reserved7); AaruLogging.Debug(MODULE_NAME, "RDB.reserved8 = 0x{0:X8}", rdb.Reserved8); AaruLogging.Debug(MODULE_NAME, "RDB.reserved9 = 0x{0:X8}", rdb.Reserved9); AaruLogging.Debug(MODULE_NAME, "RDB.writeprecomp = {0}", rdb.Writeprecomp); AaruLogging.Debug(MODULE_NAME, "RDB.reducedwrite = {0}", rdb.Reducedwrite); AaruLogging.Debug(MODULE_NAME, "RDB.steprate = {0}", rdb.Steprate); AaruLogging.Debug(MODULE_NAME, "RDB.reserved10 = 0x{0:X8}", rdb.Reserved10); AaruLogging.Debug(MODULE_NAME, "RDB.reserved11 = 0x{0:X8}", rdb.Reserved11); AaruLogging.Debug(MODULE_NAME, "RDB.reserved12 = 0x{0:X8}", rdb.Reserved12); AaruLogging.Debug(MODULE_NAME, "RDB.reserved13 = 0x{0:X8}", rdb.Reserved13); AaruLogging.Debug(MODULE_NAME, "RDB.reserved14 = 0x{0:X8}", rdb.Reserved14); AaruLogging.Debug(MODULE_NAME, "RDB.RDBBlockLow = {0}", rdb.RdbBlockLow); AaruLogging.Debug(MODULE_NAME, "RDB.RDBBlockHigh = {0}", rdb.RdbBlockHigh); AaruLogging.Debug(MODULE_NAME, "RDB.LowCylinder = {0}", rdb.LowCylinder); AaruLogging.Debug(MODULE_NAME, "RDB.HighCylinder = {0}", rdb.HighCylinder); AaruLogging.Debug(MODULE_NAME, "RDB.CylBlocks = {0}", rdb.CylBlocks); AaruLogging.Debug(MODULE_NAME, "RDB.AutoParkSeconds = {0}", rdb.AutoParkSeconds); AaruLogging.Debug(MODULE_NAME, "RDB.HighCylinder = {0}", rdb.HighCylinder); AaruLogging.Debug(MODULE_NAME, "RDB.reserved15 = 0x{0:X8}", rdb.Reserved15); AaruLogging.Debug(MODULE_NAME, "RDB.diskVendor = \"{0}\"", rdb.DiskVendor); AaruLogging.Debug(MODULE_NAME, "RDB.diskProduct = \"{0}\"", rdb.DiskProduct); AaruLogging.Debug(MODULE_NAME, "RDB.diskRevision = \"{0}\"", rdb.DiskRevision); AaruLogging.Debug(MODULE_NAME, "RDB.controllerVendor = \"{0}\"", rdb.ControllerVendor); AaruLogging.Debug(MODULE_NAME, "RDB.controllerProduct = \"{0}\"", rdb.ControllerProduct); AaruLogging.Debug(MODULE_NAME, "RDB.controllerRevision = \"{0}\"", rdb.ControllerRevision); AaruLogging.Debug(MODULE_NAME, "RDB.reserved16 = 0x{0:X8}", rdb.Reserved16); AaruLogging.Debug(MODULE_NAME, "RDB.reserved17 = 0x{0:X8}", rdb.Reserved17); AaruLogging.Debug(MODULE_NAME, "RDB.reserved18 = 0x{0:X8}", rdb.Reserved18); AaruLogging.Debug(MODULE_NAME, "RDB.reserved19 = 0x{0:X8}", rdb.Reserved19); AaruLogging.Debug(MODULE_NAME, "RDB.reserved20 = 0x{0:X8}", rdb.Reserved20); AaruLogging.Debug(MODULE_NAME, "RDB.reserved21 = 0x{0:X8}", rdb.Reserved21); AaruLogging.Debug(MODULE_NAME, "RDB.reserved22 = 0x{0:X8}", rdb.Reserved22); AaruLogging.Debug(MODULE_NAME, "RDB.reserved23 = 0x{0:X8}", rdb.Reserved23); AaruLogging.Debug(MODULE_NAME, "RDB.reserved24 = 0x{0:X8}", rdb.Reserved24); AaruLogging.Debug(MODULE_NAME, "RDB.reserved25 = 0x{0:X8}", rdb.Reserved25); // Reading BadBlock list List badBlockChain = []; ulong nextBlock = rdb.BadblockPtr; while(nextBlock != 0xFFFFFFFF) { AaruLogging.Debug(MODULE_NAME, Localization.Going_to_block_0_in_search_of_a_BadBlock_block, nextBlock); errno = imagePlugin.ReadSector(nextBlock, false, out sector, out _); if(errno != ErrorNumber.NoError) break; var magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != BAD_BLOCK_LIST_MAGIC) break; AaruLogging.Debug(MODULE_NAME, Localization.Found_BadBlock_block); var 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]; AaruLogging.Debug(MODULE_NAME, "chainEntry.magic = 0x{0:X8}", chainEntry.Magic); AaruLogging.Debug(MODULE_NAME, "chainEntry.size = {0} longs, {1} bytes", chainEntry.Size, chainEntry.Size * 4); AaruLogging.Debug(MODULE_NAME, "chainEntry.checksum = 0x{0:X8}", chainEntry.Checksum); AaruLogging.Debug(MODULE_NAME, "chainEntry.targetID = {0}", chainEntry.TargetId); AaruLogging.Debug(MODULE_NAME, "chainEntry.next_ptr = {0}", chainEntry.NextPtr); AaruLogging.Debug(MODULE_NAME, "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)); AaruLogging.Debug(MODULE_NAME, Localization.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 = []; nextBlock = rdb.PartitionPtr; while(nextBlock != 0xFFFFFFFF) { AaruLogging.Debug(MODULE_NAME, Localization.Going_to_block_0_in_search_of_a_PartitionEntry_block, nextBlock + sectorOffset); errno = imagePlugin.ReadSector(nextBlock + sectorOffset, false, out sector, out _); if(errno != ErrorNumber.NoError) break; var magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != PARTITION_BLOCK_MAGIC) break; AaruLogging.Debug(MODULE_NAME, Localization.Found_PartitionEntry_block); var 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) } }; var driveName = new byte[32]; Array.Copy(sector, 0x24, driveName, 0, 32); partEntry.DriveName = StringHandlers.PascalToString(driveName, Encoding.GetEncoding("iso-8859-1")); AaruLogging.Debug(MODULE_NAME, "partEntry.magic = 0x{0:X8}", partEntry.Magic); AaruLogging.Debug(MODULE_NAME, "partEntry.size = {0} longs, {1} bytes", partEntry.Size, partEntry.Size * 4); AaruLogging.Debug(MODULE_NAME, "partEntry.checksum = 0x{0:X8}", partEntry.Checksum); AaruLogging.Debug(MODULE_NAME, "partEntry.targetID = {0}", partEntry.TargetId); AaruLogging.Debug(MODULE_NAME, "partEntry.next_ptr = {0}", partEntry.NextPtr); AaruLogging.Debug(MODULE_NAME, "partEntry.flags = 0x{0:X8}", partEntry.Flags); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved1 = 0x{0:X8}", partEntry.Reserved1); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved2 = 0x{0:X8}", partEntry.Reserved2); AaruLogging.Debug(MODULE_NAME, "partEntry.devFlags = 0x{0:X8}", partEntry.DevFlags); AaruLogging.Debug(MODULE_NAME, "partEntry.driveNameLen = {0}", partEntry.DriveNameLen); AaruLogging.Debug(MODULE_NAME, "partEntry.driveName = \"{0}\"", partEntry.DriveName); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved3 = 0x{0:X8}", partEntry.Reserved3); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved4 = 0x{0:X8}", partEntry.Reserved4); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved5 = 0x{0:X8}", partEntry.Reserved5); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved6 = 0x{0:X8}", partEntry.Reserved6); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved7 = 0x{0:X8}", partEntry.Reserved7); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved8 = 0x{0:X8}", partEntry.Reserved8); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved9 = 0x{0:X8}", partEntry.Reserved9); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved10 = 0x{0:X8}", partEntry.Reserved10); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved11 = 0x{0:X8}", partEntry.Reserved11); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved12 = 0x{0:X8}", partEntry.Reserved12); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved13 = 0x{0:X8}", partEntry.Reserved13); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved14 = 0x{0:X8}", partEntry.Reserved14); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved15 = 0x{0:X8}", partEntry.Reserved15); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved16 = 0x{0:X8}", partEntry.Reserved16); AaruLogging.Debug(MODULE_NAME, "partEntry.reserved17 = 0x{0:X8}", partEntry.Reserved17); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.size = {0} longs, {1} bytes", partEntry.DosEnvVec.Size, partEntry.DosEnvVec.Size * 4); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.block_size = {0} longs, {1} bytes", partEntry.DosEnvVec.BlockSize, partEntry.DosEnvVec.BlockSize * 4); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.sec_org = 0x{0:X8}", partEntry.DosEnvVec.SecOrg); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.surfaces = {0}", partEntry.DosEnvVec.Surfaces); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.spb = {0}", partEntry.DosEnvVec.Spb); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.bpt = {0}", partEntry.DosEnvVec.Bpt); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.reservedblocks = {0}", partEntry.DosEnvVec.Reservedblocks); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.prealloc = {0}", partEntry.DosEnvVec.Prealloc); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.interleave = {0}", partEntry.DosEnvVec.Interleave); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.lowCylinder = {0}", partEntry.DosEnvVec.LowCylinder); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.highCylinder = {0}", partEntry.DosEnvVec.HighCylinder); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.numBuffer = {0}", partEntry.DosEnvVec.NumBuffer); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.bufMemType = {0}", partEntry.DosEnvVec.BufMemType); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.maxTransfer = {0}", partEntry.DosEnvVec.MaxTransfer); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.Mask = 0x{0:X8}", partEntry.DosEnvVec.Mask); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.bootPriority = {0}", partEntry.DosEnvVec.BootPriority); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.dosType = {0}", AmigaDosTypeToString(partEntry.DosEnvVec.DosType)); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.baud = {0}", partEntry.DosEnvVec.Baud); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.control = 0x{0:X8}", partEntry.DosEnvVec.Control); AaruLogging.Debug(MODULE_NAME, "partEntry.dosEnvVec.bootBlocks = {0}", partEntry.DosEnvVec.BootBlocks); partitionEntries.Add(partEntry); nextBlock = partEntry.NextPtr; } // Reading BadBlock list List fshdEntries = []; List segmentEntries = []; nextBlock = rdb.FsheaderPtr; while(nextBlock != 0xFFFFFFFF) { AaruLogging.Debug(MODULE_NAME, Localization.Going_to_block_0_in_search_of_a_FileSystemHeader_block, nextBlock); errno = imagePlugin.ReadSector(nextBlock, false, out sector, out _); if(errno != ErrorNumber.NoError) break; var magic = BigEndianBitConverter.ToUInt32(sector, 0); if(magic != FILESYSTEM_HEADER_MAGIC) break; AaruLogging.Debug(MODULE_NAME, Localization.Found_FileSystemHeader_block); var 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) } }; AaruLogging.Debug(MODULE_NAME, "FSHD.magic = 0x{0:X8}", fshd.Magic); AaruLogging.Debug(MODULE_NAME, "FSHD.size = {0} longs, {1} bytes", fshd.Size, fshd.Size * 4); AaruLogging.Debug(MODULE_NAME, "FSHD.checksum = 0x{0:X8}", fshd.Checksum); AaruLogging.Debug(MODULE_NAME, "FSHD.targetID = {0}", fshd.TargetId); AaruLogging.Debug(MODULE_NAME, "FSHD.next_ptr = {0}", fshd.NextPtr); AaruLogging.Debug(MODULE_NAME, "FSHD.flags = 0x{0:X8}", fshd.Flags); AaruLogging.Debug(MODULE_NAME, "FSHD.reserved1 = 0x{0:X8}", fshd.Reserved1); AaruLogging.Debug(MODULE_NAME, "FSHD.reserved2 = 0x{0:X8}", fshd.Reserved2); AaruLogging.Debug(MODULE_NAME, "FSHD.dosType = {0}", AmigaDosTypeToString(fshd.DosType)); AaruLogging.Debug(MODULE_NAME, "FSHD.version = {0:D2}.{1:D2} (0x{2:X8})", (fshd.Version & 0xFFFF0000) >> 16, fshd.Version & 0xFFFF, fshd.Version); AaruLogging.Debug(MODULE_NAME, "FSHD.patchFlags = 0x{0:X8}", fshd.PatchFlags); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.type = {0}", fshd.Dnode.Type); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.task = {0}", fshd.Dnode.Task); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.locked = {0}", fshd.Dnode.Locked); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.handler = {0}", fshd.Dnode.Handler); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.stackSize = {0}", fshd.Dnode.StackSize); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.priority = {0}", fshd.Dnode.Priority); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.startup = {0}", fshd.Dnode.Startup); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.seglist_ptr = {0}", fshd.Dnode.SeglistPtr); AaruLogging.Debug(MODULE_NAME, "FSHD.dnode.global_vec = 0x{0:X8}", fshd.Dnode.GlobalVec); nextBlock = fshd.Dnode.SeglistPtr; var thereAreLoadSegments = false; var sha1Ctx = new Sha1Context(); while(nextBlock != 0xFFFFFFFF) { AaruLogging.Debug(MODULE_NAME, Localization.Going_to_block_0_in_search_of_a_LoadSegment_block, nextBlock); errno = imagePlugin.ReadSector(nextBlock, false, out sector, out _); if(errno != ErrorNumber.NoError) break; var magicSeg = BigEndianBitConverter.ToUInt32(sector, 0); if(magicSeg != LOAD_SEG_MAGIC) break; AaruLogging.Debug(MODULE_NAME, Localization.Found_LoadSegment_block); thereAreLoadSegments = true; var 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); AaruLogging.Debug(MODULE_NAME, "loadSeg.magic = 0x{0:X8}", loadSeg.Magic); AaruLogging.Debug(MODULE_NAME, "loadSeg.size = {0} longs, {1} bytes", loadSeg.Size, loadSeg.Size * 4); AaruLogging.Debug(MODULE_NAME, "loadSeg.checksum = 0x{0:X8}", loadSeg.Checksum); AaruLogging.Debug(MODULE_NAME, "loadSeg.targetID = {0}", loadSeg.TargetId); AaruLogging.Debug(MODULE_NAME, "loadSeg.next_ptr = {0}", loadSeg.NextPtr); segmentEntries.Add(loadSeg); nextBlock = loadSeg.NextPtr; sha1Ctx.Update(loadSeg.LoadData); } if(thereAreLoadSegments) { string loadSegSha1 = sha1Ctx.End(); AaruLogging.Debug(MODULE_NAME, Localization.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; } #endregion static string AmigaDosTypeToDescriptionString(uint amigaDosType) { switch(amigaDosType) { case TYPEID_OFS: return Localization.Amiga_Original_File_System; case TYPEID_FFS: return Localization.Amiga_Fast_File_System; case TYPEID_OFS_INTL: return Localization.Amiga_Original_File_System_with_international_characters; case TYPEID_FFS_INTL: return Localization.Amiga_Fast_File_System_with_international_characters; case TYPEID_OFS_CACHE: return Localization.Amiga_Original_File_System_with_directory_cache; case TYPEID_FFS_CACHE: return Localization.Amiga_Fast_File_System_with_directory_cache; case TYPEID_OFS2: return Localization.Amiga_Original_File_System_with_long_filenames; case TYPEID_FFS2: return Localization.Amiga_Fast_File_System_with_long_filenames; case TYPEID_AMIX_SYSV: return Localization.Amiga_UNIX_System_V_filesystem; case TYPEID_AMIX_BOOT: return Localization.Amiga_UNIX_boot_filesystem; case TYPEID_AMIX_FFS: return Localization.Amiga_UNIX_BSD_filesystem; case TYPEID_AMIX_RESERVED: return Localization.Amiga_UNIX_Reserved_partition__swap_; case TYPEID_PFS: case TYPEID_PFS2: case TYPEID_PFS_MUSER: case TYPEID_AFS: return Localization.ProfessionalFileSystem; case TYPEID_SFS: return Localization.SmartFileSystem_v1; case TYPEID_SFS2: return Localization.SmartFileSystem_v2; case TYPEID_JXFS: return Localization.JXFS; case TYPEID_CROSS_DOS: return Localization.FAT_as_set_by_CrossDOS; case TYPEID_CROSS_MAC: return Localization.HFS_as_set_by_CrossMac; case TYPEID_BFFS: return Localization._4_2_UFS_for_BFFS; case TYPEID_OFS_MUSER: return Localization.Amiga_Original_File_System_with_multi_user_patches; case TYPEID_FFS_MUSER: return Localization.Amiga_Fast_File_System_with_multi_user_patches; case TYPEID_OFS_INTL_MUSER: return Localization.Amiga_Original_File_System_with_international_characters_and_multi_user_patches; case TYPEID_FFS_INTL_MUSER: return Localization.Amiga_Fast_File_System_with_international_characters_and_multi_user_patches; case TYPEID_OFS_CACHE_MUSER: return Localization.Amiga_Original_File_System_with_directory_cache_and_multi_user_patches; case TYPEID_FFS_CACHE_MUSER: return Localization.Amiga_Fast_File_System_with_directory_cache_and_multi_user_patches; case TYPEID_OLD_BSD_UNUSED: return Localization.BSD_unused; case TYPEID_OLD_BSD_SWAP: return Localization.BSD_swap; case TYPEID_OLD_BSD42_FFS: return Localization.BSD_4_2_FFS; case TYPEID_OLD_BSD44_LFS: return Localization.BSD_4_4_LFS; case TYPEID_NETBSD_ROOT_UNUSED: return Localization.NetBSD_unused_root_partition; case TYPEID_NETBSD_ROOT_42FFS: return Localization.NetBSD_4_2_FFS_root_partition; case TYPEID_NETBSD_ROOT_44LFS: return Localization.NetBSD_4_4_LFS_root_partition; case TYPEID_NETBSD_USER_UNUSED: return Localization.NetBSD_unused_user_partition; case TYPEID_NETBSD_USER_42FFS: return Localization.NetBSD_4_2_FFS_user_partition; case TYPEID_NETBSD_USER_44LFS: return Localization.NetBSD_4_4_LFS_user_partition; case TYPEID_NETBSD_SWAP: return Localization.NetBSD_swap_partition; case TYPEID_LINUX: return Localization.Linux_filesystem_partition; case TYPEID_LINUX_SWAP: return Localization.Linux_swap_partition; case TYPEID_RAID_FRAME: case TYPEID_RAID_FRAME0: return Localization.RaidFrame_partition; default: { if((amigaDosType & TYPEID_OFS) == TYPEID_OFS) { return string.Format(Localization.Unknown_Amiga_DOS_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_AMIX_SYSV) == TYPEID_AMIX_SYSV) { return string.Format(Localization.Unknown_Amiga_UNIX_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & 0x50465300) == 0x50465300 || (amigaDosType & 0x41465300) == 0x41465300) { return string.Format(Localization.Unknown_ProfessionalFileSystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_SFS) == TYPEID_SFS) { return string.Format(Localization.Unknown_SmartFileSystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_OFS_MUSER) == TYPEID_OFS_MUSER) { return string.Format(Localization.Unknown_Amiga_DOS_multi_user_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_OLD_BSD_UNUSED) == TYPEID_OLD_BSD_UNUSED) { return string.Format(Localization.Unknown_BSD_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_NETBSD_ROOT_UNUSED) == TYPEID_NETBSD_ROOT_UNUSED) { return string.Format(Localization.Unknown_NetBSD_root_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_NETBSD_USER_UNUSED) == TYPEID_NETBSD_USER_UNUSED) { return string.Format(Localization.Unknown_NetBSD_user_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_NETBSD_SWAP) == TYPEID_NETBSD_SWAP) { return string.Format(Localization.Unknown_NetBSD_swap_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } if((amigaDosType & TYPEID_LINUX) == TYPEID_LINUX || (amigaDosType & TYPEID_LINUX_SWAP) == TYPEID_LINUX_SWAP) { return string.Format(Localization.Unknown_Linux_filesystem_type_0, AmigaDosTypeToString(amigaDosType)); } return string.Format(Localization.Unknown_partition_type_0, AmigaDosTypeToString(amigaDosType)); } } } static string AmigaDosTypeToString(uint amigaDosType, bool quoted = true) { var 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}"; } #region Nested type: BadBlockEntry /// Pair for spare blocks struct BadBlockEntry { /// Bad block pointer public uint BadBlock; /// Replacement block pointer public uint GoodBlock; } #endregion #region Nested type: BadBlockList /// 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; } #endregion #region Nested type: DeviceNode /// 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; } #endregion #region Nested type: DosEnvironmentVector /// 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; } #endregion #region Nested type: FileSystemHeader /// 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; } #endregion #region Nested type: LoadSegment /// 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; } #endregion #region Nested type: PartitionEntry 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; } #endregion #region Nested type: RigidDiskBlock /// 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; } #endregion }