Files
WPinternals/DiscUtils/Ntfs/FixupRecordBase.cs
T
Gustave Monce a2a1c2302b Code cleanup
2019-12-22 12:25:48 +01:00

190 lines
6.6 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.IO;
internal abstract class FixupRecordBase
{
private int _sectorSize;
private string _magic;
private ushort _updateSequenceOffset;
private ushort _updateSequenceCount;
private ushort _updateSequenceNumber;
private ushort[] _updateSequenceArray;
public FixupRecordBase(string magic, int sectorSize)
{
_magic = magic;
_sectorSize = sectorSize;
}
public FixupRecordBase(string magic, int sectorSize, int recordLength)
{
Initialize(magic, sectorSize, recordLength);
}
public string Magic
{
get { return _magic; }
}
public ushort UpdateSequenceOffset
{
get { return _updateSequenceOffset; }
}
public ushort UpdateSequenceCount
{
get { return _updateSequenceCount; }
}
public ushort UpdateSequenceNumber
{
get { return _updateSequenceNumber; }
}
public int UpdateSequenceSize
{
get { return _updateSequenceCount * 2; }
}
public int Size
{
get
{
return CalcSize();
}
}
public void FromBytes(byte[] buffer, int offset)
{
FromBytes(buffer, offset, false);
}
public void FromBytes(byte[] buffer, int offset, bool ignoreMagic)
{
string diskMagic = Utilities.BytesToString(buffer, offset + 0x00, 4);
if (_magic == null)
{
_magic = diskMagic;
}
else
{
if (diskMagic != _magic && ignoreMagic)
{
return;
}
if (diskMagic != _magic)
{
throw new IOException("Corrupt record");
}
}
_updateSequenceOffset = Utilities.ToUInt16LittleEndian(buffer, offset + 0x04);
_updateSequenceCount = Utilities.ToUInt16LittleEndian(buffer, offset + 0x06);
_updateSequenceNumber = Utilities.ToUInt16LittleEndian(buffer, offset + _updateSequenceOffset);
_updateSequenceArray = new ushort[_updateSequenceCount - 1];
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
_updateSequenceArray[i] = Utilities.ToUInt16LittleEndian(buffer, offset + _updateSequenceOffset + (2 * (i + 1)));
}
UnprotectBuffer(buffer, offset);
Read(buffer, offset);
}
public void ToBytes(byte[] buffer, int offset)
{
_updateSequenceOffset = Write(buffer, offset);
ProtectBuffer(buffer, offset);
Utilities.StringToBytes(_magic, buffer, offset + 0x00, 4);
Utilities.WriteBytesLittleEndian(_updateSequenceOffset, buffer, offset + 0x04);
Utilities.WriteBytesLittleEndian(_updateSequenceCount, buffer, offset + 0x06);
Utilities.WriteBytesLittleEndian(_updateSequenceNumber, buffer, offset + _updateSequenceOffset);
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
Utilities.WriteBytesLittleEndian(_updateSequenceArray[i], buffer, offset + _updateSequenceOffset + (2 * (i + 1)));
}
}
protected void Initialize(string magic, int sectorSize, int recordLength)
{
_magic = magic;
_sectorSize = sectorSize;
_updateSequenceCount = (ushort)(1 + Utilities.Ceil(recordLength, Sizes.Sector));
_updateSequenceNumber = 1;
_updateSequenceArray = new ushort[_updateSequenceCount - 1];
}
protected abstract void Read(byte[] buffer, int offset);
protected abstract ushort Write(byte[] buffer, int offset);
protected abstract int CalcSize();
private void UnprotectBuffer(byte[] buffer, int offset)
{
// First do validation check - make sure the USN matches on all sectors)
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
if (_updateSequenceNumber != Utilities.ToUInt16LittleEndian(buffer, offset + (Sizes.Sector * (i + 1)) - 2))
{
throw new IOException("Corrupt file system record found");
}
}
// Now replace the USNs with the actual data from the sequence array
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
Utilities.WriteBytesLittleEndian(_updateSequenceArray[i], buffer, offset + (Sizes.Sector * (i + 1)) - 2);
}
}
private void ProtectBuffer(byte[] buffer, int offset)
{
_updateSequenceNumber++;
// Read in the bytes that are replaced by the USN
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
_updateSequenceArray[i] = Utilities.ToUInt16LittleEndian(buffer, offset + (Sizes.Sector * (i + 1)) - 2);
}
// Overwrite the bytes that are replaced with the USN
for (int i = 0; i < _updateSequenceArray.Length; ++i)
{
Utilities.WriteBytesLittleEndian(_updateSequenceNumber, buffer, offset + (Sizes.Sector * (i + 1)) - 2);
}
}
}
}