diff --git a/DiscImageChef.Helpers/BigEndianStructure.cs b/DiscImageChef.Helpers/BigEndianStructure.cs new file mode 100644 index 00000000..c15ca8da --- /dev/null +++ b/DiscImageChef.Helpers/BigEndianStructure.cs @@ -0,0 +1,118 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : EndianSwapStructure.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace DiscImageChef.Helpers +{ + public static class BigEndianStructure + { + // TODO: Check this works + /// + /// Marshals a big-endian byte array to a C# structure. Dunno if it works with nested structures. + /// + /// The big endian byte array. + /// Byte array. + /// C# structure type. + public static T ByteArrayToStructureBigEndian(byte[] bytes) where T : struct + { + GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); + handle.Free(); + Type t = stuff.GetType(); + FieldInfo[] fieldInfo = t.GetFields(); + foreach(FieldInfo fi in fieldInfo) + { + if(fi.FieldType == typeof(short)) + { + short i16 = (short)fi.GetValue(stuff); + byte[] b16 = BitConverter.GetBytes(i16); + byte[] b16r = b16.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToInt16(b16r, 0)); + } + else if(fi.FieldType == typeof(int)) + { + int i32 = (int)fi.GetValue(stuff); + byte[] b32 = BitConverter.GetBytes(i32); + byte[] b32r = b32.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToInt32(b32r, 0)); + } + else if(fi.FieldType == typeof(long)) + { + long i64 = (long)fi.GetValue(stuff); + byte[] b64 = BitConverter.GetBytes(i64); + byte[] b64r = b64.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToInt64(b64r, 0)); + } + else if(fi.FieldType == typeof(ushort)) + { + ushort i16 = (ushort)fi.GetValue(stuff); + byte[] b16 = BitConverter.GetBytes(i16); + byte[] b16r = b16.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToUInt16(b16r, 0)); + } + else if(fi.FieldType == typeof(uint)) + { + uint i32 = (uint)fi.GetValue(stuff); + byte[] b32 = BitConverter.GetBytes(i32); + byte[] b32r = b32.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToUInt32(b32r, 0)); + } + else if(fi.FieldType == typeof(ulong)) + { + ulong i64 = (ulong)fi.GetValue(stuff); + byte[] b64 = BitConverter.GetBytes(i64); + byte[] b64r = b64.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToUInt64(b64r, 0)); + } + else if(fi.FieldType == typeof(float)) + { + float iflt = (float)fi.GetValue(stuff); + byte[] bflt = BitConverter.GetBytes(iflt); + byte[] bfltr = bflt.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToSingle(bfltr, 0)); + } + else if(fi.FieldType == typeof(double)) + { + double idbl = (double)fi.GetValue(stuff); + byte[] bdbl = BitConverter.GetBytes(idbl); + byte[] bdblr = bdbl.Reverse().ToArray(); + fi.SetValueDirect(__makeref(stuff), BitConverter.ToDouble(bdblr, 0)); + } + } + return stuff; + } + } +} + diff --git a/DiscImageChef.Helpers/ChangeLog b/DiscImageChef.Helpers/ChangeLog index 3b9f5c68..486a931f 100644 --- a/DiscImageChef.Helpers/ChangeLog +++ b/DiscImageChef.Helpers/ChangeLog @@ -1,3 +1,10 @@ +2016-08-21 Natalia Portillo + + * BigEndianStructure.cs: + * DiscImageChef.Helpers.csproj: Added code that directly + marshals from a big-endian byte array. But untested with + nested structures. + 2016-08-09 Natalia Portillo * DiscImageChef.Helpers.csproj: Bumped version to 3.2.99.2. diff --git a/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj b/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj index bad2344d..f1d6aea1 100644 --- a/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj +++ b/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj @@ -42,6 +42,7 @@ + diff --git a/DiscImageChef.Partitions/Acorn.cs b/DiscImageChef.Partitions/Acorn.cs new file mode 100644 index 00000000..1fafae44 --- /dev/null +++ b/DiscImageChef.Partitions/Acorn.cs @@ -0,0 +1,224 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Acorn.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages Acorn FileCore partitions. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class Acorn : PartPlugin + { + const ulong ADFS_SB_POS = 0xC00; + const uint LINUX_MAGIC = 0xDEAFA1DE; + const uint SWAP_MAGIC = 0xDEAFAB1E; + const uint RISCIX_MAGIC = 0x4A657320; + const uint TYPE_LINUX = 9; + const uint TYPE_RISCIX_MFM = 1; + const uint TYPE_RISCIX_SCSI = 2; + const uint TYPE_MASK = 15; + + public Acorn() + { + Name = "Acorn FileCore partitions"; + PluginUUID = new Guid("A7C8FEBE-8D00-4933-B9F3-42184C8BA808"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + ulong sbSector; + + if(imagePlugin.GetSectorSize() > ADFS_SB_POS) + sbSector = 0; + else + sbSector = ADFS_SB_POS / imagePlugin.GetSectorSize(); + + byte[] sector = imagePlugin.ReadSector(sbSector); + + if(sector.Length < 512) + return false; + + AcornBootBlock bootBlock = new AcornBootBlock(); + IntPtr bbPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(sector, 0, bbPtr, 512); + bootBlock = (AcornBootBlock)Marshal.PtrToStructure(bbPtr, typeof(AcornBootBlock)); + Marshal.FreeHGlobal(bbPtr); + + int checksum = 0; + for(int i = 0; i < 0x1FF; i++) + checksum = ((checksum & 0xFF) + (checksum >> 8) + sector[i]); + + int heads = bootBlock.discRecords.heads + ((bootBlock.discRecords.lowsector >> 6) & 1); + int secCyl = bootBlock.discRecords.spt * heads; + int mapSector = bootBlock.startCylinder * secCyl; + + byte[] map = imagePlugin.ReadSector((ulong)mapSector); + + ulong counter = 0; + + if((bootBlock.flags & TYPE_MASK) == TYPE_LINUX) + { + LinuxTable table = new LinuxTable(); + IntPtr tablePtr = Marshal.AllocHGlobal(512); + Marshal.Copy(map, 0, tablePtr, 512); + table = (LinuxTable)Marshal.PtrToStructure(tablePtr, typeof(LinuxTable)); + Marshal.FreeHGlobal(tablePtr); + + foreach(LinuxEntry entry in table.entries) + { + Partition part = new Partition(); + part.PartitionStartSector = (ulong)(mapSector + entry.start); + part.PartitionStart = part.PartitionStartSector * (ulong)sector.Length; + part.PartitionLength = entry.size; + part.PartitionSectors = (ulong)(entry.size * sector.Length); + part.PartitionSequence = counter; + if(entry.magic == LINUX_MAGIC || entry.magic == SWAP_MAGIC) + { + partitions.Add(part); + counter++; + } + } + } + else if((bootBlock.flags & TYPE_MASK) == TYPE_RISCIX_MFM || + (bootBlock.flags & TYPE_MASK) == TYPE_RISCIX_SCSI) + { + RiscIxTable table = new RiscIxTable(); + IntPtr tablePtr = Marshal.AllocHGlobal(512); + Marshal.Copy(map, 0, tablePtr, 512); + table = (RiscIxTable)Marshal.PtrToStructure(tablePtr, typeof(RiscIxTable)); + Marshal.FreeHGlobal(tablePtr); + + if(table.magic == RISCIX_MAGIC) + { + foreach(RiscIxEntry entry in table.partitions) + { + Partition part = new Partition(); + part.PartitionStartSector = (ulong)(mapSector + entry.start); + part.PartitionStart = part.PartitionStartSector * (ulong)sector.Length; + part.PartitionLength = entry.length; + part.PartitionSectors = (ulong)(entry.length * sector.Length); + part.PartitionName = StringHandlers.CToString(entry.name, Encoding.GetEncoding("iso-8859-1")); + part.PartitionSequence = counter; + if(entry.length > 0) + { + partitions.Add(part); + counter++; + } + } + } + } + + return !(partitions.Count == 0); + } + + [StructLayout(LayoutKind.Sequential)] + struct DiscRecord + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)] + public byte[] spare; + public byte log2secsize; + public byte spt; + public byte heads; + public byte density; + public byte idlen; + public byte log2bpmb; + public byte skew; + public byte bootoption; + public byte lowsector; + public byte nzones; + public ushort zone_spare; + public uint root; + public uint disc_size; + public ushort disc_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] disc_name; + public uint disc_type; + public uint disc_size_high; + public byte flags; + public byte nzones_high; + public uint format_version; + public uint root_size; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct AcornBootBlock + { + public DiscRecord discRecords; + public byte flags; + public ushort startCylinder; + public byte checksum; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct LinuxTable + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 42)] + public LinuxEntry[] entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] padding; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct LinuxEntry + { + public uint magic; + public uint start; + public uint size; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RiscIxTable + { + public uint magic; + public uint date; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public RiscIxEntry[] partitions; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RiscIxEntry + { + public uint start; + public uint length; + public uint one; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] name; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/BSD.cs b/DiscImageChef.Partitions/BSD.cs new file mode 100644 index 00000000..1929ea97 --- /dev/null +++ b/DiscImageChef.Partitions/BSD.cs @@ -0,0 +1,404 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : BSD.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages BSD disklabels. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class BSD : PartPlugin + { + public const uint DISKMAGIC = 0x82564557; + + public BSD() + { + Name = "BSD disklabel"; + PluginUUID = new Guid("246A6D93-4F1A-1F8A-344D-50187A5513A9"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] sector = imagePlugin.ReadSector(0); + if(sector.Length < 512) + return false; + bool found = false; + + DiskLabel dl = GetDiskLabel(sector); + + if(dl.d_magic == DISKMAGIC || dl.d_magic2 == DISKMAGIC) + found = true; + else + { + sector = imagePlugin.ReadSector(1); + + dl = GetDiskLabel(sector); + + found |= (dl.d_magic == DISKMAGIC || dl.d_magic2 == DISKMAGIC); + } + + if(found) + { + ulong counter = 0; + + foreach(BSDPartition entry in dl.d_partitions) + { + Partition part = new Partition(); + part.PartitionStartSector = entry.p_offset; + part.PartitionStart = (entry.p_offset * dl.d_secsize); + part.PartitionLength = entry.p_size; + part.PartitionSectors = (entry.p_size * dl.d_secsize); + part.PartitionType = fsTypeToString(entry.p_fstype); + part.PartitionSequence = counter; + if(entry.p_fstype != fsType.Unused) + { + partitions.Add(part); + counter++; + } + } + } + + return found; + } + + /// Drive type + public enum dType : ushort + { + /// SMD, XSMD + SMD = 1, + /// MSCP + MSCP = 2, + /// Other DEC (rk, rl) + DEC = 3, + /// SCSI + SCSI = 4, + /// ESDI + ESDI = 5, + /// ST506 et al + ST506 = 6, + /// CS/80 on HP-IB + HPIB = 7, + /// HP Fiber-link + HPFL = 8, + /// Floppy + FLOPPY = 10, + /// Concatenated disk + CCD = 11, + /// uvnode pseudo-disk + VND = 12, + /// DiskOnChip + DOC2K = 13, + /// ATAPI + ATAPI = 13, + /// CMU RAIDframe + RAID = 14, + /// Logical disk + LD = 15, + /// IBM JFS 2 + JFS2 = 16, + /// Cryptographic pseudo-disk + CGD = 17, + /// Vinum volume + VINUM = 18, + /// Flash memory devices + FLASH = 19, + /// Device-mapper pseudo-disk devices + DM = 20, + /// Rump virtual disk + RUMPD = 21, + /// Memory disk + MD = 22 + } + + /// Filesystem type + public enum fsType : byte + { + /// Unused entry + Unused = 0, + /// Swap partition + Swap = 1, + /// UNIX 6th Edition + V6 = 2, + /// UNIX 7th Edition + V7 = 3, + /// UNIX System V + SystemV = 4, + /// UNIX 7th Edition with 1K blocks + V7_1K = 5, + /// UNIX 8th Edition with 4K blocks + V8 = 6, + /// 4.2BSD Fast File System + BSDFFS = 7, + /// MS-DOS filesystem + MSDOS = 8, + /// 4.4LFS + BSDLFS = 9, + /// In use, unknown or unsupported + Other = 10, + /// HPFS + HPFS = 11, + /// ISO9660 + ISO9660 = 12, + /// Boot partition + Boot = 13, + /// Amiga FFS + AFFS = 14, + /// Apple HFS + HFS = 15, + /// Acorn ADFS + FileCore = 16, + /// Digital Advanced File System + ADVfs = 16, + /// Digital LSM Public Region + LSMpublic = 17, + /// Linux ext2 + ext2 = 17, + /// Digital LSM Private Region + LSMprivate = 18, + /// NTFS + NTFS = 18, + /// Digital LSM Simple Disk + LSMsimple = 19, + /// RAIDframe component + RAID = 19, + /// Concatenated disk component + CCD = 20, + /// IBM JFS2 + JFS2 = 21, + /// Apple UFS + AppleUFS = 22, + /// Hammer filesystem + HAMMER = 22, + /// Hammer2 filesystem + HAMMER2 = 23, + /// UDF + UDF = 24, + /// System V Boot filesystem + SysVBoot = 25, + /// EFS + EFS = 26, + /// ZFS + ZFS = 27, + /// NiLFS + NILFS = 27, + /// Cryptographic disk + CGD = 28, + /// MINIX v3 + MINIX = 29, + /// FreeBSD nandfs + NANDFS = 30 + } + + /// + /// Drive flags + /// + [Flags] + public enum dFlags : uint + { + /// Removable media + Removable = 0x01, + /// Drive supports ECC + ECC = 0x02, + /// Drive supports bad sector forwarding + BadSectorForward = 0x04, + /// Disk emulator + RAMDisk = 0x08, + /// Can do back to back transfer + Chain = 0x10, + /// Dynamic geometry device + DynamicGeometry = 0x20 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct DiskLabel + { + /// + public uint d_magic; + /// + public dType d_type; + /// Disk subtype + public ushort d_subtype; + /// Type name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] d_typename; + /// Pack identifier + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] d_packname; + /// Bytes per sector + public uint d_secsize; + /// Sectors per track + public uint d_nsectors; + /// Tracks per cylinder + public uint d_ntracks; + /// Cylinders per unit + public uint d_ncylinders; + /// Sectors per cylinder + public uint d_secpercyl; + /// Sectors per unit + public uint d_secperunit; + /// Spare sectors per track + public ushort d_sparespertrack; + /// Spare sectors per cylinder + public ushort d_sparespercyl; + /// Alternate cylinders + public uint d_acylinders; + /// Rotational speed + public ushort d_rpm; + /// Hardware sector interleave + public ushort d_interleave; + /// Sector 0 skew per track + public ushort d_trackskew; + /// Sector 0 sker per cylinder + public ushort d_cylskeew; + /// Head switch time in microseconds + public uint d_headswitch; + /// Track to track seek in microseconds + public uint d_trkseek; + /// + public dFlags d_flags; + /// Drive-specific information + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public uint[] d_drivedata; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + /// + public uint[] d_spare; + /// again + public uint d_magic2; + /// XOR of data + public ushort d_checksum; + /// How many partitions + public ushort d_npartitions; + /// Size of boot area in bytes + public uint d_bbsize; + /// Maximum size of superblock in bytes + public uint d_sbsize; + /// Partitions + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] + public BSDPartition[] d_partitions; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BSDPartition + { + /// Sectors in partition + public uint p_size; + /// Starting sector + public uint p_offset; + /// Fragment size + public uint p_fsize; + /// Filesystem type, + public fsType p_fstype; + /// Fragment size + public byte p_frag; + /// Cylinder per group + public ushort p_cpg; + } + + public static string fsTypeToString(fsType typ) + { + switch(typ) + { + case fsType.Unused: + return "Unused entry"; + case fsType.Swap: + return "Swap partition"; + case fsType.V6: + return "UNIX 6th Edition"; + case fsType.V7: + return "UNIX 7th Edition"; + case fsType.SystemV: + return "UNIX System V"; + case fsType.V7_1K: + return "UNIX 7th Edition with 1K blocks"; + case fsType.V8: + return "UNIX 8th Edition with 4K blocks"; + case fsType.BSDFFS: + return "4.2BSD Fast File System"; + case fsType.BSDLFS: + return "4.4LFS"; + case fsType.HPFS: + return "HPFS"; + case fsType.ISO9660: + return "ISO9660"; + case fsType.Boot: + return "Boot"; + case fsType.AFFS: + return "Amiga FFS"; + case fsType.HFS: + return "Apple HFS"; + case fsType.ADVfs: + return "Digital Advanced File System"; + case fsType.LSMpublic: + return "Digital LSM Public Region"; + case fsType.LSMprivate: + return "Digital LSM Private Region"; + case fsType.LSMsimple: + return "Digital LSM Simple Disk"; + case fsType.CCD: + return "Concatenated disk"; + case fsType.JFS2: + return "IBM JFS2"; + case fsType.HAMMER: + return "Hammer"; + case fsType.HAMMER2: + return "Hammer2"; + case fsType.UDF: + return "UDF"; + case fsType.EFS: + return "EFS"; + case fsType.ZFS: + return "ZFS"; + case fsType.NANDFS: + return "FreeBSD nandfs"; + case fsType.Other: + return "Other or unknown"; + default: + return "Unknown"; + } + } + + 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); + return dl; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/ChangeLog b/DiscImageChef.Partitions/ChangeLog index 9762040f..79c45e6c 100644 --- a/DiscImageChef.Partitions/ChangeLog +++ b/DiscImageChef.Partitions/ChangeLog @@ -1,3 +1,53 @@ +2016-08-21 Natalia Portillo + + * Acorn.cs: Added support for Acorn FileCore partition, closes + #4. + + * BSD.cs: Moved BSD partitions from inside MBR code to + separate code, as they can (and do) appear on other + architectures as the only scheme. + + * DEC.cs: Added support for DEC disklabels, closes #11. + + * DragonFlyBSD.cs: Added support for DragonFly BSD 64-bit + disklabels. + + * PC98.cs: Added support for NEC PC-9800 partitions. + + * RioKarma.cs: Added support for Rio Karma partitions. + + * SGI.cs: Added support for SGI DVHs, closes #9. + + * UNIX.cs: Moved UNIX partitions from inside MBR code to + separate code, as they can (and do) appear on other + architectures as the only scheme. + + * DiscImageChef.Partitions.csproj: Added support for Acorn + FileCore partition, closes #4. + Added support for DEC disklabels, closes #11. + Added support for SGI DVHs, closes #9. + Moved BSD partitions from inside MBR code to separate code, as + they can (and do) appear on other architectures as the only + scheme. + Added support for DragonFly BSD 64-bit disklabels. + Added support for NEC PC-9800 partitions. + Added support for Rio Karma partitions. + Moved UNIX partitions from inside MBR code to separate code, + as they can (and do) appear on other architectures as the only + scheme. + + * GPT.cs: Added new partition type UUIDs. + + * MBR.cs: Moved BSD partitions from inside MBR code to + separate code, as they can (and do) appear on other + architectures as the only scheme. + Moved UNIX partitions from inside MBR code to separate code, + as they can (and do) appear on other architectures as the only + scheme. + + * Sun.cs: Added new partition types. + Prepare structures for marshaling. + 2016-08-09 Natalia Portillo * DiscImageChef.Partitions.csproj: Bumped version to 3.2.99.2. diff --git a/DiscImageChef.Partitions/DEC.cs b/DiscImageChef.Partitions/DEC.cs new file mode 100644 index 00000000..00ff31df --- /dev/null +++ b/DiscImageChef.Partitions/DEC.cs @@ -0,0 +1,107 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : DEC.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages DEC disklabels. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class DEC : PartPlugin + { + const int PT_MAGIC = 0x032957; + const int PT_VALID = 1; + + public DEC() + { + Name = "DEC disklabel"; + PluginUUID = new Guid("58CEC3B7-3B93-4D47-86EE-D6DADE9D444F"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] sector = imagePlugin.ReadSector(31); + if(sector.Length < 512) + return false; + + DECLabel table = new DECLabel(); + IntPtr tablePtr = Marshal.AllocHGlobal(512); + Marshal.Copy(sector, 0, tablePtr, 512); + table = (DECLabel)Marshal.PtrToStructure(tablePtr, typeof(DECLabel)); + Marshal.FreeHGlobal(tablePtr); + + if(table.pt_magic != PT_MAGIC || table.pt_valid != PT_VALID) + return false; + + ulong counter = 0; + + foreach(DECPartition entry in table.pt_part) + { + Partition part = new Partition(); + part.PartitionStartSector = entry.pi_blkoff; + part.PartitionStart = (ulong)(entry.pi_blkoff * sector.Length); + part.PartitionLength = (ulong)entry.pi_nblocks; + part.PartitionSectors = (ulong)(entry.pi_nblocks * sector.Length); + part.PartitionSequence = counter; + if(part.PartitionLength > 0) + { + partitions.Add(part); + counter++; + } + } + + return true; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DECLabel + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 440)] + public byte[] padding; + public int pt_magic; + public int pt_valid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public DECPartition[] pt_part; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DECPartition + { + public int pi_nblocks; + public uint pi_blkoff; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj b/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj index a9023284..f6fc78e7 100644 --- a/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj +++ b/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj @@ -42,6 +42,14 @@ + + + + + + + + diff --git a/DiscImageChef.Partitions/DragonFlyBSD.cs b/DiscImageChef.Partitions/DragonFlyBSD.cs new file mode 100644 index 00000000..7d8cde69 --- /dev/null +++ b/DiscImageChef.Partitions/DragonFlyBSD.cs @@ -0,0 +1,133 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : DragonFlyBSD.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages DragonFly BSD 64-bit disklabels. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class DragonFlyBSD : PartPlugin + { + const uint DISK_MAGIC64 = 0xC4464C59; + + public DragonFlyBSD() + { + Name = "DragonFly BSD 64-bit disklabel"; + PluginUUID = new Guid("D49E41A6-D952-4760-9D94-03DAE2450C5F"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + uint nSectors = 2048 / imagePlugin.GetSectorSize(); + + byte[] sectors = imagePlugin.ReadSectors(0, nSectors); + if(sectors.Length < 2048) + return false; + + Disklabel64 disklabel = new Disklabel64(); + IntPtr labelPtr = Marshal.AllocHGlobal(2048); + Marshal.Copy(sectors, 0, labelPtr, 2048); + disklabel = (Disklabel64)Marshal.PtrToStructure(labelPtr, typeof(Disklabel64)); + Marshal.FreeHGlobal(labelPtr); + + if(disklabel.d_magic != 0xC4464C59) + return false; + + ulong counter = 0; + + foreach(Partition64 entry in disklabel.d_partitions) + { + Partition part = new Partition(); + part.PartitionStartSector = entry.p_boffset; + part.PartitionStart = entry.p_boffset; + part.PartitionLength = entry.p_bsize; + part.PartitionSectors = entry.p_bsize; + if((BSD.fsType)entry.p_fstype == BSD.fsType.Other) + part.PartitionType = entry.p_type_uuid.ToString(); + else + part.PartitionType = BSD.fsTypeToString((BSD.fsType)entry.p_fstype); + part.PartitionName = entry.p_stor_uuid.ToString(); + part.PartitionSequence = counter; + if(entry.p_bsize > 0 && entry.p_boffset > 0) + { + partitions.Add(part); + counter++; + } + } + + return true; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Disklabel64 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] d_reserved0; + public uint d_magic; + public uint d_crc; + public uint d_align; + public uint d_npartitions; + public Guid d_stor_uuid; + public ulong d_total_size; + public ulong d_bbase; + public ulong d_pbase; + public ulong d_pstop; + public ulong d_abase; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] d_packname; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] d_reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public Partition64[] d_partitions; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Partition64 + { + public ulong p_boffset; + public ulong p_bsize; + public byte p_fstype; + public byte p_unused01; + public byte p_unused02; + public byte p_unused03; + public uint p_unused04; + public uint p_unused05; + public uint p_unused06; + public Guid p_type_uuid; + public Guid p_stor_uuid; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/GPT.cs b/DiscImageChef.Partitions/GPT.cs index e09b3556..b22bce60 100644 --- a/DiscImageChef.Partitions/GPT.cs +++ b/DiscImageChef.Partitions/GPT.cs @@ -215,10 +215,14 @@ namespace DiscImageChef.PartPlugins return "FreeBSD Swap"; case "516E7CB6-6ECF-11D6-8FF8-00022D09712B": return "FreeBSD UFS"; + case "516E7CB7-6ECF-11D6-8FF8-00022D09712B": + return "FreeBSD UFS2"; case "516E7CB8-6ECF-11D6-8FF8-00022D09712B": return "FreeBSD Vinum"; case "516E7CBA-6ECF-11D6-8FF8-00022D09712B": return "FreeBSD ZFS"; + case "74BA7DD9-A689-11E1-BD04-00E081286ACF": + return "FreeBSD nandfs"; case "48465300-0000-11AA-AA11-00306543ECAC": return "Apple HFS"; case "55465300-0000-11AA-AA11-00306543ECAC": @@ -323,6 +327,24 @@ namespace DiscImageChef.PartPlugins return "Acronis Secure Zone"; case "7C3457EF-0000-11AA-AA11-00306543ECAC": return "Apple File System"; + case "9D087404-1CA5-11DC-8817-01301BB8A9F5": + return "DragonflyBSD Label"; + case "9D58FDBD-1CA5-11DC-8817-01301BB8A9F5": + return "DragonflyBSD Swap"; + case "9D94CE7C-1CA5-11DC-8817-01301BB8A9F5": + return "DragonflyBSD UFS"; + case "9DD4478F-1CA5-11DC-8817-01301BB8A9F5": + return "DragonflyBSD Vinum"; + case "DBD5211B-1CA5-11DC-8817-01301BB8A9F5": + return "DragonflyBSD CCD"; + case "3D48CE54-1D16-11DC-8817-01301BB8A9F5": + return "DragonflyBSD Label"; + case "BD215AB2-1D16-11DC-8696-01301BB8A9F5": + return "DragonflyBSD Legacy"; + case "61DC63AC-6E38-11DC-8513-01301BB8A9F5": + return "DragonflyBSD Hammer"; + case "5CBB9AD1-862D-11DC-A94D-01301BB8A9F5": + return "DragonflyBSD Hammer2"; default: return ""; } diff --git a/DiscImageChef.Partitions/MBR.cs b/DiscImageChef.Partitions/MBR.cs index b07e0ed7..e2293810 100644 --- a/DiscImageChef.Partitions/MBR.cs +++ b/DiscImageChef.Partitions/MBR.cs @@ -137,31 +137,28 @@ namespace DiscImageChef.PartPlugins case 0xA9: case 0xB7: // BSD disklabels { - uint magic = BitConverter.ToUInt32(disklabel_sector, 0); + BSD.DiskLabel bsdDisklabel = BSD.GetDiskLabel(disklabel_sector); - if(magic == 0x82564557) + if(bsdDisklabel.d_magic == BSD.DISKMAGIC && bsdDisklabel.d_magic2 == BSD.DISKMAGIC) { - ushort no_parts = BitConverter.ToUInt16(disklabel_sector, 126); - // TODO: Handle disklabels bigger than 1 sector or search max no_parts - for(int j = 0; j < no_parts; j++) + foreach(BSD.BSDPartition bsdPartition in bsdDisklabel.d_partitions) { + CommonTypes.Partition part = new CommonTypes.Partition(); - byte bsd_type; - part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 4); - part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 0); - part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); - part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); - bsd_type = disklabel_sector[134 + j * 16 + 8]; + part.PartitionSectors = bsdPartition.p_size; + part.PartitionStartSector = bsdPartition.p_offset; + part.PartitionLength = bsdPartition.p_size * bsdDisklabel.d_secsize; + part.PartitionStart = bsdPartition.p_offset * bsdDisklabel.d_secsize; - part.PartitionType = string.Format("BSD: {0}", bsd_type); - part.PartitionName = decodeBSDType(bsd_type); + part.PartitionType = string.Format("BSD: {0}", bsdPartition.p_fstype); + part.PartitionName = BSD.fsTypeToString(bsdPartition.p_fstype); part.PartitionSequence = counter; part.PartitionDescription = "Partition inside a BSD disklabel."; - if(bsd_type != 0) + if(bsdPartition.p_fstype != BSD.fsType.Unused) { partitions.Add(part); counter++; @@ -178,15 +175,15 @@ namespace DiscImageChef.PartPlugins 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 == UNIXDiskLabel_MAGIC) + if(magic == UNIX.UNIXDiskLabel_MAGIC) { - UNIXDiskLabel dl = new UNIXDiskLabel(); - UNIXVTOC vtoc = new UNIXVTOC(); // old/new + 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 == UNIXVTOC_MAGIC) + if(vtoc.magic == UNIX.UNIXVTOC_MAGIC) { isNewDL = true; vtocoffset = 72; @@ -194,7 +191,7 @@ namespace DiscImageChef.PartPlugins else { vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); - if(vtoc.magic != UNIXDiskLabel_MAGIC) + if(vtoc.magic != UNIX.UNIXDiskLabel_MAGIC) { valid = true; break; @@ -225,7 +222,7 @@ namespace DiscImageChef.PartPlugins //dl.pad = br.ReadBytes(48); // 124 } - if(vtoc.magic == UNIXVTOC_MAGIC) + if(vtoc.magic == UNIX.UNIXVTOC_MAGIC) { vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176 byte[] vtoc_name = new byte[8]; @@ -238,14 +235,14 @@ namespace DiscImageChef.PartPlugins // TODO: What if number of slices overlaps sector (>23)? for(int j = 0; j < vtoc.slices; j++) { - UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); + UNIX.UNIXVTOCEntry vtoc_ent = new UNIX.UNIXVTOCEntry(); - vtoc_ent.tag = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 + vtoc_ent.tag = (DiscImageChef.PartPlugins.UNIX.UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 vtoc_ent.flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2); // 162/234 + j*12 vtoc_ent.start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6); // 166/238 + j*12 vtoc_ent.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_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) + 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 @@ -254,7 +251,7 @@ namespace DiscImageChef.PartPlugins part.PartitionStart = vtoc_ent.start * dl.bps; part.PartitionLength = vtoc_ent.length * dl.bps; part.PartitionSequence = counter; - part.PartitionType = string.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); + part.PartitionType = string.Format("UNIX: {0}", UNIX.decodeUNIXTAG(vtoc_ent.tag, isNewDL)); string info = ""; @@ -439,31 +436,28 @@ namespace DiscImageChef.PartPlugins case 0xA9: case 0xB7: // BSD disklabels { - uint magic = BitConverter.ToUInt32(disklabel_sector, 0); + BSD.DiskLabel bsdDisklabel = BSD.GetDiskLabel(disklabel_sector); - if(magic == 0x82564557) + if(bsdDisklabel.d_magic == BSD.DISKMAGIC && bsdDisklabel.d_magic2 == BSD.DISKMAGIC) { - ushort no_parts = BitConverter.ToUInt16(disklabel_sector, 126); - // TODO: Handle disklabels bigger than 1 sector or search max no_parts - for(int j = 0; j < no_parts; j++) + foreach(BSD.BSDPartition bsdPartition in bsdDisklabel.d_partitions) { + CommonTypes.Partition part = new CommonTypes.Partition(); - byte bsd_type; - part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 4); - part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 0); - part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); - part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); - bsd_type = disklabel_sector[134 + j * 16 + 8]; + part.PartitionSectors = bsdPartition.p_size; + part.PartitionStartSector = bsdPartition.p_offset; + part.PartitionLength = bsdPartition.p_size * bsdDisklabel.d_secsize; + part.PartitionStart = bsdPartition.p_offset * bsdDisklabel.d_secsize; - part.PartitionType = string.Format("BSD: {0}", bsd_type); - part.PartitionName = decodeBSDType(bsd_type); + part.PartitionType = string.Format("BSD: {0}", bsdPartition.p_fstype); + part.PartitionName = BSD.fsTypeToString(bsdPartition.p_fstype); part.PartitionSequence = counter; part.PartitionDescription = "Partition inside a BSD disklabel."; - if(bsd_type != 0) + if(bsdPartition.p_fstype != BSD.fsType.Unused) { partitions.Add(part); counter++; @@ -480,15 +474,15 @@ namespace DiscImageChef.PartPlugins 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 == UNIXDiskLabel_MAGIC) + if(magic == UNIX.UNIXDiskLabel_MAGIC) { - UNIXDiskLabel dl = new UNIXDiskLabel(); - UNIXVTOC vtoc = new UNIXVTOC(); // old/new + 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 == UNIXVTOC_MAGIC) + if(vtoc.magic == UNIX.UNIXVTOC_MAGIC) { isNewDL = true; vtocoffset = 72; @@ -496,7 +490,7 @@ namespace DiscImageChef.PartPlugins else { vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); - if(vtoc.magic != UNIXDiskLabel_MAGIC) + if(vtoc.magic != UNIX.UNIXDiskLabel_MAGIC) { valid = true; break; @@ -527,7 +521,7 @@ namespace DiscImageChef.PartPlugins //dl.pad = br.ReadBytes(48); // 124 } - if(vtoc.magic == UNIXVTOC_MAGIC) + if(vtoc.magic == UNIX.UNIXVTOC_MAGIC) { vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176 byte[] vtoc_name = new byte[8]; @@ -540,14 +534,14 @@ namespace DiscImageChef.PartPlugins // TODO: What if number of slices overlaps sector (>23)? for(int j = 0; j < vtoc.slices; j++) { - UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); + UNIX.UNIXVTOCEntry vtoc_ent = new UNIX.UNIXVTOCEntry(); - vtoc_ent.tag = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 + vtoc_ent.tag = (DiscImageChef.PartPlugins.UNIX.UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 vtoc_ent.flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2); // 162/234 + j*12 vtoc_ent.start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6); // 166/238 + j*12 vtoc_ent.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_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) + 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 @@ -556,7 +550,7 @@ namespace DiscImageChef.PartPlugins part.PartitionStart = vtoc_ent.start * dl.bps; part.PartitionLength = vtoc_ent.length * dl.bps; part.PartitionSequence = counter; - part.PartitionType = string.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); + part.PartitionType = string.Format("UNIX: {0}", UNIX.decodeUNIXTAG(vtoc_ent.tag, isNewDL)); string info = ""; @@ -695,43 +689,6 @@ namespace DiscImageChef.PartPlugins #pragma warning restore IDE0004 // Remove Unnecessary Cast } - static string decodeBSDType(byte type) - { - switch(type) - { - case 1: - return "Swap"; - case 2: - return "UNIX Version 6"; - case 3: - return "UNIX Version 7"; - case 4: - return "System V"; - case 5: - return "4.1BSD"; - case 6: - return "UNIX Eigth Edition"; - case 7: - return "4.2BSD"; - case 8: - return "MS-DOS"; - case 9: - return "4.4LFS"; - case 11: - return "HPFS"; - case 12: - return "ISO9660"; - case 13: - return "Boot"; - case 14: - return "Amiga FFS"; - case 15: - return "Apple HFS"; - default: - return "Unknown"; - } - } - static string decodeMBRType(byte type) { switch(type) @@ -1073,163 +1030,5 @@ namespace DiscImageChef.PartPlugins // Total sectors } - const uint UNIXDiskLabel_MAGIC = 0xCA5E600D; - const uint UNIXVTOC_MAGIC = 0x600DDEEE; - // Same as Solaris VTOC - struct UNIXDiskLabel - { - public uint type; - // Drive type, seems always 0 - public uint magic; - // UNIXDiskLabel_MAGIC - public uint version; - // Only seen 1 - public string serial; - // 12 bytes, serial number of the device - public uint cyls; - // data cylinders per device - public uint trks; - // data tracks per cylinder - public uint secs; - // data sectors per track - public uint bps; - // data bytes per sector - public uint start; - // first sector of this partition - public byte[] unknown1; - // 48 bytes - public uint alt_tbl; - // byte offset of alternate table - public uint alt_len; - // byte length of alternate table - // From onward here, is not on old version - public uint phys_cyl; - // physical cylinders per device - public uint phys_trk; - // physical tracks per cylinder - public uint phys_sec; - // physical sectors per track - public uint phys_bytes; - // physical bytes per sector - public uint unknown2; - // - public uint unknown3; - // - public byte[] pad; - // 32bytes - } - - struct UNIXVTOC - { - public uint magic; - // UNIXVTOC_MAGIC - public uint version; - // 1 - public string name; - // 8 bytes - public ushort slices; - // # of slices - public ushort unknown; - // - public byte[] reserved; - // 40 bytes - } - - struct UNIXVTOCEntry - { - public ushort tag; - // TAG - public ushort flags; - // Flags (see below) - public uint start; - // Start sector - public uint length; - // Length of slice in sectors - } - - const ushort UNIX_TAG_EMPTY = 0x0000; - // empty - const ushort UNIX_TAG_BOOT = 0x0001; - // boot - const ushort UNIX_TAG_ROOT = 0x0002; - // root - const ushort UNIX_TAG_SWAP = 0x0003; - // swap - const ushort UNIX_TAG_USER = 0x0004; - // /usr - const ushort UNIX_TAG_WHOLE = 0x0005; - // whole disk - const ushort UNIX_TAG_STAND = 0x0006; - // stand partition ?? - const ushort UNIX_TAG_ALT_S = 0x0006; - // alternate sector space - const ushort UNIX_TAG_VAR = 0x0007; - // /var - const ushort UNIX_TAG_OTHER = 0x0007; - // non UNIX - const ushort UNIX_TAG_HOME = 0x0008; - // /home - const ushort UNIX_TAG_ALT_T = 0x0008; - // alternate track space - const ushort UNIX_TAG_ALT_ST = 0x0009; - // alternate sector track - const ushort UNIX_TAG_NEW_STAND = 0x0009; - // stand partition ?? - const ushort UNIX_TAG_CACHE = 0x000A; - // cache - const ushort UNIX_TAG_NEW_VAR = 0x000A; - // /var - const ushort UNIX_TAG_RESERVED = 0x000B; - // reserved - const ushort UNIX_TAG_NEW_HOME = 0x000B; - // /home - const ushort UNIX_TAG_DUMP = 0x000C; - // dump partition - const ushort UNIX_TAG_NEW_ALT_ST = 0x000D; - // alternate sector track - const ushort UNIX_TAG_VM_PUBLIC = 0x000E; - // volume mgt public partition - const ushort UNIX_TAG_VM_PRIVATE = 0x000F; - // volume mgt private partition - static string decodeUNIXTAG(ushort type, bool isNew) - { - switch(type) - { - case UNIX_TAG_EMPTY: - return "Unused"; - case UNIX_TAG_BOOT: - return "Boot"; - case UNIX_TAG_ROOT: - return "/"; - case UNIX_TAG_SWAP: - return "Swap"; - case UNIX_TAG_USER: - return "/usr"; - case UNIX_TAG_WHOLE: - return "Whole disk"; - case UNIX_TAG_STAND: - return isNew ? "Stand" : "Alternate sector space"; - case UNIX_TAG_VAR: - return isNew ? "/var" : "non UNIX"; - case UNIX_TAG_HOME: - return isNew ? "/home" : "Alternate track space"; - case UNIX_TAG_ALT_ST: - return isNew ? "Alternate sector track" : "Stand"; - case UNIX_TAG_CACHE: - return isNew ? "Cache" : "/var"; - case UNIX_TAG_RESERVED: - return isNew ? "Reserved" : "/home"; - case UNIX_TAG_DUMP: - return "dump"; - case UNIX_TAG_NEW_ALT_ST: - return "Alternate sector track"; - case UNIX_TAG_VM_PUBLIC: - return "volume mgt public partition"; - case UNIX_TAG_VM_PRIVATE: - return "volume mgt private partition"; - default: - return string.Format("Unknown TAG: 0x{0:X4}", type); - } - } } } \ No newline at end of file diff --git a/DiscImageChef.Partitions/PC98.cs b/DiscImageChef.Partitions/PC98.cs new file mode 100644 index 00000000..2b986777 --- /dev/null +++ b/DiscImageChef.Partitions/PC98.cs @@ -0,0 +1,129 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : PC98.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages NEC PC-9800 partitions. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class PC98 : PartPlugin + { + const ushort IntelMagic = 0xAA55; + + public PC98() + { + Name = "NEC PC-9800 partitions table"; + PluginUUID = new Guid("27333401-C7C2-447D-961C-22AD0641A09A\n"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] bootSector = imagePlugin.ReadSector(0); + byte[] sector = imagePlugin.ReadSector(1); + if(sector.Length < 512) + return false; + if(bootSector[0x1FE] != 0x55 || bootSector[0x1FF] != 0xAA) + return false; + + PC98Table table = new PC98Table(); + IntPtr tablePtr = Marshal.AllocHGlobal(512); + Marshal.Copy(sector, 0, tablePtr, 512); + table = (PC98Table)Marshal.PtrToStructure(tablePtr, typeof(PC98Table)); + Marshal.FreeHGlobal(tablePtr); + + ulong counter = 0; + + foreach(PC98Partition entry in table.entries) + { + if(entry.dp_ssect != entry.dp_esect && + entry.dp_shd != entry.dp_ehd && + entry.dp_scyl != entry.dp_ecyl && + entry.dp_ecyl > 0) + { + + Partition part = new Partition(); + part.PartitionStartSector = CHStoLBA(entry.dp_scyl, entry.dp_shd, entry.dp_ssect); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + part.PartitionSectors = CHStoLBA(entry.dp_ecyl, entry.dp_ehd, entry.dp_esect) - part.PartitionStartSector; + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + part.PartitionType = string.Format("{0}", (entry.dp_sid << 8) | entry.dp_mid); + part.PartitionName = entry.dp_name; + part.PartitionSequence = counter; + + partitions.Add(part); + counter++; + } + } + + return true; + } + + static uint CHStoLBA(ushort cyl, byte head, byte sector) + { +#pragma warning disable IDE0004 // Remove Unnecessary Cast + return (((uint)cyl * 16) + (uint)head) * 63 + (uint)sector - 1; +#pragma warning restore IDE0004 // Remove Unnecessary Cast + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PC98Table + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public PC98Partition[] entries; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PC98Partition + { + public byte dp_mid; + public byte dp_sid; + public byte dp_dum1; + public byte dp_dum2; + public byte dp_ipl_sct; + public byte dp_ipl_head; + public ushort dp_ipl_cyl; + public byte dp_ssect; + public byte dp_shd; + public ushort dp_scyl; + public byte dp_esect; + public byte dp_ehd; + public ushort dp_ecyl; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public string dp_name; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/RioKarma.cs b/DiscImageChef.Partitions/RioKarma.cs new file mode 100644 index 00000000..b3a6ddf7 --- /dev/null +++ b/DiscImageChef.Partitions/RioKarma.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : RioKarma.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages Rio Karma partitions. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class RioKarma : PartPlugin + { + const ushort KarmaMagic = 0xAB56; + const byte EntryMagic = 0x4D; + + public RioKarma() + { + Name = "Rio Karma partitioning"; + PluginUUID = new Guid("246A6D93-4F1A-1F8A-344D-50187A5513A9"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] sector = imagePlugin.ReadSector(0); + if(sector.Length < 512) + return false; + + RioKarmaTable table = new RioKarmaTable(); + IntPtr tablePtr = Marshal.AllocHGlobal(512); + Marshal.Copy(sector, 0, tablePtr, 512); + table = (RioKarmaTable)Marshal.PtrToStructure(tablePtr, typeof(RioKarmaTable)); + Marshal.FreeHGlobal(tablePtr); + + if(table.magic != KarmaMagic) + return false; + + ulong counter = 0; + + foreach(RioKarmaEntry entry in table.entries) + { + Partition part = new Partition(); + part.PartitionStartSector = entry.offset; + part.PartitionStart = (ulong)(entry.offset * sector.Length); + part.PartitionLength = entry.size; + part.PartitionSectors = (ulong)(entry.size * sector.Length); + part.PartitionType = "Rio Karma"; + part.PartitionSequence = counter; + if(entry.type == EntryMagic) + { + partitions.Add(part); + counter++; + } + } + + return true; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RioKarmaTable + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 270)] + public byte[] reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public RioKarmaEntry[] entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 208)] + public byte[] padding; + public ushort magic; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RioKarmaEntry + { + public uint reserverd; + public byte type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] reserved2; + public uint offset; + public uint size; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/SGI.cs b/DiscImageChef.Partitions/SGI.cs new file mode 100644 index 00000000..e5b73636 --- /dev/null +++ b/DiscImageChef.Partitions/SGI.cs @@ -0,0 +1,136 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : SGI.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages SGI DVHs. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.Helpers; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class SGI : PartPlugin + { + const int SGI_MAGIC = 0x0BE5A941; + + public SGI() + { + Name = "SGI Disk Volume Header"; + PluginUUID = new Guid("AEF5AB45-4880-4CE8-8735-F0A402E2E5F2"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] sector = imagePlugin.ReadSector(0); + if(sector.Length < 512) + return false; + + SGILabel disklabel = BigEndianStructure.ByteArrayToStructureBigEndian(sector); + + if(disklabel.magic != SGI_MAGIC) + return false; + + ulong counter = 0; + + foreach(SGIPartition entry in disklabel.partitions) + { + Partition part = new Partition(); + part.PartitionStartSector = entry.first_block; + part.PartitionStart = (entry.first_block * 512); + part.PartitionLength = entry.num_blocks; + part.PartitionSectors = (entry.num_blocks * 512); + part.PartitionType = string.Format("{0}", entry.type); + part.PartitionSequence = counter; + if(part.PartitionLength > 0) + { + partitions.Add(part); + counter++; + } + } + + return true; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SGILabel + { + /// + public uint magic; + /// + public ushort root_part_num; + /// + public ushort swap_part_num; + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] boot_file; + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] device_params; + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public SGIVolume[] volume; + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public SGIPartition[] partitions; + /// + public uint csum; + /// + public uint padding; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SGIVolume + { + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] name; + /// + public uint block_num; + /// + public uint num_bytes; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SGIPartition + { + /// + public uint num_blocks; + /// + public uint first_block; + /// + public uint type; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/Sun.cs b/DiscImageChef.Partitions/Sun.cs index dcce3d5b..ee418b34 100644 --- a/DiscImageChef.Partitions/Sun.cs +++ b/DiscImageChef.Partitions/Sun.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using DiscImageChef.Console; namespace DiscImageChef.PartPlugins @@ -52,10 +53,20 @@ namespace DiscImageChef.PartPlugins SunStand = 0x0006, SunVar = 0x0007, SunHome = 0x0008, + SunAlt = 0x0009, + SunCache = 0x000A, + VxVmPublic = 0x000E, + VxVmPrivate = 0x000F, LinuxSwap = 0x0082, Linux = 0x0083, LVM = 0x008E, - LinuxRaid = 0x00FD + LinuxRaid = 0x00FD, + NetBSD = 0x00FF, + FreeBSD_Swap = 0x0901, + FreeBSD_UFS = 0x0902, + FreeBSD_Vinum = 0x0903, + FreeBSD_ZFS = 0x0904, + FreeBSD_NANDFS = 0x0905 } [Flags] @@ -255,11 +266,13 @@ namespace DiscImageChef.PartPlugins } } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SunDiskLabel { /// /// Offset 0x000: Informative string, 128 bytes /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public string info; /// /// Offset 0x080: Volume Table Of Contents @@ -276,6 +289,7 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x110: Unused, 148 bytes /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 148)] public byte[] spare; /// /// Offset 0x1A4: Rotational speed @@ -328,6 +342,7 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x1BC: Partitions /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public SunPartition[] partitions; /// /// Offset 0x1FC: @@ -339,6 +354,7 @@ namespace DiscImageChef.PartPlugins public ushort csum; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SunVTOC { /// @@ -348,6 +364,7 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x04: Volume name, 8 bytes /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public string volname; /// /// Offset 0x0C: Number of partitions @@ -356,6 +373,7 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x0E: Partition information, 8 entries /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public SunInfo[] infos; /// /// Offset 0x2E: Padding @@ -364,6 +382,7 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x30: Information needed by mboot, 3 entries /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public uint[] bootinfo; /// /// Offset 0x3C: VTOC magic @@ -372,13 +391,16 @@ namespace DiscImageChef.PartPlugins /// /// Offset 0x40: Reserved, 40 bytes /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] public byte[] reserved; /// /// Offset 0x68: Partition timestamps, 8 entries /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public uint[] timestamp; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SunInfo { /// @@ -391,6 +413,7 @@ namespace DiscImageChef.PartPlugins public ushort flags; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SunPartition { /// diff --git a/DiscImageChef.Partitions/UNIX.cs b/DiscImageChef.Partitions/UNIX.cs new file mode 100644 index 00000000..565d0d3e --- /dev/null +++ b/DiscImageChef.Partitions/UNIX.cs @@ -0,0 +1,341 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : UNIX.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages UNIX VTOC and disklabels. +// +// --[ 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins +{ + class UNIX : PartPlugin + { + public const uint UNIXDiskLabel_MAGIC = 0xCA5E600D; + public const uint UNIXVTOC_MAGIC = 0x600DDEEE; + + public UNIX() + { + Name = "UNIX VTOC and disklabel"; + PluginUUID = new Guid("6D35A66F-8D77-426F-A562-D88F6A1F1702"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + uint magic; + byte[] unix_dl_sector; + + unix_dl_sector = imagePlugin.ReadSector(0); + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + if(magic != UNIXDiskLabel_MAGIC) + { + unix_dl_sector = imagePlugin.ReadSector(1); + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + if(magic != UNIXDiskLabel_MAGIC) + { + unix_dl_sector = imagePlugin.ReadSector(8); + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + + if(magic != UNIXDiskLabel_MAGIC) + { + unix_dl_sector = imagePlugin.ReadSector(29); + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + + if(magic != UNIXDiskLabel_MAGIC) + return false; + } + } + } + + UNIXDiskLabel dl = new UNIXDiskLabel(); + UNIXVTOC vtoc = new UNIXVTOC(); // old/new + bool isNewDL = false; + int vtocoffset = 0; + ulong counter = 0; + + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if(vtoc.magic == UNIXVTOC_MAGIC) + { + isNewDL = true; + vtocoffset = 72; + } + else + { + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if(vtoc.magic != UNIXDiskLabel_MAGIC) + { + return false; + } + } + + 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.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 + } + + if(vtoc.magic == 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 + + // TODO: What if number of slices overlaps sector (>23)? + for(int j = 0; j < vtoc.slices; j++) + { + UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); + + vtoc_ent.tag = (UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 + vtoc_ent.flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2); // 162/234 + j*12 + vtoc_ent.start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6); // 166/238 + j*12 + vtoc_ent.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_TAG.EMPTY && vtoc_ent.tag != UNIX_TAG.WHOLE) + { + Partition part = new Partition(); + part.PartitionStartSector = vtoc_ent.start; + part.PartitionSectors = vtoc_ent.length; + part.PartitionStart = vtoc_ent.start * dl.bps; + part.PartitionLength = vtoc_ent.length * dl.bps; + part.PartitionSequence = counter; + part.PartitionType = string.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); + + string info = ""; + + if((vtoc_ent.flags & 0x01) == 0x01) + info += " (do not mount)"; + if((vtoc_ent.flags & 0x10) == 0x10) + info += " (do not mount)"; + + part.PartitionDescription = "UNIX slice" + info + "."; + + partitions.Add(part); + counter++; + } + } + } + + return true; + } + + // Same as Solaris VTOC + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UNIXDiskLabel + { + /// Drive type, seems always 0 + public uint type; + /// UNIXDiskLabel_MAGIC + public uint magic; + /// Only seen 1 + public uint version; + /// 12 bytes, serial number of the device + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public string serial; + /// data cylinders per device + public uint cyls; + /// data tracks per cylinder + public uint trks; + /// data sectors per track + public uint secs; + /// data bytes per sector + public uint bps; + /// first sector of this partition + public uint start; + /// 48 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] unknown1; + /// byte offset of alternate table + public uint alt_tbl; + /// byte length of alternate table + public uint alt_len; + // From onward here, is not on old version + /// physical cylinders per device + public uint phys_cyl; + /// physical tracks per cylinder + public uint phys_trk; + /// physical sectors per track + public uint phys_sec; + /// physical bytes per sector + public uint phys_bytes; + /// + public uint unknown2; + /// + public uint unknown3; + /// 32bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] pad; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UNIXVTOC + { + /// UNIXVTOC_MAGIC + public uint magic; + /// 1 + public uint version; + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public string name; + /// # of slices + public ushort slices; + /// + public ushort unknown; + /// 40 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public byte[] reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UNIXVTOCEntry + { + /// TAG + public UNIX_TAG tag; + public ushort flags; + /// Flags (see below) + public uint start; + /// Start sector + public uint length; + /// Length of slice in sectors + } + + public enum UNIX_TAG : ushort + { + /// empty + EMPTY = 0x0000, + /// boot + BOOT = 0x0001, + /// root + ROOT = 0x0002, + /// swap + SWAP = 0x0003, + /// /usr + USER = 0x0004, + /// whole disk + WHOLE = 0x0005, + /// stand partition ?? + STAND = 0x0006, + /// alternate sector space + ALT_S = 0x0006, + /// /var + VAR = 0x0007, + /// non UNIX + OTHER = 0x0007, + /// /home + HOME = 0x0008, + /// alternate track space + ALT_T = 0x0008, + /// alternate sector track + ALT_ST = 0x0009, + /// stand partition ?? + NEW_STAND = 0x0009, + /// cache + CACHE = 0x000A, + /// /var + NEW_VAR = 0x000A, + /// reserved + RESERVED = 0x000B, + /// /home + NEW_HOME = 0x000B, + /// dump partition + DUMP = 0x000C, + /// alternate sector track + NEW_ALT_ST = 0x000D, + /// volume mgt public partition + VM_PUBLIC = 0x000E, + /// volume mgt private partition + VM_PRIVATE = 0x000F + } + + public static string decodeUNIXTAG(UNIX_TAG type, bool isNew) + { + switch(type) + { + case UNIX_TAG.EMPTY: + return "Unused"; + case UNIX_TAG.BOOT: + return "Boot"; + case UNIX_TAG.ROOT: + return "/"; + case UNIX_TAG.SWAP: + return "Swap"; + case UNIX_TAG.USER: + return "/usr"; + case UNIX_TAG.WHOLE: + return "Whole disk"; + case UNIX_TAG.STAND: + return isNew ? "Stand" : "Alternate sector space"; + case UNIX_TAG.VAR: + return isNew ? "/var" : "non UNIX"; + case UNIX_TAG.HOME: + return isNew ? "/home" : "Alternate track space"; + case UNIX_TAG.ALT_ST: + return isNew ? "Alternate sector track" : "Stand"; + case UNIX_TAG.CACHE: + return isNew ? "Cache" : "/var"; + case UNIX_TAG.RESERVED: + return isNew ? "Reserved" : "/home"; + case UNIX_TAG.DUMP: + return "dump"; + case UNIX_TAG.NEW_ALT_ST: + return "Alternate sector track"; + case UNIX_TAG.VM_PUBLIC: + return "volume mgt public partition"; + case UNIX_TAG.VM_PRIVATE: + return "volume mgt private partition"; + default: + return string.Format("Unknown TAG: 0x{0:X4}", type); + } + } + + } +} \ No newline at end of file diff --git a/README.md b/README.md index a402c1b1..1502afe0 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,14 @@ Supported partitioning schemes * Atari AHDI and ICDPro * Sun disklabel * EFI GUID Partition Table (GPT) +* Acorn Linux and RISCiX partitions +* BSD disklabels +* DragonFly BSD 64-bit disklabel +* DEC disklabels +* NEC PC9800 partitions +* SGI volume headers +* Rio Karma partitions +* UNIX VTOC and disklabel Supported file systems for read-only operations =============================================== diff --git a/TODO b/TODO index 610ad5f9..a7907313 100644 --- a/TODO +++ b/TODO @@ -38,10 +38,7 @@ Filesystem plugins: --- Add support for ECMA-67 Partitioning scheme plugins: ---- Add support for Acorn partitions --- Add support for AIX partitions ---- Add support for SGI partitions ---- Add support for Ultrix partitions Teledisk plugin: --- Add support for "advanced compression"