mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
343 lines
14 KiB
C#
343 lines
14 KiB
C#
// /***************************************************************************
|
|
// 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-2017 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using DiscImageChef.CommonTypes;
|
|
using DiscImageChef.ImagePlugins;
|
|
|
|
namespace DiscImageChef.PartPlugins
|
|
{
|
|
public 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
|
|
{
|
|
tag = (UNIX_TAG)BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0), // 160/232 + j*12
|
|
flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2), // 162/234 + j*12
|
|
start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6), // 166/238 + j*12
|
|
length = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 10) // 170/242 + j*12
|
|
};
|
|
if((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX_TAG.EMPTY && vtoc_ent.tag != UNIX_TAG.WHOLE)
|
|
{
|
|
Partition part = new Partition
|
|
{
|
|
Start = vtoc_ent.start,
|
|
Length = vtoc_ent.length,
|
|
Offset = vtoc_ent.start * dl.bps,
|
|
Size = vtoc_ent.length * dl.bps,
|
|
Sequence = counter,
|
|
Type = string.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)),
|
|
Scheme = Name
|
|
};
|
|
string info = "";
|
|
|
|
if((vtoc_ent.flags & 0x01) == 0x01)
|
|
info += " (do not mount)";
|
|
if((vtoc_ent.flags & 0x10) == 0x10)
|
|
info += " (do not mount)";
|
|
|
|
part.Description = "UNIX slice" + info + ".";
|
|
|
|
partitions.Add(part);
|
|
counter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
} |