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

298 lines
9.4 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;
using System.Collections.Generic;
using System.IO;
internal sealed class IndexRoot : IByteArraySerializable, IDiagnosticTraceable
{
public const int HeaderOffset = 0x10;
private uint _attrType;
private AttributeCollationRule _collationRule;
private uint _indexAllocationEntrySize;
private byte _rawClustersPerIndexRecord;
public uint AttributeType
{
get { return _attrType; }
set { _attrType = value; }
}
public AttributeCollationRule CollationRule
{
get { return _collationRule; }
set { _collationRule = value; }
}
public uint IndexAllocationSize
{
get { return _indexAllocationEntrySize; }
set { _indexAllocationEntrySize = value; }
}
public byte RawClustersPerIndexRecord
{
get { return _rawClustersPerIndexRecord; }
set { _rawClustersPerIndexRecord = value; }
}
public int Size
{
get { return 16; }
}
public IComparer<byte[]> GetCollator(UpperCase upCase)
{
switch (_collationRule)
{
case AttributeCollationRule.Filename:
return new FileNameComparer(upCase);
case AttributeCollationRule.SecurityHash:
return new SecurityHashComparer();
case AttributeCollationRule.UnsignedLong:
return new UnsignedLongComparer();
case AttributeCollationRule.MultipleUnsignedLongs:
return new MultipleUnsignedLongComparer();
case AttributeCollationRule.Sid:
return new SidComparer();
default:
throw new NotImplementedException();
}
}
public int ReadFrom(byte[] buffer, int offset)
{
_attrType = Utilities.ToUInt32LittleEndian(buffer, 0x00);
_collationRule = (AttributeCollationRule)Utilities.ToUInt32LittleEndian(buffer, 0x04);
_indexAllocationEntrySize = Utilities.ToUInt32LittleEndian(buffer, 0x08);
_rawClustersPerIndexRecord = buffer[0x0C];
return 16;
}
public void WriteTo(byte[] buffer, int offset)
{
Utilities.WriteBytesLittleEndian(_attrType, buffer, 0);
Utilities.WriteBytesLittleEndian((uint)_collationRule, buffer, 0x04);
Utilities.WriteBytesLittleEndian(_indexAllocationEntrySize, buffer, 0x08);
Utilities.WriteBytesLittleEndian(_rawClustersPerIndexRecord, buffer, 0x0C);
}
public void Dump(TextWriter writer, string indent)
{
writer.WriteLine(indent + " Attr Type: " + _attrType);
writer.WriteLine(indent + " Collation Rule: " + _collationRule);
writer.WriteLine(indent + " Index Alloc Size: " + _indexAllocationEntrySize);
writer.WriteLine(indent + " Raw Clusters Per Record: " + _rawClustersPerIndexRecord);
}
private sealed class SecurityHashComparer : IComparer<byte[]>
{
public int Compare(byte[] x, byte[] y)
{
if (x == null && y == null)
{
return 0;
}
else if (y == null)
{
return -1;
}
else if (x == null)
{
return 1;
}
uint xHash = Utilities.ToUInt32LittleEndian(x, 0);
uint yHash = Utilities.ToUInt32LittleEndian(y, 0);
if (xHash < yHash)
{
return -1;
}
else if (xHash > yHash)
{
return 1;
}
uint xId = Utilities.ToUInt32LittleEndian(x, 4);
uint yId = Utilities.ToUInt32LittleEndian(y, 4);
if (xId < yId)
{
return -1;
}
else if (xId > yId)
{
return 1;
}
else
{
return 0;
}
}
}
private sealed class UnsignedLongComparer : IComparer<byte[]>
{
public int Compare(byte[] x, byte[] y)
{
if (x == null && y == null)
{
return 0;
}
else if (y == null)
{
return -1;
}
else if (x == null)
{
return 1;
}
uint xVal = Utilities.ToUInt32LittleEndian(x, 0);
uint yVal = Utilities.ToUInt32LittleEndian(y, 0);
if (xVal < yVal)
{
return -1;
}
else if (xVal > yVal)
{
return 1;
}
return 0;
}
}
private sealed class MultipleUnsignedLongComparer : IComparer<byte[]>
{
public int Compare(byte[] x, byte[] y)
{
for (int i = 0; i < x.Length / 4; ++i)
{
if (x == null && y == null)
{
return 0;
}
else if (y == null)
{
return -1;
}
else if (x == null)
{
return 1;
}
uint xVal = Utilities.ToUInt32LittleEndian(x, i * 4);
uint yVal = Utilities.ToUInt32LittleEndian(y, i * 4);
if (xVal < yVal)
{
return -1;
}
else if (xVal > yVal)
{
return 1;
}
}
return 0;
}
}
private sealed class FileNameComparer : IComparer<byte[]>
{
private UpperCase _stringComparer;
public FileNameComparer(UpperCase upCase)
{
_stringComparer = upCase;
}
public int Compare(byte[] x, byte[] y)
{
if (x == null && y == null)
{
return 0;
}
else if (y == null)
{
return -1;
}
else if (x == null)
{
return 1;
}
byte xFnLen = x[0x40];
byte yFnLen = y[0x40];
return _stringComparer.Compare(x, 0x42, xFnLen * 2, y, 0x42, yFnLen * 2);
}
}
private sealed class SidComparer : IComparer<byte[]>
{
public int Compare(byte[] x, byte[] y)
{
if (x == null && y == null)
{
return 0;
}
else if (y == null)
{
return -1;
}
else if (x == null)
{
return 1;
}
int toComp = Math.Min(x.Length, y.Length);
for (int i = 0; i < toComp; ++i)
{
int val = ((int)x[i]) - ((int)y[i]);
if (val != 0)
{
return val;
}
}
if (x.Length < y.Length)
{
return -1;
}
else if (x.Length > y.Length)
{
return 1;
}
return 0;
}
}
}
}