From 8cd63de25ed5a528d629e766c6584e1ca2e0e071 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 26 Jul 2017 23:46:42 +0100 Subject: [PATCH] Added support for big-endian disklabels, more positions, and corrected calculations. Also, added more debug output. --- DiscImageChef.Partitions/BSD.cs | 152 ++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 37 deletions(-) diff --git a/DiscImageChef.Partitions/BSD.cs b/DiscImageChef.Partitions/BSD.cs index f8a31c718..8fcb1360f 100644 --- a/DiscImageChef.Partitions/BSD.cs +++ b/DiscImageChef.Partitions/BSD.cs @@ -35,12 +35,21 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using DiscImageChef.CommonTypes; using DiscImageChef.ImagePlugins; +using DiscImageChef.Console; +using System.Linq; namespace DiscImageChef.PartPlugins { public class BSD : PartPlugin { public const uint DISKMAGIC = 0x82564557; + public const uint DISKCIGAM = 0x57455682; + /// Known sector locations for BSD disklabel + readonly ulong[] labelLocations = { 0, 1, 2, 9 }; + /// Known byte offsets for BSD disklabel + readonly uint[] labelOffsets = { 0, 9, 64, 128, 516 }; + /// Maximum size of a disklabel with 22 partitions + const uint maxLabelSize = 500; public BSD() { @@ -51,50 +60,106 @@ namespace DiscImageChef.PartPlugins public override bool GetInformation(ImagePlugin imagePlugin, out List partitions, ulong sectorOffset) { partitions = new List(); + uint run = (maxLabelSize + labelOffsets.Last()) / imagePlugin.GetSectorSize(); + if((maxLabelSize + labelOffsets.Last()) % imagePlugin.GetSectorSize() > 0) + run++; - byte[] sector = imagePlugin.ReadSector(sectorOffset); - if(sector.Length < 512) - return false; + byte[] sector; + DiskLabel dl = new DiskLabel(); bool found = false; - DiskLabel dl = GetDiskLabel(sector); - - if(dl.d_magic == DISKMAGIC || dl.d_magic2 == DISKMAGIC) - found = true; - else + foreach(ulong location in labelLocations) { - sector = imagePlugin.ReadSector(1 + sectorOffset); + if(location + run + sectorOffset >= imagePlugin.GetSectors()) + return false; - dl = GetDiskLabel(sector); + byte[] tmp = imagePlugin.ReadSectors(location + sectorOffset, run); + foreach(uint offset in labelOffsets) + { + sector = new byte[maxLabelSize]; + Array.Copy(tmp, offset, sector, 0, maxLabelSize); + dl = GetDiskLabel(sector); + DicConsole.DebugWriteLine("BSD plugin", "dl.magic on sector {0} at offset {1} = 0x{2:X8} (expected 0x{3:X8})", location + sectorOffset, offset, dl.d_magic, DISKMAGIC); + if((dl.d_magic == DISKMAGIC && dl.d_magic2 == DISKMAGIC) || + (dl.d_magic == DISKCIGAM && dl.d_magic2 == DISKCIGAM)) + { + found = true; + break; + } + } - found |= (dl.d_magic == DISKMAGIC || dl.d_magic2 == DISKMAGIC); + if(found) + break; } - if(found) - { - ulong counter = 0; + if(!found) + return false; - foreach(BSDPartition entry in dl.d_partitions) + if(dl.d_magic == DISKCIGAM && dl.d_magic2 == DISKCIGAM) + + DicConsole.DebugWriteLine("BSD plugin", "dl.d_type = {0}", dl.d_type); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_subtype = {0}", dl.d_subtype); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_typename = {0}", StringHandlers.CToString(dl.d_typename)); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_packname = {0}", StringHandlers.CToString(dl.d_packname)); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_secsize = {0}", dl.d_secsize); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_nsectors = {0}", dl.d_nsectors); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_ntracks = {0}", dl.d_ntracks); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_ncylinders = {0}", dl.d_ncylinders); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_secpercyl = {0}", dl.d_secpercyl); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_secperunit = {0}", dl.d_secperunit); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_sparespertrack = {0}", dl.d_sparespertrack); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_sparespercyl = {0}", dl.d_sparespercyl); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_acylinders = {0}", dl.d_acylinders); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_rpm = {0}", dl.d_rpm); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_interleave = {0}", dl.d_interleave); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_trackskew = {0}", dl.d_trackskew); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_cylskeew = {0}", dl.d_cylskeew); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_headswitch = {0}", dl.d_headswitch); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_trkseek = {0}", dl.d_trkseek); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_flags = {0}", dl.d_flags); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_drivedata[0] = {0}", dl.d_drivedata[0]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_drivedata[1] = {0}", dl.d_drivedata[1]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_drivedata[2] = {0}", dl.d_drivedata[2]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_drivedata[3] = {0}", dl.d_drivedata[3]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_drivedata[4] = {0}", dl.d_drivedata[4]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_spare[0] = {0}", dl.d_spare[0]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_spare[1] = {0}", dl.d_spare[1]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_spare[2] = {0}", dl.d_spare[2]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_spare[3] = {0}", dl.d_spare[3]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_spare[4] = {0}", dl.d_spare[4]); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_magic2 = 0x{0:X8}", dl.d_magic2); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_checksum = 0x{0:X8}", dl.d_checksum); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_npartitions = {0}", dl.d_npartitions); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_bbsize = {0}", dl.d_bbsize); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_sbsize = {0}", dl.d_sbsize); + + ulong counter = 0; + + for(int i = 0; i < dl.d_npartitions && i < 22; i++) + { + DicConsole.DebugWriteLine("BSD plugin", "dl.d_partitions[i].p_offset = {0}", dl.d_partitions[i].p_offset); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_partitions[i].p_size = {0}", dl.d_partitions[i].p_size); + DicConsole.DebugWriteLine("BSD plugin", "dl.d_partitions[i].p_fstype = {0} ({1})", dl.d_partitions[i].p_fstype, fsTypeToString(dl.d_partitions[i].p_fstype)); + Partition part = new Partition { - Partition part = new Partition - { - Start = entry.p_offset, - Offset = (entry.p_offset * dl.d_secsize), - Size = entry.p_size, - Length = (entry.p_size * dl.d_secsize), - Type = fsTypeToString(entry.p_fstype), - Sequence = counter, - Scheme = Name - }; - if(entry.p_fstype != fsType.Unused) - { - partitions.Add(part); - counter++; - } + Start = ((dl.d_partitions[i].p_offset * dl.d_secsize) / imagePlugin.GetSectorSize()), + Offset = (dl.d_partitions[i].p_offset * dl.d_secsize), + Length = (dl.d_partitions[i].p_size * dl.d_secsize) / imagePlugin.GetSectorSize(), + Size = (dl.d_partitions[i].p_size * dl.d_secsize), + Type = fsTypeToString(dl.d_partitions[i].p_fstype), + Sequence = counter, + Scheme = Name + }; + if(dl.d_partitions[i].p_fstype != fsType.Unused) + { + DicConsole.DebugWriteLine("BSD plugin", "part.start = {0}", part.Start); + DicConsole.DebugWriteLine("BSD plugin", "Adding it..."); + partitions.Add(part); + counter++; } } - return found; + return partitions.Count > 0; } /// Drive type @@ -310,7 +375,7 @@ namespace DiscImageChef.PartPlugins /// Maximum size of superblock in bytes public uint d_sbsize; /// Partitions - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] public BSDPartition[] d_partitions; } @@ -387,6 +452,8 @@ namespace DiscImageChef.PartPlugins return "ZFS"; case fsType.NANDFS: return "FreeBSD nandfs"; + case fsType.MSDOS: + return "FAT"; case fsType.Other: return "Other or unknown"; default: @@ -396,11 +463,22 @@ namespace DiscImageChef.PartPlugins public static DiskLabel GetDiskLabel(byte[] disklabel) { - DiskLabel dl = new DiskLabel(); - IntPtr dlPtr = Marshal.AllocHGlobal(512); - Marshal.Copy(disklabel, 0, dlPtr, 512); - dl = (DiskLabel)Marshal.PtrToStructure(dlPtr, typeof(DiskLabel)); - Marshal.FreeHGlobal(dlPtr); + GCHandle handle = GCHandle.Alloc(disklabel, GCHandleType.Pinned); + DiskLabel dl = (DiskLabel)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DiskLabel)); + handle.Free(); + return dl; + } + + public static DiskLabel SwapDiskLabel(DiskLabel disklabel) + { + DiskLabel dl = BigEndianMarshal.SwapStructureMembersEndian(disklabel); + for(int i = 0; i < dl.d_drivedata.Length; i++) + dl.d_drivedata[i] = BigEndianMarshal.SwapStructureMembersEndian(dl.d_drivedata[i]); + for(int i = 0; i < dl.d_drivedata.Length; i++) + dl.d_spare[i] = BigEndianMarshal.SwapStructureMembersEndian(dl.d_spare[i]); + for(int i = 0; i < dl.d_drivedata.Length; i++) + dl.d_partitions[i] = BigEndianMarshal.SwapStructureMembersEndian(dl.d_partitions[i]); + return dl; } }