Initial commit - WPinternals 2.6

This commit is contained in:
Rene Lergner
2018-10-25 22:35:49 +02:00
commit 396ae57f05
483 changed files with 159677 additions and 0 deletions
@@ -0,0 +1,64 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal sealed class ComponentRecord : DatabaseRecord
{
public string StatusString;
public ExtentMergeType MergeType; // (02 Spanned, Simple, Mirrored) (01 on striped)
public uint Unknown1; // Zero
public ulong NumExtents; // Could be num disks
public uint Unknown2; // Zero
public uint LinkId; // Identical on mirrors
public ulong Unknown3; // 00 .. 00
public ulong VolumeId;
public ulong Unknown4; // ??
public long StripeSizeSectors;
public long StripeStride; // aka num partitions
protected override void DoReadFrom(byte[] buffer, int offset)
{
base.DoReadFrom(buffer, offset);
int pos = offset + 0x18;
Id = ReadVarULong(buffer, ref pos);
Name = ReadVarString(buffer, ref pos);
StatusString = ReadVarString(buffer, ref pos);
MergeType = (ExtentMergeType)ReadByte(buffer, ref pos);
Unknown1 = ReadUInt(buffer, ref pos); // Zero
NumExtents = ReadVarULong(buffer, ref pos);
Unknown2 = ReadUInt(buffer, ref pos);
LinkId = ReadUInt(buffer, ref pos);
Unknown3 = ReadULong(buffer, ref pos); // Zero
VolumeId = ReadVarULong(buffer, ref pos);
Unknown4 = ReadVarULong(buffer, ref pos); // Zero
if ((Flags & 0x1000) != 0)
{
StripeSizeSectors = ReadVarLong(buffer, ref pos);
StripeStride = ReadVarLong(buffer, ref pos);
}
}
}
}
+177
View File
@@ -0,0 +1,177 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
using System.Collections.Generic;
using System.IO;
internal class Database
{
private DatabaseHeader _vmdb;
private Dictionary<ulong, DatabaseRecord> _records;
public Database(Stream stream)
{
long dbStart = stream.Position;
byte[] buffer = new byte[Sizes.Sector];
stream.Read(buffer, 0, buffer.Length);
_vmdb = new DatabaseHeader();
_vmdb.ReadFrom(buffer, 0);
stream.Position = dbStart + _vmdb.HeaderSize;
buffer = Utilities.ReadFully(stream, (int)(_vmdb.BlockSize * _vmdb.NumVBlks));
_records = new Dictionary<ulong, DatabaseRecord>();
for (int i = 0; i < _vmdb.NumVBlks; ++i)
{
DatabaseRecord rec = DatabaseRecord.ReadFrom(buffer, (int)(i * _vmdb.BlockSize));
if (rec != null)
{
_records.Add(rec.Id, rec);
}
}
}
internal IEnumerable<DiskRecord> Disks
{
get
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.Disk)
{
yield return (DiskRecord)record;
}
}
}
}
internal IEnumerable<VolumeRecord> Volumes
{
get
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.Volume)
{
yield return (VolumeRecord)record;
}
}
}
}
internal DiskGroupRecord GetDiskGroup(Guid guid)
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.DiskGroup)
{
DiskGroupRecord dgRecord = (DiskGroupRecord)record;
if (new Guid(dgRecord.GroupGuidString) == guid || guid == Guid.Empty)
{
return dgRecord;
}
}
}
return null;
}
internal IEnumerable<ComponentRecord> GetVolumeComponents(ulong volumeId)
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.Component)
{
ComponentRecord cmpntRecord = (ComponentRecord)record;
if (cmpntRecord.VolumeId == volumeId)
{
yield return cmpntRecord;
}
}
}
}
internal IEnumerable<ExtentRecord> GetComponentExtents(ulong componentId)
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.Extent)
{
ExtentRecord extentRecord = (ExtentRecord)record;
if (extentRecord.ComponentId == componentId)
{
yield return extentRecord;
}
}
}
}
internal DiskRecord GetDisk(ulong diskId)
{
return (DiskRecord)_records[diskId];
}
internal VolumeRecord GetVolume(ulong volumeId)
{
return (VolumeRecord)_records[volumeId];
}
internal VolumeRecord GetVolume(Guid id)
{
return FindRecord<VolumeRecord>(r => (r.VolumeGuid == id), RecordType.Volume);
}
internal IEnumerable<VolumeRecord> GetVolumes()
{
foreach (var record in _records.Values)
{
if (record.RecordType == RecordType.Volume)
{
yield return (VolumeRecord)record;
}
}
}
internal T FindRecord<T>(Predicate<T> pred, RecordType typeId)
where T : DatabaseRecord
{
foreach (var record in _records.Values)
{
if (record.RecordType == typeId)
{
T t = (T)record;
if (pred(t))
{
return t;
}
}
}
return null;
}
}
}
@@ -0,0 +1,92 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
internal class DatabaseHeader
{
public string Signature; // VMDB
public uint NumVBlks; // 00 00 17 24
public uint BlockSize; // 00 00 00 80
public uint HeaderSize; // 00 00 02 00
public ushort Unknown1; // 00 01
public ushort VersionNum; // 00 04
public ushort VersionDenom; // 00 0a
public string GroupName;
public string DiskGroupId;
public long CommittedSequence; // 0xA
public long PendingSequence; // 0xA
public uint Unknown2; // 1
public uint Unknown3; // 1
public uint Unknown4; // 3
public uint Unknown5; // 3
public long Unknown6; // 0
public long Unknown7; // 1
public uint Unknown8; // 1
public uint Unknown9; // 3
public uint UnknownA; // 3
public long UnknownB; // 0
public uint UnknownC; // 0
public DateTime Timestamp;
public void ReadFrom(byte[] buffer, int offset)
{
Signature = Utilities.BytesToString(buffer, offset + 0x00, 4);
NumVBlks = Utilities.ToUInt32BigEndian(buffer, offset + 0x04);
BlockSize = Utilities.ToUInt32BigEndian(buffer, offset + 0x08);
HeaderSize = Utilities.ToUInt32BigEndian(buffer, offset + 0x0C);
Unknown1 = Utilities.ToUInt16BigEndian(buffer, offset + 0x10);
VersionNum = Utilities.ToUInt16BigEndian(buffer, offset + 0x12);
VersionDenom = Utilities.ToUInt16BigEndian(buffer, offset + 0x14);
GroupName = Utilities.BytesToString(buffer, offset + 0x16, 31).Trim('\0');
DiskGroupId = Utilities.BytesToString(buffer, offset + 0x35, 0x40).Trim('\0');
// May be wrong way round...
CommittedSequence = Utilities.ToInt64BigEndian(buffer, offset + 0x75);
PendingSequence = Utilities.ToInt64BigEndian(buffer, offset + 0x7D);
Unknown2 = Utilities.ToUInt32BigEndian(buffer, offset + 0x85);
Unknown3 = Utilities.ToUInt32BigEndian(buffer, offset + 0x89);
Unknown4 = Utilities.ToUInt32BigEndian(buffer, offset + 0x8D);
Unknown5 = Utilities.ToUInt32BigEndian(buffer, offset + 0x91);
Unknown6 = Utilities.ToInt64BigEndian(buffer, offset + 0x95);
Unknown7 = Utilities.ToInt64BigEndian(buffer, offset + 0x9D);
Unknown8 = Utilities.ToUInt32BigEndian(buffer, offset + 0xA5);
Unknown9 = Utilities.ToUInt32BigEndian(buffer, offset + 0xA9);
UnknownA = Utilities.ToUInt32BigEndian(buffer, offset + 0xAD);
UnknownB = Utilities.ToInt64BigEndian(buffer, offset + 0xB1);
UnknownC = Utilities.ToUInt32BigEndian(buffer, offset + 0xB9);
Timestamp = DateTime.FromFileTimeUtc(Utilities.ToInt64BigEndian(buffer, offset + 0xBD));
}
////private static int CalcChecksum()
////{
//// // Zero checksum bytes (0x08, 4)
//// // Add all byte values for ?? bytes
//// throw new NotImplementedException();
////}
}
}
@@ -0,0 +1,157 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
internal abstract class DatabaseRecord
{
public string Signature; // VBLK
public uint Label;
public uint Counter;
public uint Valid;
public uint Flags;
public RecordType RecordType;
public uint DataLength;
public ulong Id;
public string Name;
protected DatabaseRecord()
{
}
public static DatabaseRecord ReadFrom(byte[] buffer, int offset)
{
DatabaseRecord result = null;
if (Utilities.ToInt32BigEndian(buffer, offset + 0xC) != 0)
{
switch ((RecordType)(buffer[offset + 0x13] & 0xF))
{
case RecordType.Volume:
result = new VolumeRecord();
break;
case RecordType.Component:
result = new ComponentRecord();
break;
case RecordType.Extent:
result = new ExtentRecord();
break;
case RecordType.Disk:
result = new DiskRecord();
break;
case RecordType.DiskGroup:
result = new DiskGroupRecord();
break;
default:
throw new NotImplementedException("Unrecognized record type: " + buffer[offset + 0x13]);
}
result.DoReadFrom(buffer, offset);
}
return result;
}
protected static ulong ReadVarULong(byte[] buffer, ref int offset)
{
int length = buffer[offset];
ulong result = 0;
for (int i = 0; i < length; ++i)
{
result = (result << 8) | buffer[offset + i + 1];
}
offset += length + 1;
return result;
}
protected static long ReadVarLong(byte[] buffer, ref int offset)
{
return (long)ReadVarULong(buffer, ref offset);
}
protected static string ReadVarString(byte[] buffer, ref int offset)
{
int length = buffer[offset];
string result = Utilities.BytesToString(buffer, offset + 1, length);
offset += length + 1;
return result;
}
protected static byte ReadByte(byte[] buffer, ref int offset)
{
return buffer[offset++];
}
protected static uint ReadUInt(byte[] buffer, ref int offset)
{
offset += 4;
return Utilities.ToUInt32BigEndian(buffer, offset - 4);
}
protected static long ReadLong(byte[] buffer, ref int offset)
{
offset += 8;
return Utilities.ToInt64BigEndian(buffer, offset - 8);
}
protected static ulong ReadULong(byte[] buffer, ref int offset)
{
offset += 8;
return Utilities.ToUInt64BigEndian(buffer, offset - 8);
}
protected static string ReadString(byte[] buffer, int len, ref int offset)
{
offset += len;
return Utilities.BytesToString(buffer, offset - len, len);
}
protected static Guid ReadBinaryGuid(byte[] buffer, ref int offset)
{
offset += 16;
return Utilities.ToGuidBigEndian(buffer, offset - 16);
}
protected virtual void DoReadFrom(byte[] buffer, int offset)
{
Signature = Utilities.BytesToString(buffer, offset + 0x00, 4);
Label = Utilities.ToUInt32BigEndian(buffer, offset + 0x04);
Counter = Utilities.ToUInt32BigEndian(buffer, offset + 0x08);
Valid = Utilities.ToUInt32BigEndian(buffer, offset + 0x0C);
Flags = Utilities.ToUInt32BigEndian(buffer, offset + 0x10);
RecordType = (RecordType)(Flags & 0xF);
DataLength = Utilities.ToUInt32BigEndian(buffer, 0x14);
}
}
}
@@ -0,0 +1,49 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal sealed class DiskGroupRecord : DatabaseRecord
{
public string GroupGuidString;
public uint Unknown1;
protected override void DoReadFrom(byte[] buffer, int offset)
{
base.DoReadFrom(buffer, offset);
int pos = offset + 0x18;
Id = ReadVarULong(buffer, ref pos);
Name = ReadVarString(buffer, ref pos);
if ((Flags & 0xF0) == 0x40)
{
GroupGuidString = ReadBinaryGuid(buffer, ref pos).ToString();
}
else
{
GroupGuidString = ReadVarString(buffer, ref pos);
}
Unknown1 = ReadUInt(buffer, ref pos);
}
}
}
@@ -0,0 +1,47 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal sealed class DiskRecord : DatabaseRecord
{
public string DiskGuidString;
protected override void DoReadFrom(byte[] buffer, int offset)
{
base.DoReadFrom(buffer, offset);
int pos = offset + 0x18;
Id = ReadVarULong(buffer, ref pos);
Name = ReadVarString(buffer, ref pos);
if ((Flags & 0xF0) == 0x40)
{
DiskGuidString = ReadBinaryGuid(buffer, ref pos).ToString();
}
else
{
DiskGuidString = ReadVarString(buffer, ref pos);
}
}
}
}
+146
View File
@@ -0,0 +1,146 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
using System.IO;
using DiscUtils.Partitions;
internal class DynamicDisk : IDiagnosticTraceable
{
private VirtualDisk _disk;
private PrivateHeader _header;
private Database _database;
internal DynamicDisk(VirtualDisk disk)
{
_disk = disk;
_header = GetPrivateHeader(_disk);
TocBlock toc = GetTableOfContents();
long dbStart = (_header.ConfigurationStartLba * 512) + (toc.Item1Start * 512);
_disk.Content.Position = dbStart;
_database = new Database(_disk.Content);
}
public SparseStream Content
{
get { return _disk.Content; }
}
public long DataOffset
{
get { return _header.DataStartLba; }
}
public Guid Id
{
get { return new Guid(_header.DiskId); }
}
public Guid GroupId
{
get { return string.IsNullOrEmpty(_header.DiskGroupId) ? Guid.Empty : new Guid(_header.DiskGroupId); }
}
public Database Database
{
get { return _database; }
}
public void Dump(TextWriter writer, string linePrefix)
{
writer.WriteLine(linePrefix + "DISK (" + _header.DiskId + ")");
writer.WriteLine(linePrefix + " Metadata Version: " + ((_header.Version >> 16) & 0xFFFF) + "." + (_header.Version & 0xFFFF));
writer.WriteLine(linePrefix + " Timestamp: " + _header.Timestamp);
writer.WriteLine(linePrefix + " Disk Id: " + _header.DiskId);
writer.WriteLine(linePrefix + " Host Id: " + _header.HostId);
writer.WriteLine(linePrefix + " Disk Group Id: " + _header.DiskGroupId);
writer.WriteLine(linePrefix + " Disk Group Name: " + _header.DiskGroupName);
writer.WriteLine(linePrefix + " Data Start: " + _header.DataStartLba + " (Sectors)");
writer.WriteLine(linePrefix + " Data Size: " + _header.DataSizeLba + " (Sectors)");
writer.WriteLine(linePrefix + " Configuration Start: " + _header.ConfigurationStartLba + " (Sectors)");
writer.WriteLine(linePrefix + " Configuration Size: " + _header.ConfigurationSizeLba + " (Sectors)");
writer.WriteLine(linePrefix + " TOC Size: " + _header.TocSizeLba + " (Sectors)");
writer.WriteLine(linePrefix + " Next TOC: " + _header.NextTocLba + " (Sectors)");
writer.WriteLine(linePrefix + " Number of Configs: " + _header.NumberOfConfigs);
writer.WriteLine(linePrefix + " Config Size: " + _header.ConfigurationSizeLba + " (Sectors)");
writer.WriteLine(linePrefix + " Number of Logs: " + _header.NumberOfLogs);
writer.WriteLine(linePrefix + " Log Size: " + _header.LogSizeLba + " (Sectors)");
}
internal static PrivateHeader GetPrivateHeader(VirtualDisk disk)
{
if (disk.IsPartitioned)
{
long headerPos = 0;
PartitionTable pt = disk.Partitions;
if (pt is BiosPartitionTable)
{
headerPos = 0xc00;
}
else
{
foreach (var part in pt.Partitions)
{
if (part.GuidType == GuidPartitionTypes.WindowsLdmMetadata)
{
headerPos = part.LastSector * Sizes.Sector;
}
}
}
if (headerPos != 0)
{
disk.Content.Position = headerPos;
byte[] buffer = new byte[Sizes.Sector];
disk.Content.Read(buffer, 0, buffer.Length);
PrivateHeader hdr = new PrivateHeader();
hdr.ReadFrom(buffer, 0);
return hdr;
}
}
return null;
}
private TocBlock GetTableOfContents()
{
byte[] buffer = new byte[_header.TocSizeLba * 512];
_disk.Content.Position = (_header.ConfigurationStartLba * 512) + (1 * _header.TocSizeLba * 512);
_disk.Content.Read(buffer, 0, buffer.Length);
TocBlock tocBlock = new TocBlock();
tocBlock.ReadFrom(buffer, 0);
if (tocBlock.Signature == "TOCBLOCK")
{
return tocBlock;
}
return null;
}
}
}
@@ -0,0 +1,319 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using DiscUtils.Partitions;
internal class DynamicDiskGroup : IDiagnosticTraceable
{
private DiskGroupRecord _record;
private Dictionary<Guid, DynamicDisk> _disks;
private Database _database;
internal DynamicDiskGroup(VirtualDisk disk)
{
_disks = new Dictionary<Guid, DynamicDisk>();
DynamicDisk dynDisk = new DynamicDisk(disk);
_database = dynDisk.Database;
_disks.Add(dynDisk.Id, dynDisk);
_record = dynDisk.Database.GetDiskGroup(dynDisk.GroupId);
}
public void Add(VirtualDisk disk)
{
DynamicDisk dynDisk = new DynamicDisk(disk);
_disks.Add(dynDisk.Id, dynDisk);
}
#region IDiagnosticTraceable Members
public void Dump(TextWriter writer, string linePrefix)
{
writer.WriteLine(linePrefix + "DISK GROUP (" + _record.Name + ")");
writer.WriteLine(linePrefix + " Name: " + _record.Name);
writer.WriteLine(linePrefix + " Flags: 0x" + (_record.Flags & 0xFFF0).ToString("X4", CultureInfo.InvariantCulture));
writer.WriteLine(linePrefix + " Database Id: " + _record.Id);
writer.WriteLine(linePrefix + " Guid: " + _record.GroupGuidString);
writer.WriteLine();
writer.WriteLine(linePrefix + " DISKS");
foreach (var disk in _database.Disks)
{
writer.WriteLine(linePrefix + " DISK (" + disk.Name + ")");
writer.WriteLine(linePrefix + " Name: " + disk.Name);
writer.WriteLine(linePrefix + " Flags: 0x" + (disk.Flags & 0xFFF0).ToString("X4", CultureInfo.InvariantCulture));
writer.WriteLine(linePrefix + " Database Id: " + disk.Id);
writer.WriteLine(linePrefix + " Guid: " + disk.DiskGuidString);
DynamicDisk dynDisk;
if (_disks.TryGetValue(new Guid(disk.DiskGuidString), out dynDisk))
{
writer.WriteLine(linePrefix + " PRIVATE HEADER");
dynDisk.Dump(writer, linePrefix + " ");
}
}
writer.WriteLine(linePrefix + " VOLUMES");
foreach (var vol in _database.Volumes)
{
writer.WriteLine(linePrefix + " VOLUME (" + vol.Name + ")");
writer.WriteLine(linePrefix + " Name: " + vol.Name);
writer.WriteLine(linePrefix + " BIOS Type: " + vol.BiosType.ToString("X2", CultureInfo.InvariantCulture) + " [" + BiosPartitionTypes.ToString(vol.BiosType) + "]");
writer.WriteLine(linePrefix + " Flags: 0x" + (vol.Flags & 0xFFF0).ToString("X4", CultureInfo.InvariantCulture));
writer.WriteLine(linePrefix + " Database Id: " + vol.Id);
writer.WriteLine(linePrefix + " Guid: " + vol.VolumeGuid);
writer.WriteLine(linePrefix + " State: " + vol.ActiveString);
writer.WriteLine(linePrefix + " Drive Hint: " + vol.MountHint);
writer.WriteLine(linePrefix + " Num Components: " + vol.ComponentCount);
writer.WriteLine(linePrefix + " Link Id: " + vol.PartitionComponentLink);
writer.WriteLine(linePrefix + " COMPONENTS");
foreach (var cmpnt in _database.GetVolumeComponents(vol.Id))
{
writer.WriteLine(linePrefix + " COMPONENT (" + cmpnt.Name + ")");
writer.WriteLine(linePrefix + " Name: " + cmpnt.Name);
writer.WriteLine(linePrefix + " Flags: 0x" + (cmpnt.Flags & 0xFFF0).ToString("X4", CultureInfo.InvariantCulture));
writer.WriteLine(linePrefix + " Database Id: " + cmpnt.Id);
writer.WriteLine(linePrefix + " State: " + cmpnt.StatusString);
writer.WriteLine(linePrefix + " Mode: " + cmpnt.MergeType);
writer.WriteLine(linePrefix + " Num Extents: " + cmpnt.NumExtents);
writer.WriteLine(linePrefix + " Link Id: " + cmpnt.LinkId);
writer.WriteLine(linePrefix + " Stripe Size: " + cmpnt.StripeSizeSectors + " (Sectors)");
writer.WriteLine(linePrefix + " Stripe Stride: " + cmpnt.StripeStride);
writer.WriteLine(linePrefix + " EXTENTS");
foreach (var extent in _database.GetComponentExtents(cmpnt.Id))
{
writer.WriteLine(linePrefix + " EXTENT (" + extent.Name + ")");
writer.WriteLine(linePrefix + " Name: " + extent.Name);
writer.WriteLine(linePrefix + " Flags: 0x" + (extent.Flags & 0xFFF0).ToString("X4", CultureInfo.InvariantCulture));
writer.WriteLine(linePrefix + " Database Id: " + extent.Id);
writer.WriteLine(linePrefix + " Disk Offset: " + extent.DiskOffsetLba + " (Sectors)");
writer.WriteLine(linePrefix + " Volume Offset: " + extent.OffsetInVolumeLba + " (Sectors)");
writer.WriteLine(linePrefix + " Size: " + extent.SizeLba + " (Sectors)");
writer.WriteLine(linePrefix + " Component Id: " + extent.ComponentId);
writer.WriteLine(linePrefix + " Disk Id: " + extent.DiskId);
writer.WriteLine(linePrefix + " Link Id: " + extent.PartitionComponentLink);
writer.WriteLine(linePrefix + " Interleave Order: " + extent.InterleaveOrder);
}
}
}
}
#endregion
internal DynamicVolume[] GetVolumes()
{
List<DynamicVolume> vols = new List<DynamicVolume>();
foreach (var record in _database.GetVolumes())
{
vols.Add(new DynamicVolume(this, record.VolumeGuid));
}
return vols.ToArray();
}
internal VolumeRecord GetVolume(Guid volume)
{
return _database.GetVolume(volume);
}
internal LogicalVolumeStatus GetVolumeStatus(ulong volumeId)
{
return GetVolumeStatus(_database.GetVolume(volumeId));
}
internal SparseStream OpenVolume(ulong volumeId)
{
return OpenVolume(_database.GetVolume(volumeId));
}
private static int CompareExtentOffsets(ExtentRecord x, ExtentRecord y)
{
if (x.OffsetInVolumeLba > y.OffsetInVolumeLba)
{
return 1;
}
else if (x.OffsetInVolumeLba < y.OffsetInVolumeLba)
{
return -1;
}
return 0;
}
private static int CompareExtentInterleaveOrder(ExtentRecord x, ExtentRecord y)
{
if (x.InterleaveOrder > y.InterleaveOrder)
{
return 1;
}
else if (x.InterleaveOrder < y.InterleaveOrder)
{
return -1;
}
return 0;
}
private static LogicalVolumeStatus WorstOf(LogicalVolumeStatus x, LogicalVolumeStatus y)
{
return (LogicalVolumeStatus)Math.Max((int)x, (int)y);
}
private LogicalVolumeStatus GetVolumeStatus(VolumeRecord volume)
{
int numFailed = 0;
ulong numOK = 0;
LogicalVolumeStatus worst = LogicalVolumeStatus.Healthy;
foreach (var cmpnt in _database.GetVolumeComponents(volume.Id))
{
LogicalVolumeStatus cmpntStatus = GetComponentStatus(cmpnt);
worst = WorstOf(worst, cmpntStatus);
if (cmpntStatus == LogicalVolumeStatus.Failed)
{
numFailed++;
}
else
{
numOK++;
}
}
if (numOK < 1)
{
return LogicalVolumeStatus.Failed;
}
else if (numOK == volume.ComponentCount)
{
return worst;
}
else
{
return LogicalVolumeStatus.FailedRedundancy;
}
}
private LogicalVolumeStatus GetComponentStatus(ComponentRecord cmpnt)
{
// NOTE: no support for RAID, so either valid or failed...
LogicalVolumeStatus status = LogicalVolumeStatus.Healthy;
foreach (var extent in _database.GetComponentExtents(cmpnt.Id))
{
DiskRecord disk = _database.GetDisk(extent.DiskId);
if (!_disks.ContainsKey(new Guid(disk.DiskGuidString)))
{
status = LogicalVolumeStatus.Failed;
break;
}
}
return status;
}
private SparseStream OpenExtent(ExtentRecord extent)
{
DiskRecord disk = _database.GetDisk(extent.DiskId);
DynamicDisk diskObj = _disks[new Guid(disk.DiskGuidString)];
return new SubStream(diskObj.Content, Ownership.None, (diskObj.DataOffset + extent.DiskOffsetLba) * Sizes.Sector, extent.SizeLba * Sizes.Sector);
}
private SparseStream OpenComponent(ComponentRecord component)
{
if (component.MergeType == ExtentMergeType.Concatenated)
{
List<ExtentRecord> extents = new List<ExtentRecord>(_database.GetComponentExtents(component.Id));
extents.Sort(CompareExtentOffsets);
// Sanity Check...
long pos = 0;
foreach (var extent in extents)
{
if (extent.OffsetInVolumeLba != pos)
{
throw new IOException("Volume extents are non-contiguous");
}
pos += extent.SizeLba;
}
List<SparseStream> streams = new List<SparseStream>();
foreach (var extent in extents)
{
streams.Add(OpenExtent(extent));
}
return new ConcatStream(Ownership.Dispose, streams.ToArray());
}
else if (component.MergeType == ExtentMergeType.Interleaved)
{
List<ExtentRecord> extents = new List<ExtentRecord>(_database.GetComponentExtents(component.Id));
extents.Sort(CompareExtentInterleaveOrder);
List<SparseStream> streams = new List<SparseStream>();
foreach (var extent in extents)
{
streams.Add(OpenExtent(extent));
}
return new StripedStream(component.StripeSizeSectors * Sizes.Sector, Ownership.Dispose, streams.ToArray());
}
else
{
throw new NotImplementedException("Unknown component mode: " + component.MergeType);
}
}
private SparseStream OpenVolume(VolumeRecord volume)
{
List<SparseStream> cmpntStreams = new List<SparseStream>();
foreach (var component in _database.GetVolumeComponents(volume.Id))
{
if (GetComponentStatus(component) == LogicalVolumeStatus.Healthy)
{
cmpntStreams.Add(OpenComponent(component));
}
}
if (cmpntStreams.Count < 1)
{
throw new IOException("Volume with no associated or healthy components");
}
else if (cmpntStreams.Count == 1)
{
return cmpntStreams[0];
}
else
{
return new MirrorStream(Ownership.Dispose, cmpntStreams.ToArray());
}
}
}
}
@@ -0,0 +1,153 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System.Collections.Generic;
using System.IO;
using DiscUtils.Partitions;
/// <summary>
/// A class that understands Windows LDM structures, mapping physical volumes to logical volumes.
/// </summary>
public class DynamicDiskManager : IDiagnosticTraceable
{
private Dictionary<string, DynamicDiskGroup> _groups;
/// <summary>
/// Initializes a new instance of the DynamicDiskManager class.
/// </summary>
/// <param name="disks">The initial set of disks to manage.</param>
public DynamicDiskManager(params VirtualDisk[] disks)
{
_groups = new Dictionary<string, DynamicDiskGroup>();
foreach (var disk in disks)
{
Add(disk);
}
}
/// <summary>
/// Determines if a physical volume contains LDM data.
/// </summary>
/// <param name="volumeInfo">The volume to inspect.</param>
/// <returns><c>true</c> if the physical volume contains LDM data, else <c>false</c>.</returns>
public static bool HandlesPhysicalVolume(PhysicalVolumeInfo volumeInfo)
{
PartitionInfo pi = volumeInfo.Partition;
if (pi != null)
{
return IsLdmPartition(pi);
}
return false;
}
/// <summary>
/// Determines if a disk is 'dynamic' (i.e. contains LDM volumes).
/// </summary>
/// <param name="disk">The disk to inspect.</param>
/// <returns><c>true</c> if the disk contains LDM volumes, else <c>false</c>.</returns>
public static bool IsDynamicDisk(VirtualDisk disk)
{
if (disk.IsPartitioned)
{
foreach (var partition in disk.Partitions.Partitions)
{
if (IsLdmPartition(partition))
{
return true;
}
}
}
return false;
}
/// <summary>
/// Adds a new disk to be managed.
/// </summary>
/// <param name="disk">The disk to manage.</param>
public void Add(VirtualDisk disk)
{
PrivateHeader header = DynamicDisk.GetPrivateHeader(disk);
DynamicDiskGroup group;
if (_groups.TryGetValue(header.DiskGroupId, out group))
{
group.Add(disk);
}
else
{
group = new DynamicDiskGroup(disk);
_groups.Add(header.DiskGroupId, group);
}
}
/// <summary>
/// Gets the logical volumes held across the set of managed disks.
/// </summary>
/// <returns>An array of logical volumes.</returns>
public LogicalVolumeInfo[] GetLogicalVolumes()
{
List<LogicalVolumeInfo> result = new List<LogicalVolumeInfo>();
foreach (var group in _groups.Values)
{
foreach (var volume in group.GetVolumes())
{
LogicalVolumeInfo lvi = new LogicalVolumeInfo(
volume.Identity,
null,
volume.Open,
volume.Length,
volume.BiosType,
volume.Status);
result.Add(lvi);
}
}
return result.ToArray();
}
/// <summary>
/// Writes a diagnostic report about the state of the disk manager.
/// </summary>
/// <param name="writer">The writer to send the report to.</param>
/// <param name="linePrefix">The prefix to place at the start of each line.</param>
public void Dump(TextWriter writer, string linePrefix)
{
writer.WriteLine(linePrefix + "DISK GROUPS");
foreach (var group in _groups.Values)
{
group.Dump(writer, linePrefix + " ");
}
}
private static bool IsLdmPartition(PartitionInfo partition)
{
return partition.BiosType == BiosPartitionTypes.WindowsDynamicVolume
|| partition.GuidType == GuidPartitionTypes.WindowsLdmMetadata
|| partition.GuidType == GuidPartitionTypes.WindowsLdmData;
}
}
}
@@ -0,0 +1,53 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System.Collections.Generic;
[LogicalVolumeFactory]
internal class DynamicDiskManagerFactory : LogicalVolumeFactory
{
public override bool HandlesPhysicalVolume(PhysicalVolumeInfo volume)
{
return DynamicDiskManager.HandlesPhysicalVolume(volume);
}
public override void MapDisks(IEnumerable<VirtualDisk> disks, Dictionary<string, LogicalVolumeInfo> result)
{
DynamicDiskManager mgr = new DynamicDiskManager();
foreach (var disk in disks)
{
if (DynamicDiskManager.IsDynamicDisk(disk))
{
mgr.Add(disk);
}
}
foreach (var vol in mgr.GetLogicalVolumes())
{
result.Add(vol.Identity, vol);
}
}
}
}
@@ -0,0 +1,76 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
using System.IO;
internal class DynamicVolume
{
private DynamicDiskGroup _group;
private Guid _volumeId;
internal DynamicVolume(DynamicDiskGroup group, Guid volumeId)
{
_group = group;
_volumeId = volumeId;
}
public byte BiosType
{
get { return Record.BiosType; }
}
public Guid Identity
{
get { return _volumeId; }
}
public long Length
{
get { return Record.Size * Sizes.Sector; }
}
public LogicalVolumeStatus Status
{
get { return _group.GetVolumeStatus(Record.Id); }
}
private VolumeRecord Record
{
get { return _group.GetVolume(_volumeId); }
}
public SparseStream Open()
{
if (Status == LogicalVolumeStatus.Failed)
{
throw new IOException("Attempt to open 'failed' volume");
}
else
{
return _group.OpenVolume(Record.Id);
}
}
}
}
@@ -0,0 +1,31 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal enum ExtentMergeType : byte
{
None = 0,
Interleaved = 1,
Concatenated = 2
}
}
@@ -0,0 +1,60 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal sealed class ExtentRecord : DatabaseRecord
{
public uint Unknown1;
public uint Unknown2;
public uint PartitionComponentLink;
public long DiskOffsetLba;
public long OffsetInVolumeLba;
public long SizeLba;
public ulong ComponentId;
public ulong DiskId;
public ulong InterleaveOrder;
protected override void DoReadFrom(byte[] buffer, int offset)
{
base.DoReadFrom(buffer, offset);
int pos = offset + 0x18;
Id = ReadVarULong(buffer, ref pos);
Name = ReadVarString(buffer, ref pos);
Unknown1 = ReadUInt(buffer, ref pos);
Unknown2 = ReadUInt(buffer, ref pos);
PartitionComponentLink = ReadUInt(buffer, ref pos);
DiskOffsetLba = ReadLong(buffer, ref pos);
OffsetInVolumeLba = ReadLong(buffer, ref pos);
SizeLba = ReadVarLong(buffer, ref pos);
ComponentId = ReadVarULong(buffer, ref pos);
DiskId = ReadVarULong(buffer, ref pos);
if ((Flags & 0x0800) != 0)
{
InterleaveOrder = ReadVarULong(buffer, ref pos);
}
}
}
}
@@ -0,0 +1,88 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
internal class PrivateHeader
{
public string Signature; // PRIVHEAD
public uint Checksum; // 00 00 2f 96
public uint Version; // 2.12
public DateTime Timestamp;
public long Unknown2; // Active TOC? 00 .. 00 01
public long Unknown3; // 00 .. 07 ff // 1 sector less than 2MB
public long Unknown4; // 00 .. 07 40
public string DiskId; // GUID string
public string HostId; // GUID string
public string DiskGroupId; // GUID string
public string DiskGroupName; // MAX_COMPUTER_NAME_LENGTH?
public uint Unknown5; // Sector Size?
public long DataStartLba; // 3F
public long DataSizeLba; // 03 FF F7 C1
public long ConfigurationStartLba; // 03 FF F8 00
public long ConfigurationSizeLba; // 08 00
public long TocSizeLba;
public long NextTocLba;
public long NumberOfConfigs;
public long ConfigSizeLba;
public long NumberOfLogs;
public long LogSizeLba;
public void ReadFrom(byte[] buffer, int offset)
{
Signature = Utilities.BytesToString(buffer, offset + 0x00, 8);
Checksum = Utilities.ToUInt32BigEndian(buffer, offset + 0x08);
Version = Utilities.ToUInt32BigEndian(buffer, offset + 0x0C);
Timestamp = DateTime.FromFileTimeUtc(Utilities.ToInt64BigEndian(buffer, offset + 0x10));
Unknown2 = Utilities.ToInt64BigEndian(buffer, offset + 0x18);
Unknown3 = Utilities.ToInt64BigEndian(buffer, offset + 0x20);
Unknown4 = Utilities.ToInt64BigEndian(buffer, offset + 0x28);
DiskId = Utilities.BytesToString(buffer, offset + 0x30, 0x40).Trim('\0');
HostId = Utilities.BytesToString(buffer, offset + 0x70, 0x40).Trim('\0');
DiskGroupId = Utilities.BytesToString(buffer, offset + 0xB0, 0x40).Trim('\0');
DiskGroupName = Utilities.BytesToString(buffer, offset + 0xF0, 31).Trim('\0');
Unknown5 = Utilities.ToUInt32BigEndian(buffer, offset + 0x10F);
DataStartLba = Utilities.ToInt64BigEndian(buffer, offset + 0x11B);
DataSizeLba = Utilities.ToInt64BigEndian(buffer, offset + 0x123);
ConfigurationStartLba = Utilities.ToInt64BigEndian(buffer, offset + 0x12B);
ConfigurationSizeLba = Utilities.ToInt64BigEndian(buffer, offset + 0x133);
TocSizeLba = Utilities.ToInt64BigEndian(buffer, offset + 0x13B);
NextTocLba = Utilities.ToInt64BigEndian(buffer, offset + 0x143);
// These two may be reversed
NumberOfConfigs = Utilities.ToInt32BigEndian(buffer, offset + 0x14B);
NumberOfLogs = Utilities.ToInt32BigEndian(buffer, offset + 0x14F);
ConfigSizeLba = Utilities.ToInt64BigEndian(buffer, offset + 0x153);
LogSizeLba = Utilities.ToInt64BigEndian(buffer, offset + 0x15B);
}
////private static int CalcChecksum()
////{
//// // Zero checksum bytes (0x08, 4)
//// // Add all byte values for 512 bytes
//// throw new NotImplementedException();
////}
}
}
@@ -0,0 +1,34 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
internal enum RecordType : byte
{
None = 0,
Volume = 1,
Component = 2,
Extent = 3,
Disk = 4,
DiskGroup = 5
}
}
+71
View File
@@ -0,0 +1,71 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
internal class TocBlock
{
public string Signature; // TOCBLOCK
public uint Checksum; // 00 00 08 B6
public long SequenceNumber; // 00 .. 01
public long Unknown1; // 0
public long Unknown2; // 00
public string Item1Str; // 'config', length 10
public long Item1Start; // Sector Offset from ConfigurationStart
public long Item1Size; // Unit?
public uint Unknown3; // 00 06 00 01 (may be two values?)
public uint Unknown4; // 00 00 00 00
public string Item2Str; // 'log', length 10
public long Item2Start; // Sector Offset from ConfigurationStart
public long Item2Size; // Unit?
public uint Unknown5; // 00 06 00 01 (may be two values?)
public uint Unknown6; // 00 00 00 00
public void ReadFrom(byte[] buffer, int offset)
{
Signature = Utilities.BytesToString(buffer, offset + 0x00, 8);
Checksum = Utilities.ToUInt32BigEndian(buffer, offset + 0x08);
SequenceNumber = Utilities.ToInt64BigEndian(buffer, offset + 0x0C);
Unknown1 = Utilities.ToInt64BigEndian(buffer, offset + 0x14);
Unknown2 = Utilities.ToInt64BigEndian(buffer, offset + 0x1C);
Item1Str = Utilities.BytesToString(buffer, offset + 0x24, 10).Trim('\0');
Item1Start = Utilities.ToInt64BigEndian(buffer, offset + 0x2E);
Item1Size = Utilities.ToInt64BigEndian(buffer, offset + 0x36);
Unknown3 = Utilities.ToUInt32BigEndian(buffer, offset + 0x3E);
Unknown4 = Utilities.ToUInt32BigEndian(buffer, offset + 0x42);
Item2Str = Utilities.BytesToString(buffer, offset + 0x46, 10).Trim('\0');
Item2Start = Utilities.ToInt64BigEndian(buffer, offset + 0x50);
Item2Size = Utilities.ToInt64BigEndian(buffer, offset + 0x58);
Unknown5 = Utilities.ToUInt32BigEndian(buffer, offset + 0x60);
Unknown6 = Utilities.ToUInt32BigEndian(buffer, offset + 0x64);
}
////private static int CalcChecksum()
////{
//// // Zero checksum bytes (0x08, 4)
//// // Add all byte values for ?? bytes
//// throw new NotImplementedException();
////}
}
}
@@ -0,0 +1,77 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.LogicalDiskManager
{
using System;
internal sealed class VolumeRecord : DatabaseRecord
{
public string GenString;
public string NumberString; // 8000000000000000 sometimes...
public string ActiveString;
public ulong UnknownA; // Zero
public ulong UnknownB; // 00 .. 03
public ulong DupCount; // ??Seen once after adding 'foreign disk', from broken mirror (identical links(P/V/C))
public uint UnknownC; // 00 00 00 11
public ulong ComponentCount;
public uint UnknownD; // Zero
public uint PartitionComponentLink;
public ulong Unknown1; // Zero
public long Size;
public uint Unknown2; // Zero
public byte BiosType;
public Guid VolumeGuid;
public string MountHint;
protected override void DoReadFrom(byte[] buffer, int offset)
{
base.DoReadFrom(buffer, offset);
int pos = offset + 0x18;
Id = ReadVarULong(buffer, ref pos);
Name = ReadVarString(buffer, ref pos);
GenString = ReadVarString(buffer, ref pos);
NumberString = ReadVarString(buffer, ref pos);
ActiveString = ReadString(buffer, 6, ref pos);
UnknownA = ReadVarULong(buffer, ref pos);
UnknownB = ReadULong(buffer, ref pos);
DupCount = ReadVarULong(buffer, ref pos);
UnknownC = ReadUInt(buffer, ref pos);
ComponentCount = ReadVarULong(buffer, ref pos);
UnknownD = ReadUInt(buffer, ref pos);
PartitionComponentLink = ReadUInt(buffer, ref pos);
Unknown1 = ReadULong(buffer, ref pos);
Size = ReadVarLong(buffer, ref pos);
Unknown2 = ReadUInt(buffer, ref pos);
BiosType = ReadByte(buffer, ref pos);
VolumeGuid = Utilities.ToGuidBigEndian(buffer, pos);
pos += 16;
if ((Flags & 0x0200) != 0)
{
MountHint = ReadVarString(buffer, ref pos);
}
}
}
}