Rewrote, solves infinite loop on extended partitions, supports

OnTrack and NEC extensions, supports optical discs, stops
	doing disklabels here (should be moved independently).
This commit is contained in:
2017-07-24 04:05:38 +01:00
parent 7bc23c4f55
commit 98d12076d5

View File

@@ -32,14 +32,14 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using DiscImageChef.Console;
// TODO: Support AAP, AST, SpeedStor and Ontrack extensions
// TODO: Support AAP extensions
namespace DiscImageChef.PartPlugins
{
public class MBR : PartPlugin
{
const ushort MBRSignature = 0xAA55;
public MBR()
{
Name = "Master Boot Record";
@@ -48,8 +48,6 @@ namespace DiscImageChef.PartPlugins
public override bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<CommonTypes.Partition> partitions)
{
byte cyl_sect1, cyl_sect2; // For decoding cylinder and sector
ushort signature;
ulong counter = 0;
partitions = new List<CommonTypes.Partition>();
@@ -57,317 +55,115 @@ namespace DiscImageChef.PartPlugins
if(imagePlugin.GetSectorSize() < 512)
return false;
uint sectorSize = imagePlugin.GetSectorSize();
// Divider of sector size in MBR between real sector size
ulong divider = 1;
if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc)
{
sectorSize = 512;
divider = 4;
}
byte[] sector = imagePlugin.ReadSector(0);
signature = BitConverter.ToUInt16(sector, 0x1FE);
GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned);
MasterBootRecord mbr = (MasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MasterBootRecord));
TimedMasterBootRecord mbr_time = (TimedMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TimedMasterBootRecord));
SerializedMasterBootRecord mbr_serial = (SerializedMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SerializedMasterBootRecord));
ModernMasterBootRecord mbr_modern = (ModernMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ModernMasterBootRecord));
NecMasterBootRecord mbr_nec = (NecMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NecMasterBootRecord));
DiskManagerMasterBootRecord mbr_ontrack = (DiskManagerMasterBootRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DiskManagerMasterBootRecord));
handle.Free();
if(signature != MBRSignature)
if(mbr.magic != MBR_Magic)
return false; // Not MBR
for(int i = 0; i < 4; i++)
MBRPartitionEntry[] entries;
if(mbr_ontrack.dm_magic == DM_Magic)
entries = mbr_ontrack.entries;
else if(mbr_nec.nec_magic == NEC_Magic)
entries = mbr_nec.entries;
else
entries = mbr.entries;
foreach(MBRPartitionEntry entry in entries)
{
MBRPartitionEntry entry = new MBRPartitionEntry();
entry.status = sector[0x1BE + 16 * i + 0x00];
entry.start_head = sector[0x1BE + 16 * i + 0x01];
cyl_sect1 = sector[0x1BE + 16 * i + 0x02];
cyl_sect2 = sector[0x1BE + 16 * i + 0x03];
entry.start_sector = (byte)(cyl_sect1 & 0x3F);
entry.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2);
entry.type = sector[0x1BE + 16 * i + 0x04];
entry.end_head = sector[0x1BE + 16 * i + 0x05];
cyl_sect1 = sector[0x1BE + 16 * i + 0x06];
cyl_sect2 = sector[0x1BE + 16 * i + 0x07];
entry.end_sector = (byte)(cyl_sect1 & 0x3F);
entry.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2);
entry.lba_start = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x08);
entry.lba_sectors = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x0C);
byte start_sector = (byte)(entry.start_sector & 0x3F);
ushort start_cylinder = (ushort)(((entry.start_sector & 0xC0) << 2) | entry.start_cylinder);
byte end_sector = (byte)(entry.end_sector & 0x3F);
ushort end_cylinder = (ushort)(((entry.end_sector & 0xC0) << 2) | entry.end_cylinder);
ulong lba_start = entry.lba_start;
ulong lba_sectors = entry.lba_sectors;
// Let's start the fun...
bool valid = true;
bool extended = false;
bool disklabel = false;
//bool disklabel = false;
if(entry.status != 0x00 && entry.status != 0x80)
return false; // Maybe a FAT filesystem
valid &= entry.type != 0x00;
if(entry.type == 0xEE || entry.type == 0xEF)
return false; // This is a GPT
if(entry.type == 0x05 || entry.type == 0x0F || entry.type == 0x85)
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
}
if(entry.type == 0x82 || entry.type == 0xBF || entry.type == 0xA5 || entry.type == 0xA6 || entry.type == 0xA9 ||
entry.type == 0xB7 || entry.type == 0x81 || entry.type == 0x63)
{
valid = false;
disklabel = true;
}
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)
{
entry.lba_start = CHStoLBA(entry.start_cylinder, entry.start_head, entry.start_sector);
entry.lba_sectors = CHStoLBA(entry.end_cylinder, entry.end_head, entry.end_sector) - entry.lba_start;
lba_start = CHStoLBA(start_cylinder, entry.start_head, start_sector);
lba_sectors = CHStoLBA(end_cylinder, entry.end_head, entry.end_sector) - lba_start;
}
if(entry.lba_start > imagePlugin.GetSectors() || entry.lba_start + entry.lba_sectors > imagePlugin.GetSectors())
// For optical media
lba_start /= divider;
lba_sectors /= divider;
if(lba_start > imagePlugin.GetSectors())
{
valid = false;
disklabel = false;
extended = false;
}
if(disklabel)
{
byte[] disklabel_sector = imagePlugin.ReadSector(entry.lba_start);
// Some buggy implementations do some rounding errors getting a few sectors beyond device size
if(lba_start + lba_sectors > imagePlugin.GetSectors())
lba_sectors = imagePlugin.GetSectors() - lba_start;
switch(entry.type)
{
case 0xA5:
case 0xA6:
case 0xA9:
case 0xB7: // BSD disklabels
{
BSD.DiskLabel bsdDisklabel = BSD.GetDiskLabel(disklabel_sector);
if(bsdDisklabel.d_magic == BSD.DISKMAGIC && bsdDisklabel.d_magic2 == BSD.DISKMAGIC)
{
// TODO: Handle disklabels bigger than 1 sector or search max no_parts
foreach(BSD.BSDPartition bsdPartition in bsdDisklabel.d_partitions)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
Length = bsdPartition.p_size,
Start = bsdPartition.p_offset,
Size = bsdPartition.p_size * bsdDisklabel.d_secsize,
Offset = bsdPartition.p_offset * bsdDisklabel.d_secsize,
Type = string.Format("BSD: {0}", bsdPartition.p_fstype),
Name = BSD.fsTypeToString(bsdPartition.p_fstype),
Sequence = counter,
Description = "Partition inside a BSD disklabel.",
Scheme = Name
};
if(bsdPartition.p_fstype != BSD.fsType.Unused)
{
partitions.Add(part);
counter++;
}
}
}
else
valid = true;
break;
}
case 0x63: // UNIX disklabel
{
uint magic;
byte[] unix_dl_sector = imagePlugin.ReadSector(entry.lba_start + 29); // UNIX disklabel starts on sector 29 of partition
magic = BitConverter.ToUInt32(unix_dl_sector, 4);
if(magic == UNIX.UNIXDiskLabel_MAGIC)
{
UNIX.UNIXDiskLabel dl = new UNIX.UNIXDiskLabel();
UNIX.UNIXVTOC vtoc = new UNIX.UNIXVTOC(); // old/new
bool isNewDL = false;
int vtocoffset = 0;
vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172);
if(vtoc.magic == UNIX.UNIXVTOC_MAGIC)
{
isNewDL = true;
vtocoffset = 72;
}
else
{
vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172);
if(vtoc.magic != UNIX.UNIXDiskLabel_MAGIC)
{
valid = true;
break;
}
}
dl.version = BitConverter.ToUInt32(unix_dl_sector, 8); // 8
byte[] dl_serial = new byte[12];
Array.Copy(unix_dl_sector, 12, dl_serial, 0, 12);
dl.serial = StringHandlers.CToString(dl_serial); // 12
dl.cyls = BitConverter.ToUInt32(unix_dl_sector, 24); // 24
dl.trks = BitConverter.ToUInt32(unix_dl_sector, 28); // 28
dl.secs = BitConverter.ToUInt32(unix_dl_sector, 32); // 32
dl.bps = BitConverter.ToUInt32(unix_dl_sector, 36); // 36
dl.start = BitConverter.ToUInt32(unix_dl_sector, 40); // 40
//dl.unknown1 = br.ReadBytes(48); // 44
dl.alt_tbl = BitConverter.ToUInt32(unix_dl_sector, 92); // 92
dl.alt_len = BitConverter.ToUInt32(unix_dl_sector, 96); // 96
if(isNewDL) // Old version VTOC starts here
{
dl.phys_cyl = BitConverter.ToUInt32(unix_dl_sector, 100); // 100
dl.phys_trk = BitConverter.ToUInt32(unix_dl_sector, 104); // 104
dl.phys_sec = BitConverter.ToUInt32(unix_dl_sector, 108); // 108
dl.phys_bytes = BitConverter.ToUInt32(unix_dl_sector, 112); // 112
dl.unknown2 = BitConverter.ToUInt32(unix_dl_sector, 116); // 116
dl.unknown3 = BitConverter.ToUInt32(unix_dl_sector, 120); // 120
//dl.pad = br.ReadBytes(48); // 124
}
if(vtoc.magic == UNIX.UNIXVTOC_MAGIC)
{
vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176
byte[] vtoc_name = new byte[8];
Array.Copy(unix_dl_sector, 108 + vtocoffset, vtoc_name, 0, 8);
vtoc.name = StringHandlers.CToString(vtoc_name); // 108/180
vtoc.slices = BitConverter.ToUInt16(unix_dl_sector, 116 + vtocoffset); // 116/188
vtoc.unknown = BitConverter.ToUInt16(unix_dl_sector, 118 + vtocoffset); // 118/190
//vtoc.reserved = br.ReadBytes(40); // 120/192
// TODO: What if number of slices overlaps sector (>23)?
for(int j = 0; j < vtoc.slices; j++)
{
UNIX.UNIXVTOCEntry vtoc_ent = new UNIX.UNIXVTOCEntry
{
tag = (UNIX.UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0), // 160/232 + j*12
flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2), // 162/234 + j*12
start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6), // 166/238 + j*12
length = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 10) // 170/242 + j*12
};
if((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX.UNIX_TAG.EMPTY && vtoc_ent.tag != UNIX.UNIX_TAG.WHOLE)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
// TODO: Check if device bps == disklabel bps
Start = vtoc_ent.start,
Length = vtoc_ent.length,
Offset = vtoc_ent.start * dl.bps,
Size = vtoc_ent.length * dl.bps,
Sequence = counter,
Type = string.Format("UNIX: {0}", UNIX.decodeUNIXTAG(vtoc_ent.tag, isNewDL)),
Scheme = Name
};
string info = "";
if((vtoc_ent.flags & 0x01) == 0x01)
info += " (do not mount)";
if((vtoc_ent.flags & 0x10) == 0x10)
info += " (do not mount)";
part.Description = "UNIX slice" + info + ".";
partitions.Add(part);
counter++;
}
}
}
}
else
valid = true;
break;
}
case 0x82:
case 0xBF: // Solaris disklabel
{
uint magic = BitConverter.ToUInt32(disklabel_sector, 12); // 12
uint version = BitConverter.ToUInt32(disklabel_sector, 16); // 16
if(magic == 0x600DDEEE && version == 1)
{
for(int j = 0; j < 16; j++)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
Start = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 4),
Length = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 8),
Description = "Solaris slice.",
Scheme = Name,
Sequence = counter
};
part.Offset = part.Start * imagePlugin.GetSectorSize(); // 68+4+j*12
part.Size = part.Length * imagePlugin.GetSectorSize(); // 68+8+j*12
if(part.Size > 0)
{
partitions.Add(part);
counter++;
}
}
}
else
valid = true;
break;
}
case 0x81: // Minix subpartitions
{
bool minix_subs = false;
byte type;
for(int j = 0; j < 4; j++)
{
type = disklabel_sector[0x1BE + j * 16 + 4];
if(type == 0x81)
{
minix_subs = true;
CommonTypes.Partition part = new CommonTypes.Partition
{
Description = "Minix subpartition",
Type = "Minix",
Start = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 8),
Length = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 12),
Sequence = counter,
Scheme = Name
};
part.Offset = part.Start * imagePlugin.GetSectorSize();
part.Size = part.Length * imagePlugin.GetSectorSize();
partitions.Add(part);
counter++;
}
}
valid |= !minix_subs;
break;
}
default:
valid = true;
break;
}
}
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}", start_cylinder);
DicConsole.DebugWriteLine("MBR plugin", "entry.start_head {0}", entry.start_head);
DicConsole.DebugWriteLine("MBR plugin", "entry.start_sector {0}", start_sector);
DicConsole.DebugWriteLine("MBR plugin", "entry.end_cylinder {0}", end_cylinder);
DicConsole.DebugWriteLine("MBR plugin", "entry.end_head {0}", entry.end_head);
DicConsole.DebugWriteLine("MBR plugin", "entry.end_sector {0}", end_sector);
if(valid)
{
CommonTypes.Partition part = new CommonTypes.Partition();
if(entry.lba_start > 0 && entry.lba_sectors > 0)
if(lba_start > 0 && lba_sectors > 0)
{
part.Start = entry.lba_start;
part.Length = entry.lba_sectors;
part.Offset = part.Start * imagePlugin.GetSectorSize();
part.Size = part.Length * imagePlugin.GetSectorSize();
part.Offset = part.Start * sectorSize;
part.Size = part.Length * sectorSize;
}
/* else if(entry.start_head < 255 && entry.end_head < 255 &&
entry.start_sector > 0 && entry.start_sector < 64 &&
entry.end_sector > 0 && entry.end_sector < 64 &&
entry.start_cylinder < 1024 && entry.end_cylinder < 1024)
{
} */ // As we don't know the maxium cyl, head or sect of the device we need LBA
else
valid = false;
if(valid)
{
part.Type = string.Format("0x{0:X2}", entry.type);
part.Name = decodeMBRType(entry.type);
part.Name = DecodeMBRType(entry.type);
part.Sequence = counter;
part.Description = entry.status == 0x80 ? "Partition is bootable." : "";
part.Scheme = Name;
@@ -378,319 +174,109 @@ namespace DiscImageChef.PartPlugins
}
}
DicConsole.DebugWriteLine("MBR plugin", "entry.extended = {0}", extended);
if(extended) // Let's extend the fun
{
bool ext_valid = true;
bool ext_disklabel = false;
bool processing_extended = true;
sector = imagePlugin.ReadSector(entry.lba_start);
ulong chain_start = lba_start;
while(processing_extended)
{
for(int l = 0; l < 2; l++)
sector = imagePlugin.ReadSector(lba_start);
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 next_start = 0;
foreach(MBRPartitionEntry ebr_entry in ebr.entries)
{
bool ext_extended = false;
bool ext_valid = true;
start_sector = (byte)(ebr_entry.start_sector & 0x3F);
start_cylinder = (ushort)(((ebr_entry.start_sector & 0xC0) << 2) | ebr_entry.start_cylinder);
end_sector = (byte)(ebr_entry.end_sector & 0x3F);
end_cylinder = (ushort)(((ebr_entry.end_sector & 0xC0) << 2) | ebr_entry.end_cylinder);
ulong ext_start = ebr_entry.lba_start;
ulong ext_sectors = ebr_entry.lba_sectors;
MBRPartitionEntry entry2 = new MBRPartitionEntry();
entry2.status = sector[0x1BE + 16 * i + 0x00];
entry2.start_head = sector[0x1BE + 16 * i + 0x01];
cyl_sect1 = sector[0x1BE + 16 * i + 0x02];
cyl_sect2 = sector[0x1BE + 16 * i + 0x03];
entry2.start_sector = (byte)(cyl_sect1 & 0x3F);
entry2.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2);
entry2.type = sector[0x1BE + 16 * i + 0x04];
entry2.end_head = sector[0x1BE + 16 * i + 0x05];
cyl_sect1 = sector[0x1BE + 16 * i + 0x06];
cyl_sect2 = sector[0x1BE + 16 * i + 0x07];
entry2.end_sector = (byte)(cyl_sect1 & 0x3F);
entry2.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2);
entry2.lba_start = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x08);
entry2.lba_sectors = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x0C);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.status {0}", ebr_entry.status);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.type {0}", ebr_entry.type);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.lba_start {0}", ebr_entry.lba_start);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.lba_sectors {0}", ebr_entry.lba_sectors);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_cylinder {0}", start_cylinder);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_head {0}", ebr_entry.start_head);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.start_sector {0}", start_sector);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_cylinder {0}", end_cylinder);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_head {0}", ebr_entry.end_head);
DicConsole.DebugWriteLine("MBR plugin", "ebr_entry.end_sector {0}", end_sector);
// Let's start the fun...
ext_valid &= ebr_entry.status == 0x00 || ebr_entry.status == 0x80;
ext_valid &= ebr_entry.type != 0x00;
ext_valid &= ebr_entry.lba_start != 0 || ebr_entry.lba_sectors != 0 || ebr_entry.start_cylinder != 0 || ebr_entry.start_head != 0 ||
ebr_entry.start_sector != 0 || ebr_entry.end_cylinder != 0 || ebr_entry.end_head != 0 || ebr_entry.end_sector != 0;
if(ebr_entry.lba_start == 0 && ebr_entry.lba_sectors == 0 && ext_valid)
{
ext_start = CHStoLBA(start_cylinder, ebr_entry.start_head, start_sector);
ext_sectors = CHStoLBA(end_cylinder, ebr_entry.end_head, ebr_entry.end_sector) - ext_start;
}
ext_valid &= entry2.status == 0x00 || entry2.status == 0x80;
valid &= entry2.type != 0x00;
if(entry2.type == 0x82 || entry2.type == 0xBF || entry2.type == 0xA5 || entry2.type == 0xA6 ||
entry2.type == 0xA9 || entry2.type == 0xB7 || entry2.type == 0x81 || entry2.type == 0x63)
// For optical media
lba_start /= divider;
lba_sectors /= divider;
if(ebr_entry.type == 0x05 || ebr_entry.type == 0x0F || ebr_entry.type == 0x15 || ebr_entry.type == 0x1F || ebr_entry.type == 0x85 ||
ebr_entry.type == 0x91 || ebr_entry.type == 0x9B || ebr_entry.type == 0xC5 || ebr_entry.type == 0xCF || ebr_entry.type == 0xD5)
{
ext_valid = false;
ext_disklabel = true;
next_start = chain_start + ext_start;
}
if(entry2.type == 0x05 || entry2.type == 0x0F || entry2.type == 0x85)
{
ext_valid = false;
ext_disklabel = false;
ext_extended = true; // Extended partition
}
else
processing_extended &= l != 1;
if(ext_disklabel)
{
byte[] disklabel_sector = imagePlugin.ReadSector(entry2.lba_start);
ext_start += lba_start;
ext_valid &= ext_start <= imagePlugin.GetSectors();
switch(entry2.type)
{
case 0xA5:
case 0xA6:
case 0xA9:
case 0xB7: // BSD disklabels
{
BSD.DiskLabel bsdDisklabel = BSD.GetDiskLabel(disklabel_sector);
if(bsdDisklabel.d_magic == BSD.DISKMAGIC && bsdDisklabel.d_magic2 == BSD.DISKMAGIC)
{
// TODO: Handle disklabels bigger than 1 sector or search max no_parts
foreach(BSD.BSDPartition bsdPartition in bsdDisklabel.d_partitions)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
Length = bsdPartition.p_size,
Start = bsdPartition.p_offset,
Size = bsdPartition.p_size * bsdDisklabel.d_secsize,
Offset = bsdPartition.p_offset * bsdDisklabel.d_secsize,
Type = string.Format("BSD: {0}", bsdPartition.p_fstype),
Name = BSD.fsTypeToString(bsdPartition.p_fstype),
Sequence = counter,
Description = "Partition inside a BSD disklabel.",
Scheme = Name
};
if(bsdPartition.p_fstype != BSD.fsType.Unused)
{
partitions.Add(part);
counter++;
}
}
}
else
ext_valid = true;
break;
}
case 0x63: // UNIX disklabel
{
uint magic;
byte[] unix_dl_sector = imagePlugin.ReadSector(entry.lba_start + 29); // UNIX disklabel starts on sector 29 of partition
magic = BitConverter.ToUInt32(unix_dl_sector, 4);
if(magic == UNIX.UNIXDiskLabel_MAGIC)
{
UNIX.UNIXDiskLabel dl = new UNIX.UNIXDiskLabel();
UNIX.UNIXVTOC vtoc = new UNIX.UNIXVTOC(); // old/new
bool isNewDL = false;
int vtocoffset = 0;
vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172);
if(vtoc.magic == UNIX.UNIXVTOC_MAGIC)
{
isNewDL = true;
vtocoffset = 72;
}
else
{
vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172);
if(vtoc.magic != UNIX.UNIXDiskLabel_MAGIC)
{
valid = true;
break;
}
}
dl.version = BitConverter.ToUInt32(unix_dl_sector, 8); // 8
byte[] dl_serial = new byte[12];
Array.Copy(unix_dl_sector, 12, dl_serial, 0, 12);
dl.serial = StringHandlers.CToString(dl_serial); // 12
dl.cyls = BitConverter.ToUInt32(unix_dl_sector, 24); // 24
dl.trks = BitConverter.ToUInt32(unix_dl_sector, 28); // 28
dl.secs = BitConverter.ToUInt32(unix_dl_sector, 32); // 32
dl.bps = BitConverter.ToUInt32(unix_dl_sector, 36); // 36
dl.start = BitConverter.ToUInt32(unix_dl_sector, 40); // 40
//dl.unknown1 = br.ReadBytes(48); // 44
dl.alt_tbl = BitConverter.ToUInt32(unix_dl_sector, 92); // 92
dl.alt_len = BitConverter.ToUInt32(unix_dl_sector, 96); // 96
if(isNewDL) // Old version VTOC starts here
{
dl.phys_cyl = BitConverter.ToUInt32(unix_dl_sector, 100); // 100
dl.phys_trk = BitConverter.ToUInt32(unix_dl_sector, 104); // 104
dl.phys_sec = BitConverter.ToUInt32(unix_dl_sector, 108); // 108
dl.phys_bytes = BitConverter.ToUInt32(unix_dl_sector, 112); // 112
dl.unknown2 = BitConverter.ToUInt32(unix_dl_sector, 116); // 116
dl.unknown3 = BitConverter.ToUInt32(unix_dl_sector, 120); // 120
//dl.pad = br.ReadBytes(48); // 124
}
if(vtoc.magic == UNIX.UNIXVTOC_MAGIC)
{
vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176
byte[] vtoc_name = new byte[8];
Array.Copy(unix_dl_sector, 108 + vtocoffset, vtoc_name, 0, 8);
vtoc.name = StringHandlers.CToString(vtoc_name); // 108/180
vtoc.slices = BitConverter.ToUInt16(unix_dl_sector, 116 + vtocoffset); // 116/188
vtoc.unknown = BitConverter.ToUInt16(unix_dl_sector, 118 + vtocoffset); // 118/190
//vtoc.reserved = br.ReadBytes(40); // 120/192
// TODO: What if number of slices overlaps sector (>23)?
for(int j = 0; j < vtoc.slices; j++)
{
UNIX.UNIXVTOCEntry vtoc_ent = new UNIX.UNIXVTOCEntry
{
tag = (UNIX.UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0), // 160/232 + j*12
flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2), // 162/234 + j*12
start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6), // 166/238 + j*12
length = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 10) // 170/242 + j*12
};
if((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX.UNIX_TAG.EMPTY && vtoc_ent.tag != UNIX.UNIX_TAG.WHOLE)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
// TODO: Check if device bps == disklabel bps
Start = vtoc_ent.start,
Length = vtoc_ent.length,
Offset = vtoc_ent.start * dl.bps,
Size = vtoc_ent.length * dl.bps,
Sequence = counter,
Type = string.Format("UNIX: {0}", UNIX.decodeUNIXTAG(vtoc_ent.tag, isNewDL)),
Scheme = Name
};
string info = "";
if((vtoc_ent.flags & 0x01) == 0x01)
info += " (do not mount)";
if((vtoc_ent.flags & 0x10) == 0x10)
info += " (do not mount)";
part.Description = "UNIX slice" + info + ".";
partitions.Add(part);
counter++;
}
}
}
}
else
ext_valid = true;
break;
}
case 0x82:
case 0xBF: // Solaris disklabel
{
uint magic = BitConverter.ToUInt32(disklabel_sector, 12); // 12
uint version = BitConverter.ToUInt32(disklabel_sector, 16); // 16
if(magic == 0x600DDEEE && version == 1)
{
for(int j = 0; j < 16; j++)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
Start = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 4),
Length = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 8),
Description = "Solaris slice.",
Scheme = Name,
Sequence = counter
};
part.Offset = part.Start * imagePlugin.GetSectorSize(); // 68+4+j*12
part.Size = part.Length * imagePlugin.GetSectorSize(); // 68+8+j*12
if(part.Size > 0)
{
partitions.Add(part);
counter++;
}
}
}
else
ext_valid = true;
break;
}
case 0x81: // Minix subpartitions
{
bool minix_subs = false;
byte type;
for(int j = 0; j < 4; j++)
{
type = disklabel_sector[0x1BE + j * 16 + 4];
if(type == 0x81)
{
CommonTypes.Partition part = new CommonTypes.Partition
{
Description = "Minix subpartition",
Type = "Minix",
Start = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 8),
Length = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 12),
Sequence = counter,
Scheme = Name
};
minix_subs = true;
part.Offset = part.Start * imagePlugin.GetSectorSize();
part.Size = part.Length * imagePlugin.GetSectorSize();
partitions.Add(part);
counter++;
}
}
ext_valid |= !minix_subs;
break;
}
default:
ext_valid = true;
break;
}
}
// Some buggy implementations do some rounding errors getting a few sectors beyond device size
if(ext_start + ext_sectors > imagePlugin.GetSectors())
ext_sectors = imagePlugin.GetSectors() - ext_start;
if(ext_valid)
{
CommonTypes.Partition part = new CommonTypes.Partition();
if(entry2.lba_start > 0 && entry2.lba_sectors > 0)
if(ext_start > 0 && ext_sectors > 0)
{
part.Start = entry2.lba_start;
part.Length = entry2.lba_sectors;
part.Offset = part.Start * imagePlugin.GetSectorSize();
part.Size = part.Length * imagePlugin.GetSectorSize();
part.Start = ext_start;
part.Length = ext_sectors;
part.Offset = part.Start * sectorSize;
part.Size = part.Length * sectorSize;
}
/* else if(entry2.start_head < 255 && entry2.end_head < 255 &&
entry2.start_sector > 0 && entry2.start_sector < 64 &&
entry2.end_sector > 0 && entry2.end_sector < 64 &&
entry2.start_cylinder < 1024 && entry2.end_cylinder < 1024)
{
} */ // As we don't know the maxium cyl, head or sect of the device we need LBA
else
ext_valid = false;
if(ext_valid)
{
part.Type = string.Format("0x{0:X2}", entry2.type);
part.Name = decodeMBRType(entry2.type);
part.Type = string.Format("0x{0:X2}", ebr_entry.type);
part.Name = DecodeMBRType(ebr_entry.type);
part.Sequence = counter;
part.Description = entry2.status == 0x80 ? "Partition is bootable." : "";
part.Description = ebr_entry.status == 0x80 ? "Partition is bootable." : "";
part.Scheme = Name;
counter++;
partitions.Add(part);
}
}
if(ext_extended)
{
break;
}
}
DicConsole.DebugWriteLine("MBR plugin", "next_start {0}", next_start);
processing_extended &= next_start != 0;
processing_extended &= (next_start <= imagePlugin.GetSectors());
lba_start = next_start;
}
}
}
@@ -706,7 +292,7 @@ namespace DiscImageChef.PartPlugins
#pragma warning restore IDE0004 // Remove Unnecessary Cast
}
static string decodeMBRType(byte type)
static string DecodeMBRType(byte type)
{
switch(type)
{
@@ -1023,29 +609,163 @@ namespace DiscImageChef.PartPlugins
}
}
public struct MBRPartitionEntry
public const ushort MBR_Magic = 0xAA55;
public const ushort NEC_Magic = 0xA55A;
public const ushort DM_Magic = 0x55AA;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MasterBootRecord
{
public byte status;
// Partition status, 0x80 or 0x00, else invalid
public byte start_head;
// Starting head [0,254]
public byte start_sector;
// Starting sector [1,63]
public ushort start_cylinder;
// Starting cylinder [0,1023]
public byte type;
// Partition type
public byte end_head;
// Ending head [0,254]
public byte end_sector;
// Ending sector [1,63]
public ushort end_cylinder;
// Ending cylinder [0,1023]
public uint lba_start;
// Starting absolute sector
public uint lba_sectors;
// Total sectors
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 446)]
public byte[] boot_code;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
// TODO: IBM Boot Manager
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ExtendedBootRecord
{
/// <summary>Boot code, almost always unused</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 446)]
public byte[] boot_code;
/// <summary>Partitions or pointers</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TimedMasterBootRecord
{
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 218)]
public byte[] boot_code;
/// <summary>Set to 0</summary>
public ushort zero;
/// <summary>Original physical drive</summary>
public byte drive;
/// <summary>Disk timestamp, seconds</summary>
public byte seconds;
/// <summary>Disk timestamp, minutes</summary>
public byte minutes;
/// <summary>Disk timestamp, hours</summary>
public byte hours;
/// <summary>Boot code, continuation</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 222)]
public byte[] boot_code2;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SerializedMasterBootRecord
{
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 440)]
public byte[] boot_code;
/// <summary>Disk serial number</summary>
public uint serial;
/// <summary>Set to 0</summary>
public ushort zero;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ModernMasterBootRecord
{
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 218)]
public byte[] boot_code;
/// <summary>Set to 0</summary>
public ushort zero;
/// <summary>Original physical drive</summary>
public byte drive;
/// <summary>Disk timestamp, seconds</summary>
public byte seconds;
/// <summary>Disk timestamp, minutes</summary>
public byte minutes;
/// <summary>Disk timestamp, hours</summary>
public byte hours;
/// <summary>Boot code, continuation</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 216)]
public byte[] boot_code2;
/// <summary>Disk serial number</summary>
public uint serial;
/// <summary>Set to 0</summary>
public ushort zero2;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct NecMasterBootRecord
{
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 380)]
public byte[] boot_code;
/// <summary><see cref="NEC_Magic"/></summary>
public ushort nec_magic;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DiskManagerMasterBootRecord
{
/// <summary>Boot code</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 252)]
public byte[] boot_code;
/// <summary><see cref="DM_Magic"/></summary>
public ushort dm_magic;
/// <summary>Partitions</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public MBRPartitionEntry[] entries;
/// <summary><see cref="MBR_Magic"/></summary>
public ushort magic;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MBRPartitionEntry
{
/// <summary>Partition status, 0x80 or 0x00, else invalid</summary>
public byte status;
/// <summary>Starting head [0,254]</summary>
public byte start_head;
/// <summary>Starting sector [1,63]</summary>
public byte start_sector;
/// <summary>Starting cylinder [0,1023]</summary>
public byte start_cylinder;
/// <summary>Partition type</summary>
public byte type;
/// <summary>Ending head [0,254]</summary>
public byte end_head;
/// <summary>Ending sector [1,63]</summary>
public byte end_sector;
/// <summary>Ending cylinder [0,1023]</summary>
public byte end_cylinder;
/// <summary>Starting absolute sector</summary>
public uint lba_start;
/// <summary>Total sectors</summary>
public uint lba_sectors;
}
}
}