public bool GetInformation(IMediaImage imagePlugin, out List <Partition> partitions, ulong sectorOffset) { ulong counter = 0; partitions = new List <Partition>(); if (imagePlugin.Info.SectorSize < 512) { return(false); } uint sectorSize = imagePlugin.Info.SectorSize; // Divider of sector size in MBR between real sector size ulong divider = 1; if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { sectorSize = 512; divider = 4; } byte[] sector = imagePlugin.ReadSector(sectorOffset); GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned); MasterBootRecord mbr = (MasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MasterBootRecord)); TimedMasterBootRecord mbrTime = (TimedMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TimedMasterBootRecord)); SerializedMasterBootRecord mbrSerial = (SerializedMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SerializedMasterBootRecord)); ModernMasterBootRecord mbrModern = (ModernMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ModernMasterBootRecord)); NecMasterBootRecord mbrNec = (NecMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NecMasterBootRecord)); DiskManagerMasterBootRecord mbrOntrack = (DiskManagerMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DiskManagerMasterBootRecord)); handle.Free(); DicConsole.DebugWriteLine("MBR plugin", "xmlmedia = {0}", imagePlugin.Info.XmlMediaType); DicConsole.DebugWriteLine("MBR plugin", "mbr.magic = {0:X4}", mbr.magic); if (mbr.magic != MBR_MAGIC) { return(false); // Not MBR } byte[] hdrBytes = imagePlugin.ReadSector(1 + sectorOffset); ulong signature = BitConverter.ToUInt64(hdrBytes, 0); DicConsole.DebugWriteLine("MBR Plugin", "gpt.signature = 0x{0:X16}", signature); if (signature == GPT_MAGIC) { return(false); } if (signature != GPT_MAGIC && imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { hdrBytes = imagePlugin.ReadSector(sectorOffset); signature = BitConverter.ToUInt64(hdrBytes, 512); DicConsole.DebugWriteLine("MBR Plugin", "gpt.signature @ 0x200 = 0x{0:X16}", signature); if (signature == GPT_MAGIC) { return(false); } } MbrPartitionEntry[] entries; if (mbrOntrack.dm_magic == DM_MAGIC) { entries = mbrOntrack.entries; } else if (mbrNec.nec_magic == NEC_MAGIC) { entries = mbrNec.entries; } else { entries = mbr.entries; } foreach (MbrPartitionEntry entry in entries) { byte startSector = (byte)(entry.start_sector & 0x3F); ushort startCylinder = (ushort)(((entry.start_sector & 0xC0) << 2) | entry.start_cylinder); byte endSector = (byte)(entry.end_sector & 0x3F); ushort endCylinder = (ushort)(((entry.end_sector & 0xC0) << 2) | entry.end_cylinder); ulong lbaStart = entry.lba_start; ulong lbaSectors = entry.lba_sectors; // Let's start the fun... bool valid = true; bool extended = false; bool minix = false; if (entry.status != 0x00 && entry.status != 0x80) { return(false); // Maybe a FAT filesystem } valid &= entry.type != 0x00; if (entry.type == 0x05 || entry.type == 0x0F || entry.type == 0x15 || entry.type == 0x1F || entry.type == 0x85 || entry.type == 0x91 || entry.type == 0x9B || entry.type == 0xC5 || entry.type == 0xCF || entry.type == 0xD5) { valid = false; extended = true; // Extended partition } minix |= entry.type == 0x81 || entry.type == 0x80; // MINIX partition valid &= entry.lba_start != 0 || entry.lba_sectors != 0 || entry.start_cylinder != 0 || entry.start_head != 0 || entry.start_sector != 0 || entry.end_cylinder != 0 || entry.end_head != 0 || entry.end_sector != 0; if (entry.lba_start == 0 && entry.lba_sectors == 0 && valid) { lbaStart = CHS.ToLBA(startCylinder, entry.start_head, startSector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack); lbaSectors = CHS.ToLBA(endCylinder, entry.end_head, entry.end_sector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack) - lbaStart; } // For optical media lbaStart /= divider; lbaSectors /= divider; if (minix && lbaStart == sectorOffset) { minix = false; } if (lbaStart > imagePlugin.Info.Sectors) { valid = false; extended = false; } // Some buggy implementations do some rounding errors getting a few sectors beyond device size if (lbaStart + lbaSectors > imagePlugin.Info.Sectors) { lbaSectors = imagePlugin.Info.Sectors - lbaStart; } DicConsole.DebugWriteLine("MBR plugin", "entry.status {0}", entry.status); DicConsole.DebugWriteLine("MBR plugin", "entry.type {0}", entry.type); DicConsole.DebugWriteLine("MBR plugin", "entry.lba_start {0}", entry.lba_start); DicConsole.DebugWriteLine("MBR plugin", "entry.lba_sectors {0}", entry.lba_sectors); DicConsole.DebugWriteLine("MBR plugin", "entry.start_cylinder {0}", startCylinder); DicConsole.DebugWriteLine("MBR plugin", "entry.start_head {0}", entry.start_head); DicConsole.DebugWriteLine("MBR plugin", "entry.start_sector {0}", startSector); DicConsole.DebugWriteLine("MBR plugin", "entry.end_cylinder {0}", endCylinder); DicConsole.DebugWriteLine("MBR plugin", "entry.end_head {0}", entry.end_head); DicConsole.DebugWriteLine("MBR plugin", "entry.end_sector {0}", endSector); DicConsole.DebugWriteLine("MBR plugin", "entry.minix = {0}", minix); DicConsole.DebugWriteLine("MBR plugin", "lba_start {0}", lbaStart); DicConsole.DebugWriteLine("MBR plugin", "lba_sectors {0}", lbaSectors); if (valid && minix) // Let's mix the fun { if (GetMinix(imagePlugin, lbaStart, divider, sectorOffset, sectorSize, out List <Partition> mnxParts)) { partitions.AddRange(mnxParts); } else { minix = false; } } if (valid && !minix) { Partition part = new Partition(); if ((lbaStart > 0 || imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) && lbaSectors > 0) { part.Start = lbaStart + sectorOffset; part.Length = lbaSectors; part.Offset = part.Start * sectorSize; part.Size = part.Length * sectorSize; } else { valid = false; } if (valid) { part.Type = $"0x{entry.type:X2}"; part.Name = DecodeMbrType(entry.type); part.Sequence = counter; part.Description = entry.status == 0x80 ? "Partition is bootable." : ""; part.Scheme = Name; counter++; partitions.Add(part); } } DicConsole.DebugWriteLine("MBR plugin", "entry.extended = {0}", extended); if (!extended) { continue; } bool processingExtended = true; ulong chainStart = lbaStart; while (processingExtended) { sector = imagePlugin.ReadSector(lbaStart); handle = GCHandle.Alloc(sector, GCHandleType.Pinned); ExtendedBootRecord ebr = (ExtendedBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedBootRecord)); handle.Free(); DicConsole.DebugWriteLine("MBR plugin", "ebr.magic == MBR_Magic = {0}", ebr.magic == MBR_MAGIC); if (ebr.magic != MBR_MAGIC) { break; } ulong nextStart = 0; foreach (MbrPartitionEntry ebrEntry in ebr.entries) { bool extValid = true; startSector = (byte)(ebrEntry.start_sector & 0x3F); startCylinder = (ushort)(((ebrEntry.start_sector & 0xC0) << 2) | ebrEntry.start_cylinder); endSector = (byte)(ebrEntry.end_sector & 0x3F); endCylinder = (ushort)(((ebrEntry.end_sector & 0xC0) << 2) | ebrEntry.end_cylinder); ulong extStart = ebrEntry.lba_start; ulong extSectors = ebrEntry.lba_sectors; bool extMinix = false; DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.status {0}", ebrEntry.status); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.type {0}", ebrEntry.type); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.lba_start {0}", ebrEntry.lba_start); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.lba_sectors {0}", ebrEntry.lba_sectors); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_cylinder {0}", startCylinder); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_head {0}", ebrEntry.start_head); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_sector {0}", startSector); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_cylinder {0}", endCylinder); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_head {0}", ebrEntry.end_head); DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_sector {0}", endSector); // Let's start the fun... extValid &= ebrEntry.status == 0x00 || ebrEntry.status == 0x80; extValid &= ebrEntry.type != 0x00; extValid &= ebrEntry.lba_start != 0 || ebrEntry.lba_sectors != 0 || ebrEntry.start_cylinder != 0 || ebrEntry.start_head != 0 || ebrEntry.start_sector != 0 || ebrEntry.end_cylinder != 0 || ebrEntry.end_head != 0 || ebrEntry.end_sector != 0; if (ebrEntry.lba_start == 0 && ebrEntry.lba_sectors == 0 && extValid) { extStart = CHS.ToLBA(startCylinder, ebrEntry.start_head, startSector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack); extSectors = CHS.ToLBA(endCylinder, ebrEntry.end_head, ebrEntry.end_sector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack) - extStart; } extMinix |= ebrEntry.type == 0x81 || ebrEntry.type == 0x80; // For optical media extStart /= divider; extSectors /= divider; DicConsole.DebugWriteLine("MBR plugin", "ext_start {0}", extStart); DicConsole.DebugWriteLine("MBR plugin", "ext_sectors {0}", extSectors); if (ebrEntry.type == 0x05 || ebrEntry.type == 0x0F || ebrEntry.type == 0x15 || ebrEntry.type == 0x1F || ebrEntry.type == 0x85 || ebrEntry.type == 0x91 || ebrEntry.type == 0x9B || ebrEntry.type == 0xC5 || ebrEntry.type == 0xCF || ebrEntry.type == 0xD5) { extValid = false; nextStart = chainStart + extStart; } extStart += lbaStart; extValid &= extStart <= imagePlugin.Info.Sectors; // Some buggy implementations do some rounding errors getting a few sectors beyond device size if (extStart + extSectors > imagePlugin.Info.Sectors) { extSectors = imagePlugin.Info.Sectors - extStart; } if (extValid && extMinix) // Let's mix the fun { if (GetMinix(imagePlugin, lbaStart, divider, sectorOffset, sectorSize, out List <Partition> mnxParts)) { partitions.AddRange(mnxParts); } else { extMinix = false; } } if (!extValid || extMinix) { continue; } Partition part = new Partition(); if (extStart > 0 && extSectors > 0) { part.Start = extStart + sectorOffset; part.Length = extSectors; part.Offset = part.Start * sectorSize; part.Size = part.Length * sectorSize; } else { extValid = false; } if (!extValid) { continue; } part.Type = $"0x{ebrEntry.type:X2}"; part.Name = DecodeMbrType(ebrEntry.type); part.Sequence = counter; part.Description = ebrEntry.status == 0x80 ? "Partition is bootable." : ""; part.Scheme = Name; counter++; partitions.Add(part); } DicConsole.DebugWriteLine("MBR plugin", "next_start {0}", nextStart); processingExtended &= nextStart != 0; processingExtended &= nextStart <= imagePlugin.Info.Sectors; lbaStart = nextStart; } } // An empty MBR may exist, NeXT creates one and then hardcodes its disklabel return(partitions.Count != 0); }
static bool GetMinix(IMediaImage imagePlugin, ulong start, ulong divider, ulong sectorOffset, uint sectorSize, out List <Partition> partitions) { partitions = new List <Partition>(); byte[] sector = imagePlugin.ReadSector(start); GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned); ExtendedBootRecord mnx = (ExtendedBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedBootRecord)); handle.Free(); DicConsole.DebugWriteLine("MBR plugin", "mnx.magic == MBR_Magic = {0}", mnx.magic == MBR_MAGIC); if (mnx.magic != MBR_MAGIC) { return(false); } bool anyMnx = false; foreach (MbrPartitionEntry mnxEntry in mnx.entries) { bool mnxValid = true; byte startSector = (byte)(mnxEntry.start_sector & 0x3F); ushort startCylinder = (ushort)(((mnxEntry.start_sector & 0xC0) << 2) | mnxEntry.start_cylinder); byte endSector = (byte)(mnxEntry.end_sector & 0x3F); ushort endCylinder = (ushort)(((mnxEntry.end_sector & 0xC0) << 2) | mnxEntry.end_cylinder); ulong mnxStart = mnxEntry.lba_start; ulong mnxSectors = mnxEntry.lba_sectors; DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.status {0}", mnxEntry.status); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.type {0}", mnxEntry.type); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.lba_start {0}", mnxEntry.lba_start); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.lba_sectors {0}", mnxEntry.lba_sectors); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.start_cylinder {0}", startCylinder); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.start_head {0}", mnxEntry.start_head); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.start_sector {0}", startSector); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.end_cylinder {0}", endCylinder); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.end_head {0}", mnxEntry.end_head); DicConsole.DebugWriteLine("MBR plugin", "mnx_entry.end_sector {0}", endSector); mnxValid &= mnxEntry.status == 0x00 || mnxEntry.status == 0x80; mnxValid &= mnxEntry.type == 0x81 || mnxEntry.type == 0x80; mnxValid &= mnxEntry.lba_start != 0 || mnxEntry.lba_sectors != 0 || mnxEntry.start_cylinder != 0 || mnxEntry.start_head != 0 || mnxEntry.start_sector != 0 || mnxEntry.end_cylinder != 0 || mnxEntry.end_head != 0 || mnxEntry.end_sector != 0; if (mnxEntry.lba_start == 0 && mnxEntry.lba_sectors == 0 && mnxValid) { mnxStart = CHS.ToLBA(startCylinder, mnxEntry.start_head, startSector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack); mnxSectors = CHS.ToLBA(endCylinder, mnxEntry.end_head, mnxEntry.end_sector, imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack) - mnxStart; } // For optical media mnxStart /= divider; mnxSectors /= divider; DicConsole.DebugWriteLine("MBR plugin", "mnx_start {0}", mnxStart); DicConsole.DebugWriteLine("MBR plugin", "mnx_sectors {0}", mnxSectors); if (!mnxValid) { continue; } Partition part = new Partition(); if (mnxStart > 0 && mnxSectors > 0) { part.Start = mnxStart + sectorOffset; part.Length = mnxSectors; part.Offset = part.Start * sectorSize; part.Size = part.Length * sectorSize; } else { mnxValid = false; } if (!mnxValid) { continue; } anyMnx = true; part.Type = "MINIX"; part.Name = "MINIX"; part.Description = mnxEntry.status == 0x80 ? "Partition is bootable." : ""; part.Scheme = "MINIX"; partitions.Add(part); } return(anyMnx); }
public bool GetInformation(IMediaImage imagePlugin, out List <Partition> partitions, ulong sectorOffset) { partitions = new List <Partition>(); if (sectorOffset != 0) { return(false); } byte[] bootSector = imagePlugin.ReadSector(0); byte[] sector = imagePlugin.ReadSector(1); if (bootSector[bootSector.Length - 2] != 0x55 || bootSector[bootSector.Length - 1] != 0xAA) { return(false); } // Prevent false positives with some FAT BPBs if (Encoding.ASCII.GetString(bootSector, 0x36, 3) == "FAT") { return(false); } PC98Table table = Marshal.ByteArrayToStructureLittleEndian <PC98Table>(sector); ulong counter = 0; foreach (PC98Partition entry in table.entries) { AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_mid = {0}", entry.dp_mid); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_sid = {0}", entry.dp_sid); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_dum1 = {0}", entry.dp_dum1); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_dum2 = {0}", entry.dp_dum2); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ipl_sct = {0}", entry.dp_ipl_sct); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ipl_head = {0}", entry.dp_ipl_head); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ipl_cyl = {0}", entry.dp_ipl_cyl); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ssect = {0}", entry.dp_ssect); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_shd = {0}", entry.dp_shd); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_scyl = {0}", entry.dp_scyl); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_esect = {0}", entry.dp_esect); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ehd = {0}", entry.dp_ehd); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_ecyl = {0}", entry.dp_ecyl); AaruConsole.DebugWriteLine("PC98 plugin", "entry.dp_name = \"{0}\"", StringHandlers.CToString(entry.dp_name, Encoding.GetEncoding(932))); if (entry.dp_scyl == entry.dp_ecyl || entry.dp_ecyl <= 0 || entry.dp_scyl > imagePlugin.Info.Cylinders || entry.dp_ecyl > imagePlugin.Info.Cylinders || entry.dp_shd > imagePlugin.Info.Heads || entry.dp_ehd > imagePlugin.Info.Heads || entry.dp_ssect > imagePlugin.Info.SectorsPerTrack || entry.dp_esect > imagePlugin.Info.SectorsPerTrack) { continue; } var part = new Partition { Start = CHS.ToLBA(entry.dp_scyl, entry.dp_shd, (uint)(entry.dp_ssect + 1), imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack), Type = DecodePC98Sid(entry.dp_sid), Name = StringHandlers.CToString(entry.dp_name, Encoding.GetEncoding(932)).Trim(), Sequence = counter, Scheme = Name }; part.Offset = part.Start * imagePlugin.Info.SectorSize; part.Length = CHS.ToLBA(entry.dp_ecyl, entry.dp_ehd, (uint)(entry.dp_esect + 1), imagePlugin.Info.Heads, imagePlugin.Info.SectorsPerTrack) - part.Start; part.Size = part.Length * imagePlugin.Info.SectorSize; AaruConsole.DebugWriteLine("PC98 plugin", "part.Start = {0}", part.Start); AaruConsole.DebugWriteLine("PC98 plugin", "part.Type = {0}", part.Type); AaruConsole.DebugWriteLine("PC98 plugin", "part.Name = {0}", part.Name); AaruConsole.DebugWriteLine("PC98 plugin", "part.Sequence = {0}", part.Sequence); AaruConsole.DebugWriteLine("PC98 plugin", "part.Offset = {0}", part.Offset); AaruConsole.DebugWriteLine("PC98 plugin", "part.Length = {0}", part.Length); AaruConsole.DebugWriteLine("PC98 plugin", "part.Size = {0}", part.Size); if (((entry.dp_mid & 0x20) != 0x20 && (entry.dp_mid & 0x44) != 0x44) || part.Start >= imagePlugin.Info.Sectors || part.End > imagePlugin.Info.Sectors) { continue; } partitions.Add(part); counter++; } return(partitions.Count > 0); }