mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-19 22:00:12 +10:00
Initial commit - WPinternals 2.6
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user