Files
Aaru/DiscImageChef.Partitions/UNIX.cs

341 lines
14 KiB
C#
Raw Normal View History

* DiscImageChef.Helpers/BigEndianStructure.cs: * DiscImageChef.Helpers/DiscImageChef.Helpers.csproj: Added code that directly marshals from a big-endian byte array. But untested with nested structures. * DiscImageChef.Partitions/Acorn.cs: Added support for Acorn FileCore partition, closes #4. * DiscImageChef.Partitions/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. * DiscImageChef.Partitions/DEC.cs: Added support for DEC disklabels, closes #11. * DiscImageChef.Partitions/DragonFlyBSD.cs: Added support for DragonFly BSD 64-bit disklabels. * DiscImageChef.Partitions/PC98.cs: Added support for NEC PC-9800 partitions. * DiscImageChef.Partitions/RioKarma.cs: Added support for Rio Karma partitions. * DiscImageChef.Partitions/SGI.cs: Added support for SGI DVHs, closes #9. * DiscImageChef.Partitions/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. * TODO: * README.md: * DiscImageChef.Partitions/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. * DiscImageChef.Partitions/GPT.cs: Added new partition type UUIDs. * DiscImageChef.Partitions/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. * DiscImageChef.Partitions/Sun.cs: Added new partition types. Prepare structures for marshaling.
2016-08-21 08:27:43 +01:00
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : UNIX.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// 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<Partition> partitions)
{
partitions = new List<Partition>();
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
{
/// <summary>Drive type, seems always 0</summary>
public uint type;
/// <summary>UNIXDiskLabel_MAGIC</summary>
public uint magic;
/// <summary>Only seen 1</summary>
public uint version;
/// <summary>12 bytes, serial number of the device</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public string serial;
/// <summary>data cylinders per device</summary>
public uint cyls;
/// <summary>data tracks per cylinder</summary>
public uint trks;
/// <summary>data sectors per track</summary>
public uint secs;
/// <summary>data bytes per sector</summary>
public uint bps;
/// <summary>first sector of this partition</summary>
public uint start;
/// <summary>48 bytes</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
public byte[] unknown1;
/// <summary>byte offset of alternate table</summary>
public uint alt_tbl;
/// <summary>byte length of alternate table</summary>
public uint alt_len;
// From onward here, is not on old version
/// <summary>physical cylinders per device</summary>
public uint phys_cyl;
/// <summary>physical tracks per cylinder</summary>
public uint phys_trk;
/// <summary>physical sectors per track</summary>
public uint phys_sec;
/// <summary>physical bytes per sector</summary>
public uint phys_bytes;
/// <summary></summary>
public uint unknown2;
/// <summary></summary>
public uint unknown3;
/// <summary>32bytes</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] pad;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNIXVTOC
{
/// <summary>UNIXVTOC_MAGIC</summary>
public uint magic;
/// <summary>1</summary>
public uint version;
/// <summary>8 bytes</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public string name;
/// <summary># of slices</summary>
public ushort slices;
/// <summary></summary>
public ushort unknown;
/// <summary>40 bytes</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNIXVTOCEntry
{
/// <summary>TAG</summary>
public UNIX_TAG tag;
public ushort flags;
/// <summary>Flags (see below)</summary>
public uint start;
/// <summary>Start sector</summary>
public uint length;
/// <summary>Length of slice in sectors</summary>
}
public enum UNIX_TAG : ushort
{
/// <summary>empty</summary>
EMPTY = 0x0000,
/// <summary>boot</summary>
BOOT = 0x0001,
/// <summary>root</summary>
ROOT = 0x0002,
/// <summary>swap</summary>
SWAP = 0x0003,
/// <summary>/usr</summary>
USER = 0x0004,
/// <summary>whole disk</summary>
WHOLE = 0x0005,
/// <summary>stand partition ??</summary>
STAND = 0x0006,
/// <summary>alternate sector space</summary>
ALT_S = 0x0006,
/// <summary>/var</summary>
VAR = 0x0007,
/// <summary>non UNIX</summary>
OTHER = 0x0007,
/// <summary>/home</summary>
HOME = 0x0008,
/// <summary>alternate track space</summary>
ALT_T = 0x0008,
/// <summary>alternate sector track</summary>
ALT_ST = 0x0009,
/// <summary>stand partition ??</summary>
NEW_STAND = 0x0009,
/// <summary>cache</summary>
CACHE = 0x000A,
/// <summary>/var</summary>
NEW_VAR = 0x000A,
/// <summary>reserved</summary>
RESERVED = 0x000B,
/// <summary>/home</summary>
NEW_HOME = 0x000B,
/// <summary>dump partition</summary>
DUMP = 0x000C,
/// <summary>alternate sector track</summary>
NEW_ALT_ST = 0x000D,
/// <summary>volume mgt public partition</summary>
VM_PUBLIC = 0x000E,
/// <summary>volume mgt private partition</summary>
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);
}
}
}
}