mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
194 lines
6.7 KiB
C#
194 lines
6.7 KiB
C#
//
|
|
// 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.Ntfs
|
|
{
|
|
using System;
|
|
|
|
[Flags]
|
|
internal enum IndexEntryFlags : ushort
|
|
{
|
|
None = 0x00,
|
|
Node = 0x01,
|
|
End = 0x02
|
|
}
|
|
|
|
internal class IndexEntry
|
|
{
|
|
public const int EndNodeSize = 0x18;
|
|
|
|
protected IndexEntryFlags _flags;
|
|
protected long _vcn; // Only valid if Node flag set
|
|
|
|
protected byte[] _keyBuffer;
|
|
protected byte[] _dataBuffer;
|
|
|
|
private bool _isFileIndexEntry;
|
|
|
|
public IndexEntry(bool isFileIndexEntry)
|
|
{
|
|
_isFileIndexEntry = isFileIndexEntry;
|
|
}
|
|
|
|
public IndexEntry(IndexEntry toCopy, byte[] newKey, byte[] newData)
|
|
{
|
|
_isFileIndexEntry = toCopy._isFileIndexEntry;
|
|
_flags = toCopy._flags;
|
|
_vcn = toCopy._vcn;
|
|
_keyBuffer = newKey;
|
|
_dataBuffer = newData;
|
|
}
|
|
|
|
public IndexEntry(byte[] key, byte[] data, bool isFileIndexEntry)
|
|
{
|
|
_isFileIndexEntry = isFileIndexEntry;
|
|
_flags = IndexEntryFlags.None;
|
|
_keyBuffer = key;
|
|
_dataBuffer = data;
|
|
}
|
|
|
|
public byte[] KeyBuffer
|
|
{
|
|
get { return _keyBuffer; }
|
|
set { _keyBuffer = value; }
|
|
}
|
|
|
|
public byte[] DataBuffer
|
|
{
|
|
get { return _dataBuffer; }
|
|
set { _dataBuffer = value; }
|
|
}
|
|
|
|
public IndexEntryFlags Flags
|
|
{
|
|
get { return _flags; }
|
|
set { _flags = value; }
|
|
}
|
|
|
|
public long ChildrenVirtualCluster
|
|
{
|
|
get { return _vcn; }
|
|
set { _vcn = value; }
|
|
}
|
|
|
|
public virtual int Size
|
|
{
|
|
get
|
|
{
|
|
int size = 0x10; // start of variable data
|
|
|
|
if ((_flags & IndexEntryFlags.End) == 0)
|
|
{
|
|
size += _keyBuffer.Length;
|
|
size += IsFileIndexEntry ? 0 : _dataBuffer.Length;
|
|
}
|
|
|
|
size = Utilities.RoundUp(size, 8);
|
|
|
|
if ((_flags & IndexEntryFlags.Node) != 0)
|
|
{
|
|
size += 8;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
}
|
|
|
|
protected bool IsFileIndexEntry
|
|
{
|
|
get { return _isFileIndexEntry; }
|
|
}
|
|
|
|
public virtual void Read(byte[] buffer, int offset)
|
|
{
|
|
ushort dataOffset = Utilities.ToUInt16LittleEndian(buffer, offset + 0x00);
|
|
ushort dataLength = Utilities.ToUInt16LittleEndian(buffer, offset + 0x02);
|
|
ushort length = Utilities.ToUInt16LittleEndian(buffer, offset + 0x08);
|
|
ushort keyLength = Utilities.ToUInt16LittleEndian(buffer, offset + 0x0A);
|
|
_flags = (IndexEntryFlags)Utilities.ToUInt16LittleEndian(buffer, offset + 0x0C);
|
|
|
|
if ((_flags & IndexEntryFlags.End) == 0)
|
|
{
|
|
_keyBuffer = new byte[keyLength];
|
|
Array.Copy(buffer, offset + 0x10, _keyBuffer, 0, keyLength);
|
|
|
|
if (IsFileIndexEntry)
|
|
{
|
|
// Special case, for file indexes, the MFT ref is held where the data offset & length go
|
|
_dataBuffer = new byte[8];
|
|
Array.Copy(buffer, offset + 0x00, _dataBuffer, 0, 8);
|
|
}
|
|
else
|
|
{
|
|
_dataBuffer = new byte[dataLength];
|
|
Array.Copy(buffer, offset + 0x10 + keyLength, _dataBuffer, 0, dataLength);
|
|
}
|
|
}
|
|
|
|
if ((_flags & IndexEntryFlags.Node) != 0)
|
|
{
|
|
_vcn = Utilities.ToInt64LittleEndian(buffer, offset + length - 8);
|
|
}
|
|
}
|
|
|
|
public virtual void WriteTo(byte[] buffer, int offset)
|
|
{
|
|
ushort length = (ushort)Size;
|
|
|
|
if ((_flags & IndexEntryFlags.End) == 0)
|
|
{
|
|
ushort keyLength = (ushort)_keyBuffer.Length;
|
|
|
|
if (IsFileIndexEntry)
|
|
{
|
|
Array.Copy(_dataBuffer, 0, buffer, offset + 0x00, 8);
|
|
}
|
|
else
|
|
{
|
|
ushort dataOffset = (ushort)(IsFileIndexEntry ? 0 : (0x10 + keyLength));
|
|
ushort dataLength = (ushort)_dataBuffer.Length;
|
|
|
|
Utilities.WriteBytesLittleEndian(dataOffset, buffer, offset + 0x00);
|
|
Utilities.WriteBytesLittleEndian(dataLength, buffer, offset + 0x02);
|
|
Array.Copy(_dataBuffer, 0, buffer, offset + dataOffset, _dataBuffer.Length);
|
|
}
|
|
|
|
Utilities.WriteBytesLittleEndian(keyLength, buffer, offset + 0x0A);
|
|
Array.Copy(_keyBuffer, 0, buffer, offset + 0x10, _keyBuffer.Length);
|
|
}
|
|
else
|
|
{
|
|
Utilities.WriteBytesLittleEndian((ushort)0, buffer, offset + 0x00); // dataOffset
|
|
Utilities.WriteBytesLittleEndian((ushort)0, buffer, offset + 0x02); // dataLength
|
|
Utilities.WriteBytesLittleEndian((ushort)0, buffer, offset + 0x0A); // keyLength
|
|
}
|
|
|
|
Utilities.WriteBytesLittleEndian(length, buffer, offset + 0x08);
|
|
Utilities.WriteBytesLittleEndian((ushort)_flags, buffer, offset + 0x0C);
|
|
if ((_flags & IndexEntryFlags.Node) != 0)
|
|
{
|
|
Utilities.WriteBytesLittleEndian(_vcn, buffer, offset + length - 8);
|
|
}
|
|
}
|
|
}
|
|
}
|