Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Library/DiscUtils.Ntfs/NtfsFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,13 @@ public override long GetFileLength(string path)
var dirEntry = GetDirectoryEntry(dirEntryPath)
?? throw new FileNotFoundException("File not found", path);

// Ordinary file length request, use info from the directory entry for efficiency - if allowed.
if (NtfsOptions.FileLengthFromDirectoryEntries && attributeName == null &&
attributeType == AttributeType.Data)
{
return (long)dirEntry.Details.RealSize;
}

var file = GetFile(dirEntry.Reference);
var attr = file.GetAttribute(attributeType, attributeName)
?? throw new FileNotFoundException($"No such attribute '{attributeName}({attributeType})'");
Expand Down
2 changes: 1 addition & 1 deletion Library/DiscUtils.Registry/Bin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ internal bool WriteRawCellData(int cellIndex, ReadOnlySpan<byte> data)

internal int AllocateCell(int size)
{
if (size < 8 || (size % 0x7) != 0)
if (size < 8 || (size & 0x7) != 0)
{
throw new ArgumentException("Invalid cell size");
}
Expand Down
65 changes: 23 additions & 42 deletions Library/DiscUtils.Registry/SubKeyIndirectListCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,33 +160,22 @@ internal override IEnumerable<KeyNodeCell> EnumerateKeys()

internal override int LinkSubKey(string name, int cellIndex)
{
// Look for the first sublist that has a subkey name greater than name
if (ListType == "ri")
// As in UnlinkSubKey, a list's entries can be a mix of sublists ("ri") and key nodes ("li"), so dispatch
// on the actual cell type rather than on ListType (avoids a KeyNodeCell -> ListCell InvalidCastException).
// Look for the first sublist/key node whose name is greater than the new name.
for (var i = 0; i < CellIndexes.Count; ++i)
{
if (CellIndexes.Count == 0)
{
throw new NotImplementedException("Empty indirect list");
}

for (var i = 0; i < CellIndexes.Count - 1; ++i)
var cell = _hive.GetCell<Cell>(CellIndexes[i]);
if (cell is ListCell listCell)
{
var cell = _hive.GetCell<ListCell>(CellIndexes[i]);
if (cell.FindKey(name, out var tempIndex) <= 0)
// Descend into the last sublist, or the first whose range can already hold the new name.
if (i == CellIndexes.Count - 1 || listCell.FindKey(name, out _) <= 0)
{
CellIndexes[i] = cell.LinkSubKey(name, cellIndex);
CellIndexes[i] = listCell.LinkSubKey(name, cellIndex);
return _hive.UpdateCell(this, false);
}
}

var lastCell = _hive.GetCell<ListCell>(CellIndexes[CellIndexes.Count - 1]);
CellIndexes[CellIndexes.Count - 1] = lastCell.LinkSubKey(name, cellIndex);
return _hive.UpdateCell(this, false);
}

for (var i = 0; i < CellIndexes.Count; ++i)
{
var cell = _hive.GetCell<KeyNodeCell>(CellIndexes[i]);
if (string.Compare(name, cell.Name, StringComparison.OrdinalIgnoreCase) < 0)
else if (string.Compare(name, ((KeyNodeCell)cell).Name, StringComparison.OrdinalIgnoreCase) < 0)
{
CellIndexes.Insert(i, cellIndex);
return _hive.UpdateCell(this, true);
Expand All @@ -199,20 +188,19 @@ internal override int LinkSubKey(string name, int cellIndex)

internal override int UnlinkSubKey(string name)
{
if (ListType == "ri")
// A "ri" list references sublists and a "li" list references key nodes, but in practice the entries of a
// single list can be a mix of both (the read paths - Count/EnumerateKeyNames/EnumerateKeys/DoFindKey -
// already tolerate this). Dispatch on the actual cell type instead of on ListType, otherwise deleting a
// key whose containing list has a mismatched entry throws InvalidCastException (KeyNodeCell -> ListCell).
for (var i = 0; i < CellIndexes.Count; ++i)
{
if (CellIndexes.Count == 0)
{
throw new NotImplementedException("Empty indirect list");
}

for (var i = 0; i < CellIndexes.Count; ++i)
var cell = _hive.GetCell<Cell>(CellIndexes[i]);
if (cell is ListCell listCell)
{
var cell = _hive.GetCell<ListCell>(CellIndexes[i]);
if (cell.FindKey(name, out var tempIndex) <= 0)
if (listCell.FindKey(name, out _) <= 0)
{
CellIndexes[i] = cell.UnlinkSubKey(name);
if (cell.Count == 0)
CellIndexes[i] = listCell.UnlinkSubKey(name);
if (listCell.Count == 0)
{
_hive.FreeCell(CellIndexes[i]);
CellIndexes.RemoveAt(i);
Expand All @@ -221,17 +209,10 @@ internal override int UnlinkSubKey(string name)
return _hive.UpdateCell(this, false);
}
}
}
else
{
for (var i = 0; i < CellIndexes.Count; ++i)
else if (string.Equals(name, ((KeyNodeCell)cell).Name, StringComparison.OrdinalIgnoreCase))
{
var cell = _hive.GetCell<KeyNodeCell>(CellIndexes[i]);
if (string.Equals(name, cell.Name, StringComparison.OrdinalIgnoreCase))
{
CellIndexes.RemoveAt(i);
return _hive.UpdateCell(this, true);
}
CellIndexes.RemoveAt(i);
return _hive.UpdateCell(this, true);
}
}

Expand Down
6 changes: 5 additions & 1 deletion Library/DiscUtils.Streams/SparseStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,11 @@ private sealed class SynchronizedSparseStream(SparseStream content, Ownership ow

public override long Length => content.Length;

public override long Position { get; set; }
public override long Position
{
get { lock (sync) { return content.Position; } }
set { lock (sync) { content.Position = value; } }
}

public override void Flush()
{
Expand Down
36 changes: 18 additions & 18 deletions Library/DiscUtils.Vhd/DynamicStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public override IEnumerable<StreamExtent> MapContent(long start, long length)

if (offsetInSector != 0 || toRead < Sizes.Sector)
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((blockBitmap[sectorInBlock / 8] & mask) != 0)
{
var extentStart = (_blockAllocationTable[block] + sectorInBlock) *
Expand All @@ -190,7 +190,7 @@ public override IEnumerable<StreamExtent> MapContent(long start, long length)
// Processing at least one whole sector, read as many as possible
var toReadSectors = toRead / Sizes.Sector;

var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
var readFromParent = (blockBitmap[sectorInBlock / 8] & mask) == 0;

var numSectors = 1;
Expand Down Expand Up @@ -274,7 +274,7 @@ public override int Read(byte[] buffer, int offset, int count)

if (offsetInSector != 0 || toRead < Sizes.Sector)
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));

if ((blockBitmap[sectorInBlock / 8] & mask) != 0)
{
Expand All @@ -296,7 +296,7 @@ public override int Read(byte[] buffer, int offset, int count)
// Processing at least one whole sector, read as many as possible
var toReadSectors = toRead / Sizes.Sector;

var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
var readFromParent = (blockBitmap[sectorInBlock / 8] & mask) == 0;

var numSectors = 1;
Expand Down Expand Up @@ -377,7 +377,7 @@ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, Cancellation

if (offsetInSector != 0 || toRead < Sizes.Sector)
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((blockBitmap[sectorInBlock / 8] & mask) != 0)
{
_fileStream.Position = (_blockAllocationTable[block] + sectorInBlock) *
Expand All @@ -398,7 +398,7 @@ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, Cancellation
// Processing at least one whole sector, read as many as possible
var toReadSectors = toRead / Sizes.Sector;

var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
var readFromParent = (blockBitmap[sectorInBlock / 8] & mask) == 0;

var numSectors = 1;
Expand Down Expand Up @@ -479,7 +479,7 @@ public override int Read(Span<byte> buffer)

if (offsetInSector != 0 || toRead < Sizes.Sector)
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((blockBitmap[sectorInBlock / 8] & mask) != 0)
{
_fileStream.Position = (_blockAllocationTable[block] + sectorInBlock) *
Expand All @@ -500,7 +500,7 @@ public override int Read(Span<byte> buffer)
// Processing at least one whole sector, read as many as possible
var toReadSectors = toRead / Sizes.Sector;

var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
var readFromParent = (blockBitmap[sectorInBlock / 8] & mask) == 0;

var numSectors = 1;
Expand Down Expand Up @@ -621,7 +621,7 @@ public override void Write(byte[] buffer, int offset, int count)
// Reduce the write to just the end of the current sector
toWrite = Math.Min(count - numWritten, Sizes.Sector - offsetInSector);

var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));

var sectorStart = (_blockAllocationTable[block] + sectorInBlock) * Sizes.Sector +
_blockBitmapSize;
Expand Down Expand Up @@ -665,7 +665,7 @@ public override void Write(byte[] buffer, int offset, int count)
// Update all of the bits in the block bitmap
for (var i = offset; i < offset + toWrite; i += Sizes.Sector)
{
var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((_blockBitmaps[block][sectorInBlock / 8] & sectorMask) == 0)
{
_blockBitmaps[block][sectorInBlock / 8] |= sectorMask;
Expand Down Expand Up @@ -726,7 +726,7 @@ public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, Cancella
// Reduce the write to just the end of the current sector
toWrite = Math.Min(buffer.Length - numWritten, Sizes.Sector - offsetInSector);

var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));

var sectorStart = (_blockAllocationTable[block] + sectorInBlock) * Sizes.Sector +
_blockBitmapSize;
Expand Down Expand Up @@ -778,7 +778,7 @@ public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, Cancella
// Update all of the bits in the block bitmap
for (var i = 0; i < toWrite; i += Sizes.Sector)
{
var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((_blockBitmaps[block][sectorInBlock / 8] & sectorMask) == 0)
{
_blockBitmaps[block][sectorInBlock / 8] |= sectorMask;
Expand Down Expand Up @@ -841,7 +841,7 @@ public override void Write(ReadOnlySpan<byte> buffer)
// Reduce the write to just the end of the current sector
toWrite = Math.Min(buffer.Length - numWritten, Sizes.Sector - offsetInSector);

var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));

var sectorStart = (_blockAllocationTable[block] + sectorInBlock) * Sizes.Sector +
_blockBitmapSize;
Expand Down Expand Up @@ -885,7 +885,7 @@ public override void Write(ReadOnlySpan<byte> buffer)
// Update all of the bits in the block bitmap
for (var i = 0; i < toWrite; i += Sizes.Sector)
{
var sectorMask = (byte)(1 << (7 - sectorInBlock & 0x7));
var sectorMask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((_blockBitmaps[block][sectorInBlock / 8] & sectorMask) == 0)
{
_blockBitmaps[block][sectorInBlock / 8] |= sectorMask;
Expand Down Expand Up @@ -977,11 +977,11 @@ private long FindNextPresentSector(long pos, long maxPos)

if (_blockBitmaps[block][sectorInBlock / 8] == 0)
{
pos += (8 - sectorInBlock & 0x7) * Sizes.Sector;
pos += (8 - (sectorInBlock & 0x7)) * Sizes.Sector;
}
else
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((_blockBitmaps[block][sectorInBlock / 8] & mask) != 0)
{
foundStart = true;
Expand Down Expand Up @@ -1015,11 +1015,11 @@ private long FindNextAbsentSector(long pos, long maxPos)

if (_blockBitmaps[block][sectorInBlock / 8] == 0xFF)
{
pos += (8 - sectorInBlock & 0x7) * Sizes.Sector;
pos += (8 - (sectorInBlock & 0x7)) * Sizes.Sector;
}
else
{
var mask = (byte)(1 << (7 - sectorInBlock & 0x7));
var mask = (byte)(1 << (7 - (sectorInBlock & 0x7)));
if ((_blockBitmaps[block][sectorInBlock / 8] & mask) == 0)
{
foundEnd = true;
Expand Down
Loading