Files
WPinternals/DiscUtils/Ntfs/IndexEntry.cs
T
2018-10-25 22:35:49 +02:00

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);
}
}
}
}