mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 11:14:25 +00:00
687 lines
29 KiB
C#
687 lines
29 KiB
C#
// /***************************************************************************
|
|
// Aaru Data Preservation Suite
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : VTOC.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-2025 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using Aaru.CommonTypes;
|
|
using Aaru.CommonTypes.Attributes;
|
|
using Aaru.CommonTypes.Enums;
|
|
using Aaru.CommonTypes.Interfaces;
|
|
using Aaru.Helpers;
|
|
using Aaru.Logging;
|
|
using Marshal = Aaru.Helpers.Marshal;
|
|
|
|
namespace Aaru.Partitions;
|
|
|
|
/// <inheritdoc />
|
|
/// <summary>Implements decoding of UNIX VTOC partitions</summary>
|
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
|
public sealed partial class VTOC : IPartition
|
|
{
|
|
const uint PD_MAGIC = 0xCA5E600D;
|
|
const uint VTOC_SANE = 0x600DDEEE;
|
|
const uint PD_CIGAM = 0x0D605ECA;
|
|
const uint VTOC_ENAS = 0xEEDE0D60;
|
|
const int V_NUMPAR = 16;
|
|
const uint XPDVERS = 3; /* 1st version of extended pdinfo */
|
|
const string MODULE_NAME = "UNIX VTOC plugin";
|
|
|
|
#region IPartition Members
|
|
|
|
/// <inheritdoc />
|
|
public string Name => Localization.VTOC_Name;
|
|
|
|
/// <inheritdoc />
|
|
public Guid Id => new("6D35A66F-8D77-426F-A562-D88F6A1F1702");
|
|
|
|
/// <inheritdoc />
|
|
public string Author => Authors.NATALIA_PORTILLO;
|
|
|
|
/// <inheritdoc />
|
|
public bool GetInformation(IMediaImage imagePlugin, out List<Partition> partitions, ulong sectorOffset)
|
|
{
|
|
partitions = [];
|
|
|
|
uint magic = 0;
|
|
ulong pdloc = 0;
|
|
byte[] pdsector = null;
|
|
var magicFound = false;
|
|
var absolute = false;
|
|
ErrorNumber errno;
|
|
|
|
foreach(ulong i in new ulong[]
|
|
{
|
|
0, 1, 8, 29
|
|
}.TakeWhile(i => i + sectorOffset < imagePlugin.Info.Sectors))
|
|
{
|
|
errno = imagePlugin.ReadSector(i + sectorOffset, false, out pdsector, out _);
|
|
|
|
if(errno != ErrorNumber.NoError) continue;
|
|
|
|
magic = BitConverter.ToUInt32(pdsector, 4);
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
Localization.sanity_at_0_is_1_X8_should_be_2_X8_or_3_X8,
|
|
i + sectorOffset,
|
|
magic,
|
|
PD_MAGIC,
|
|
PD_CIGAM);
|
|
|
|
if(magic != PD_MAGIC && magic != PD_CIGAM) continue;
|
|
|
|
magicFound = true;
|
|
pdloc = i;
|
|
|
|
break;
|
|
}
|
|
|
|
if(!magicFound) return false;
|
|
|
|
PDInfo pd;
|
|
PDInfoOld pdold;
|
|
|
|
if(magic == PD_MAGIC)
|
|
{
|
|
pd = Marshal.ByteArrayToStructureLittleEndian<PDInfo>(pdsector);
|
|
pdold = Marshal.ByteArrayToStructureLittleEndian<PDInfoOld>(pdsector);
|
|
}
|
|
else
|
|
{
|
|
pd = Marshal.ByteArrayToStructureBigEndian<PDInfo>(pdsector);
|
|
pdold = Marshal.ByteArrayToStructureBigEndian<PDInfoOld>(pdsector);
|
|
}
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.driveid = {0}", pd.driveid);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.sanity = 0x{0:X8} (should be 0x{1:X8})", pd.sanity, PD_MAGIC);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.version = {0}", pd.version);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.serial = \"{0}\"", StringHandlers.CToString(pd.serial));
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.cyls = {0}", pd.cyls);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.tracks = {0}", pd.tracks);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.sectors = {0}", pd.sectors);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.bytes = {0}", pd.bytes);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.logicalst = {0}", pd.logicalst);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.errlogst = {0}", pd.errlogst);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.errlogsz = {0}", pd.errlogsz);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.mfgst = {0}", pd.mfgst);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.mfgsz = {0}", pd.mfgsz);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.defectst = {0}", pd.defectst);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.defectsz = {0}", pd.defectsz);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.relno = {0}", pd.relno);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.relst = {0}", pd.relst);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.relsz = {0}", pd.relsz);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.relnext = {0}", pd.relnext);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.allcstrt = {0}", pdold.allcstrt);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.allcend = {0}", pdold.allcend);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.vtoc_ptr = {0}", pd.vtoc_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.vtoc_len = {0}", pd.vtoc_len);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.vtoc_pad = {0}", pd.vtoc_pad);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.alt_ptr = {0}", pd.alt_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.alt_len = {0}", pd.alt_len);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pcyls = {0}", pd.pcyls);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.ptracks = {0}", pd.ptracks);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.psectors = {0}", pd.psectors);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pbytes = {0}", pd.pbytes);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.secovhd = {0}", pd.secovhd);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.interleave = {0}", pd.interleave);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.skew = {0}", pd.skew);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[0] = {0}", pd.pad[0]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[1] = {0}", pd.pad[1]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[2] = {0}", pd.pad[2]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[3] = {0}", pd.pad[3]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[4] = {0}", pd.pad[4]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[5] = {0}", pd.pad[5]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[6] = {0}", pd.pad[6]);
|
|
AaruLogging.Debug(MODULE_NAME, "pdinfo.pad[7] = {0}", pd.pad[7]);
|
|
|
|
magicFound = false;
|
|
var useOld = false;
|
|
errno = imagePlugin.ReadSector(pdloc + sectorOffset + 1, false, out byte[] vtocsector, out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return false;
|
|
|
|
var vtoc = new Vtoc();
|
|
var vtocOld = new VTocOld();
|
|
magic = BitConverter.ToUInt32(vtocsector, 0);
|
|
|
|
if(magic is VTOC_SANE or VTOC_ENAS)
|
|
{
|
|
magicFound = true;
|
|
AaruLogging.Debug(MODULE_NAME, Localization.New_VTOC_found_at_0, pdloc + sectorOffset + 1);
|
|
|
|
if(magic == VTOC_SANE)
|
|
vtoc = Marshal.ByteArrayToStructureLittleEndian<Vtoc>(vtocsector);
|
|
else
|
|
{
|
|
vtoc = Marshal.ByteArrayToStructureBigEndian<Vtoc>(vtocsector);
|
|
|
|
for(var i = 0; i < vtoc.v_part.Length; i++)
|
|
{
|
|
vtoc.v_part[i].p_tag = (pTag)Swapping.Swap((ushort)vtoc.v_part[i].p_tag);
|
|
vtoc.v_part[i].p_flag = (pFlag)Swapping.Swap((ushort)vtoc.v_part[i].p_flag);
|
|
vtoc.v_part[i].p_start = Swapping.Swap(vtoc.v_part[i].p_start);
|
|
vtoc.v_part[i].p_size = Swapping.Swap(vtoc.v_part[i].p_size);
|
|
vtoc.timestamp[i] = Swapping.Swap(vtoc.timestamp[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!magicFound && pd.version < XPDVERS)
|
|
{
|
|
magic = BitConverter.ToUInt32(vtocsector, 12);
|
|
|
|
if(magic is VTOC_SANE or VTOC_ENAS)
|
|
{
|
|
magicFound = true;
|
|
useOld = true;
|
|
AaruLogging.Debug(MODULE_NAME, Localization.Old_VTOC_found_at_0, pdloc + sectorOffset + 1);
|
|
|
|
if(magic == VTOC_SANE)
|
|
vtocOld = Marshal.ByteArrayToStructureLittleEndian<VTocOld>(vtocsector);
|
|
else
|
|
{
|
|
vtocOld = Marshal.ByteArrayToStructureBigEndian<VTocOld>(vtocsector);
|
|
|
|
for(var i = 0; i < vtocOld.v_part.Length; i++)
|
|
{
|
|
vtocOld.v_part[i].p_tag = (pTag)Swapping.Swap((ushort)vtocOld.v_part[i].p_tag);
|
|
vtocOld.v_part[i].p_flag = (pFlag)Swapping.Swap((ushort)vtocOld.v_part[i].p_flag);
|
|
vtocOld.v_part[i].p_start = Swapping.Swap(vtocOld.v_part[i].p_start);
|
|
vtocOld.v_part[i].p_size = Swapping.Swap(vtocOld.v_part[i].p_size);
|
|
vtocOld.timestamp[i] = Swapping.Swap(vtocOld.timestamp[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!magicFound)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME, Localization.Searching_for_VTOC_on_relative_byte_0, pd.vtoc_ptr);
|
|
ulong relSecPtr = pd.vtoc_ptr / imagePlugin.Info.SectorSize;
|
|
uint relSecOff = pd.vtoc_ptr % imagePlugin.Info.SectorSize;
|
|
uint secCount = (relSecOff + pd.vtoc_len) / imagePlugin.Info.SectorSize;
|
|
|
|
if((relSecOff + pd.vtoc_len) % imagePlugin.Info.SectorSize > 0) secCount++;
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
Localization.Going_to_read_0_sectors_from_sector_1_getting_VTOC_from_byte_2,
|
|
secCount,
|
|
relSecPtr + sectorOffset,
|
|
relSecOff);
|
|
|
|
if(relSecPtr + sectorOffset + secCount >= imagePlugin.Info.Sectors)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME, Localization.Going_to_read_past_device_size_aborting);
|
|
|
|
return false;
|
|
}
|
|
|
|
errno = imagePlugin.ReadSectors(relSecPtr + sectorOffset, false, secCount, out byte[] tmp, out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return false;
|
|
|
|
vtocsector = new byte[pd.vtoc_len];
|
|
Array.Copy(tmp, relSecOff, vtocsector, 0, pd.vtoc_len);
|
|
magic = BitConverter.ToUInt32(vtocsector, 0);
|
|
|
|
if(magic is VTOC_SANE or VTOC_ENAS)
|
|
{
|
|
magicFound = true;
|
|
AaruLogging.Debug(MODULE_NAME, Localization.New_VTOC_found);
|
|
|
|
if(magic == VTOC_SANE)
|
|
vtoc = Marshal.ByteArrayToStructureLittleEndian<Vtoc>(vtocsector);
|
|
else
|
|
{
|
|
vtoc = Marshal.ByteArrayToStructureBigEndian<Vtoc>(vtocsector);
|
|
|
|
for(var i = 0; i < vtoc.v_part.Length; i++)
|
|
{
|
|
vtoc.v_part[i].p_tag = (pTag)Swapping.Swap((ushort)vtoc.v_part[i].p_tag);
|
|
vtoc.v_part[i].p_flag = (pFlag)Swapping.Swap((ushort)vtoc.v_part[i].p_flag);
|
|
vtoc.v_part[i].p_start = Swapping.Swap(vtoc.v_part[i].p_start);
|
|
vtoc.v_part[i].p_size = Swapping.Swap(vtoc.v_part[i].p_size);
|
|
vtoc.timestamp[i] = Swapping.Swap(vtoc.timestamp[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!magicFound)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME, Localization.Cannot_find_VTOC);
|
|
|
|
return false;
|
|
}
|
|
|
|
if(useOld)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtocOld.v_sanity = 0x{0:X8} (should be 0x{1:X8})",
|
|
vtocOld.v_sanity,
|
|
VTOC_SANE);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_version = {0}", vtocOld.v_version);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_volume = \"{0}\"", StringHandlers.CToString(vtocOld.v_volume));
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_sectorsz = {0}", vtocOld.v_sectorsz);
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_nparts = {0}", vtocOld.v_nparts);
|
|
|
|
for(var i = 0; i < V_NUMPAR; i++)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtocOld.v_part[{0}].p_tag = {1} ({2})",
|
|
i,
|
|
vtocOld.v_part[i].p_tag,
|
|
(ushort)vtocOld.v_part[i].p_tag);
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtocOld.v_part[{0}].p_flag = {1} ({2})",
|
|
i,
|
|
vtocOld.v_part[i].p_flag,
|
|
(ushort)vtocOld.v_part[i].p_flag);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_part[{0}].p_start = {1}", i, vtocOld.v_part[i].p_start);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtocOld.v_part[{0}].p_size = {1}", i, vtocOld.v_part[i].p_size);
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtocOld.timestamp[{0}] = {1}",
|
|
i,
|
|
DateHandlers.UnixToDateTime(vtocOld.timestamp[i]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_sanity = 0x{0:X8} (should be 0x{1:X8})", vtoc.v_sanity, VTOC_SANE);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_version = {0}", vtoc.v_version);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_volume = \"{0}\"", StringHandlers.CToString(vtoc.v_volume));
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_pad = {0}", vtoc.v_pad);
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_nparts = {0}", vtoc.v_nparts);
|
|
|
|
for(var i = 0; i < V_NUMPAR; i++)
|
|
{
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtoc.v_part[{0}].p_tag = {1} ({2})",
|
|
i,
|
|
vtoc.v_part[i].p_tag,
|
|
(ushort)vtoc.v_part[i].p_tag);
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtoc.v_part[{0}].p_flag = {1} ({2})",
|
|
i,
|
|
vtoc.v_part[i].p_flag,
|
|
(ushort)vtoc.v_part[i].p_flag);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_part[{0}].p_start = {1}", i, vtoc.v_part[i].p_start);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "vtoc.v_part[{0}].p_size = {1}", i, vtoc.v_part[i].p_size);
|
|
|
|
AaruLogging.Debug(MODULE_NAME,
|
|
"vtoc.timestamp[{0}] = {1}",
|
|
i,
|
|
DateHandlers.UnixToDateTime(vtoc.timestamp[i]));
|
|
}
|
|
}
|
|
|
|
uint bps;
|
|
VtocPartition[] parts;
|
|
int[] timestamps;
|
|
|
|
if(useOld)
|
|
{
|
|
bps = vtocOld.v_sectorsz;
|
|
parts = vtocOld.v_part;
|
|
timestamps = vtocOld.timestamp;
|
|
}
|
|
else
|
|
{
|
|
bps = pd.bytes;
|
|
parts = vtoc.v_part;
|
|
timestamps = vtoc.timestamp;
|
|
}
|
|
|
|
// Check for a partition describing the VTOC whose start is the same as the start we know.
|
|
// This means partition starts are absolute, not relative, to the VTOC position
|
|
for(var i = 0; i < V_NUMPAR; i++)
|
|
{
|
|
if(parts[i].p_tag != pTag.V_BACKUP || (ulong)parts[i].p_start != sectorOffset) continue;
|
|
|
|
absolute = true;
|
|
|
|
break;
|
|
}
|
|
|
|
for(var i = 0; i < V_NUMPAR; i++)
|
|
{
|
|
if(parts[i].p_tag == pTag.V_UNUSED) continue;
|
|
|
|
var part = new Partition
|
|
{
|
|
Start = (ulong)(parts[i].p_start * bps) / imagePlugin.Info.SectorSize,
|
|
Length = (ulong)(parts[i].p_size * bps) / imagePlugin.Info.SectorSize,
|
|
Offset = (ulong)(parts[i].p_start * bps),
|
|
Size = (ulong)(parts[i].p_size * bps),
|
|
Sequence = (ulong)i,
|
|
Type = $"UNIX: {DecodeUnixtag(parts[i].p_tag, !useOld)}",
|
|
Scheme = Name
|
|
};
|
|
|
|
var info = "";
|
|
|
|
// Apparently old ones are absolute :?
|
|
if(!useOld && !absolute)
|
|
{
|
|
part.Start += sectorOffset;
|
|
part.Offset += sectorOffset * imagePlugin.Info.SectorSize;
|
|
}
|
|
|
|
if(parts[i].p_flag.HasFlag(pFlag.V_VALID)) info += Localization.valid;
|
|
|
|
if(parts[i].p_flag.HasFlag(pFlag.V_UNMNT)) info += Localization._unmountable_;
|
|
|
|
if(parts[i].p_flag.HasFlag(pFlag.V_OPEN)) info += Localization.open;
|
|
|
|
if(parts[i].p_flag.HasFlag(pFlag.V_REMAP)) info += Localization.alternate_sector_mapping;
|
|
|
|
if(parts[i].p_flag.HasFlag(pFlag.V_RONLY)) info += Localization._read_only_;
|
|
|
|
if(timestamps[i] != 0)
|
|
info += string.Format(Localization.created_on_0, DateHandlers.UnixToDateTime(timestamps[i]));
|
|
|
|
part.Description = "UNIX slice" + info + ".";
|
|
|
|
if(part.End < imagePlugin.Info.Sectors) partitions.Add(part);
|
|
}
|
|
|
|
return partitions.Count > 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
static string DecodeUnixtag(pTag type, bool isNew) => type switch
|
|
{
|
|
pTag.V_UNUSED => Localization.Unused,
|
|
pTag.V_BOOT => Localization.Boot,
|
|
pTag.V_ROOT => "/",
|
|
pTag.V_SWAP => Localization.swap,
|
|
pTag.V_USER => "/usr",
|
|
pTag.V_BACKUP => Localization.Whole_disk,
|
|
pTag.V_STAND_OLD => isNew
|
|
? "Stand"
|
|
: Localization.Alternate_sector_space,
|
|
pTag.V_VAR_OLD => isNew ? "/var" : Localization.non_UNIX,
|
|
pTag.V_HOME_OLD => isNew
|
|
? "/home"
|
|
: Localization.Alternate_track_space,
|
|
pTag.V_ALTSCTR_OLD => isNew
|
|
? Localization.Alternate_sector_track
|
|
: "Stand",
|
|
pTag.V_CACHE => isNew ? Localization.Cache : "/var",
|
|
pTag.V_RESERVED =>
|
|
isNew ? Localization.Reserved : "/home",
|
|
pTag.V_DUMP => Localization.dump,
|
|
pTag.V_ALTSCTR => Localization.Alternate_sector_track,
|
|
pTag.V_VMPUBLIC => Localization
|
|
.volume_mgt_public_partition,
|
|
pTag.V_VMPRIVATE => Localization
|
|
.volume_mgt_private_partition,
|
|
_ => string.Format(Localization.Unknown_TAG_0, type)
|
|
};
|
|
|
|
#region Nested type: PDInfo
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SwapEndian]
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
partial struct PDInfo
|
|
{
|
|
public uint driveid; /*identifies the device type*/
|
|
public uint sanity; /*verifies device sanity*/
|
|
public uint version; /*version number*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
|
|
public byte[] serial; /*serial number of the device*/
|
|
public uint cyls; /*number of cylinders per drive*/
|
|
public uint tracks; /*number tracks per cylinder*/
|
|
public uint sectors; /*number sectors per track*/
|
|
public uint bytes; /*number of bytes per sector*/
|
|
public uint logicalst; /*sector address of logical sector 0*/
|
|
public uint errlogst; /*sector address of error log area*/
|
|
public uint errlogsz; /*size in bytes of error log area*/
|
|
public uint mfgst; /*sector address of mfg. defect info*/
|
|
public uint mfgsz; /*size in bytes of mfg. defect info*/
|
|
public uint defectst; /*sector address of the defect map*/
|
|
public uint defectsz; /*size in bytes of defect map*/
|
|
public uint relno; /*number of relocation areas*/
|
|
public uint relst; /*sector address of relocation area*/
|
|
public uint relsz; /*size in sectors of relocation area*/
|
|
public uint relnext; /*address of next avail reloc sector*/
|
|
/* the previous items are left intact from AT&T's 3b2 pdinfo. Following
|
|
are added for the 80386 port */
|
|
public uint vtoc_ptr; /*byte offset of vtoc block*/
|
|
public ushort vtoc_len; /*byte length of vtoc block*/
|
|
public ushort vtoc_pad; /* pad for 16-bit machine alignment */
|
|
public uint alt_ptr; /*byte offset of alternates table*/
|
|
public ushort alt_len; /*byte length of alternates table*/
|
|
/* new in version 3 */
|
|
public uint pcyls; /*physical cylinders per drive*/
|
|
public uint ptracks; /*physical tracks per cylinder*/
|
|
public uint psectors; /*physical sectors per track*/
|
|
public uint pbytes; /*physical bytes per sector*/
|
|
public uint secovhd; /*sector overhead bytes per sector*/
|
|
public ushort interleave; /*interleave factor*/
|
|
public ushort skew; /*skew factor*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
public uint[] pad; /*space for more stuff*/
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: PDInfoOld
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SwapEndian]
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
partial struct PDInfoOld
|
|
{
|
|
public uint driveid; /*identifies the device type*/
|
|
public uint sanity; /*verifies device sanity*/
|
|
public uint version; /*version number*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
|
|
public byte[] serial; /*serial number of the device*/
|
|
public uint cyls; /*number of cylinders per drive*/
|
|
public uint tracks; /*number tracks per cylinder*/
|
|
public uint sectors; /*number sectors per track*/
|
|
public uint bytes; /*number of bytes per sector*/
|
|
public uint logicalst; /*sector address of logical sector 0*/
|
|
public uint errlogst; /*sector address of error log area*/
|
|
public uint errlogsz; /*size in bytes of error log area*/
|
|
public uint mfgst; /*sector address of mfg. defect info*/
|
|
public uint mfgsz; /*size in bytes of mfg. defect info*/
|
|
public uint defectst; /*sector address of the defect map*/
|
|
public uint defectsz; /*size in bytes of defect map*/
|
|
public uint relno; /*number of relocation areas*/
|
|
public uint relst; /*sector address of relocation area*/
|
|
public uint relsz; /*size in sectors of relocation area*/
|
|
public uint relnext; /*address of next avail reloc sector*/
|
|
public uint allcstrt; /*start of the allocatable disk*/
|
|
public uint allcend; /*end of allocatable disk*/
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: pFlag
|
|
|
|
[Flags]
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
enum pFlag : ushort
|
|
{
|
|
/* Partition permission flags */
|
|
V_UNMNT = 0x01, /* Unmountable partition */
|
|
V_RONLY = 0x10, /* Read only */
|
|
V_REMAP = 0x20, /* do alternate sector mapping */
|
|
V_OPEN = 0x100, /* Partition open (for driver use) */
|
|
V_VALID = 0x200, /* Partition is valid to use */
|
|
V_VOMASK = 0x300 /* mask for open and valid */
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: pTag
|
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
enum pTag : ushort
|
|
{
|
|
/// <summary>empty</summary>
|
|
V_UNUSED = 0x0000,
|
|
/// <summary>boot</summary>
|
|
V_BOOT = 0x0001,
|
|
/// <summary>root</summary>
|
|
V_ROOT = 0x0002,
|
|
/// <summary>swap</summary>
|
|
V_SWAP = 0x0003,
|
|
/// <summary>/usr</summary>
|
|
V_USER = 0x0004,
|
|
/// <summary>whole disk</summary>
|
|
V_BACKUP = 0x0005,
|
|
/// <summary>stand partition ??</summary>
|
|
V_STAND_OLD = 0x0006,
|
|
/// <summary>alternate sector space</summary>
|
|
V_ALTS_OLD = 0x0006,
|
|
/// <summary>/var</summary>
|
|
V_VAR_OLD = 0x0007,
|
|
/// <summary>non UNIX</summary>
|
|
V_OTHER = 0x0007,
|
|
/// <summary>/home</summary>
|
|
V_HOME_OLD = 0x0008,
|
|
/// <summary>alternate track space</summary>
|
|
V_ALTS = 0x0008,
|
|
/// <summary>alternate sector track</summary>
|
|
V_ALTSCTR_OLD = 0x0009,
|
|
/// <summary>stand partition ??</summary>
|
|
V_STAND = 0x0009,
|
|
/// <summary>cache</summary>
|
|
V_CACHE = 0x000A,
|
|
/// <summary>/var</summary>
|
|
V_VAR = 0x000A,
|
|
/// <summary>reserved</summary>
|
|
V_RESERVED = 0x000B,
|
|
/// <summary>/home</summary>
|
|
V_HOME = 0x000B,
|
|
/// <summary>dump partition</summary>
|
|
V_DUMP = 0x000C,
|
|
/// <summary>alternate sector track</summary>
|
|
V_ALTSCTR = 0x000D,
|
|
/// <summary>volume mgt public partition</summary>
|
|
V_VMPUBLIC = 0x000E,
|
|
/// <summary>volume mgt private partition</summary>
|
|
V_VMPRIVATE = 0x000F
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: Vtoc
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SwapEndian]
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
partial struct Vtoc
|
|
{
|
|
public uint v_sanity; /*to verify vtoc sanity*/
|
|
public uint v_version; /*layout version*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
public byte[] v_volume; /*volume name*/
|
|
public ushort v_nparts; /*number of partitions*/
|
|
public ushort v_pad; /*pad for 286 compiler*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
|
public uint[] v_reserved; /*free space*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = V_NUMPAR)]
|
|
public VtocPartition[] v_part; /*partition headers*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = V_NUMPAR)]
|
|
public int[] timestamp; /* SCSI time stamp */
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: VTocOld
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SwapEndian]
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
partial struct VTocOld
|
|
{
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
public uint[] v_bootinfo; /*info needed by mboot*/
|
|
public uint v_sanity; /*to verify vtoc sanity*/
|
|
public uint v_version; /*layout version*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
public byte[] v_volume; /*volume name*/
|
|
public ushort v_sectorsz; /*sector size in bytes*/
|
|
public ushort v_nparts; /*number of partitions*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
|
public uint[] v_reserved; /*free space*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = V_NUMPAR)]
|
|
public VtocPartition[] v_part; /*partition headers*/
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = V_NUMPAR)]
|
|
public int[] timestamp; /* SCSI time stamp */
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested type: VtocPartition
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SwapEndian]
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
partial struct VtocPartition
|
|
{
|
|
public pTag p_tag; /*ID tag of partition*/
|
|
public pFlag p_flag; /*permision flags*/
|
|
public int p_start; /*start sector no of partition*/
|
|
public int p_size; /*# of blocks in partition*/
|
|
}
|
|
|
|
#endregion
|
|
} |