mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Rent arrays in BucketTree.Visitor
This commit is contained in:
parent
33b414a15c
commit
83dc874df1
3 changed files with 158 additions and 140 deletions
|
@ -36,47 +36,51 @@ namespace LibHac.FsSystem
|
|||
|
||||
var visitor = new BucketTree.Visitor();
|
||||
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
long inPos = offset;
|
||||
int outPos = 0;
|
||||
int remaining = destination.Length;
|
||||
|
||||
while (remaining > 0)
|
||||
try
|
||||
{
|
||||
var currentEntry = visitor.Get<Entry>();
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Get and validate the next entry offset
|
||||
long nextEntryOffset;
|
||||
if (visitor.CanMoveNext())
|
||||
long inPos = offset;
|
||||
int outPos = 0;
|
||||
int remaining = destination.Length;
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
var currentEntry = visitor.Get<Entry>();
|
||||
|
||||
nextEntryOffset = visitor.Get<Entry>().Offset;
|
||||
if (!Table.Includes(nextEntryOffset))
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
// Get and validate the next entry offset
|
||||
long nextEntryOffset;
|
||||
if (visitor.CanMoveNext())
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
nextEntryOffset = visitor.Get<Entry>().Offset;
|
||||
if (!Table.Includes(nextEntryOffset))
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEntryOffset = Table.GetEnd();
|
||||
}
|
||||
|
||||
int bytesToRead = (int)Math.Min(nextEntryOffset - inPos, remaining);
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
UpdateCounterSubsection((uint)currentEntry.Generation);
|
||||
|
||||
rc = base.DoRead(inPos, destination.Slice(outPos, bytesToRead));
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
outPos += bytesToRead;
|
||||
inPos += bytesToRead;
|
||||
remaining -= bytesToRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEntryOffset = Table.GetEnd();
|
||||
}
|
||||
|
||||
int bytesToRead = (int)Math.Min(nextEntryOffset - inPos, remaining);
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
UpdateCounterSubsection((uint)currentEntry.Generation);
|
||||
|
||||
rc = base.DoRead(inPos, destination.Slice(outPos, bytesToRead));
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
outPos += bytesToRead;
|
||||
inPos += bytesToRead;
|
||||
remaining -= bytesToRead;
|
||||
}
|
||||
finally { visitor.Dispose(); }
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -384,7 +385,7 @@ namespace LibHac.FsSystem
|
|||
|
||||
if (Entry == null)
|
||||
{
|
||||
Entry = new byte[tree.EntrySize];
|
||||
Entry = ArrayPool<byte>.Shared.Rent((int)tree.EntrySize);
|
||||
Tree = tree;
|
||||
EntryIndex = -1;
|
||||
}
|
||||
|
@ -394,7 +395,11 @@ namespace LibHac.FsSystem
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
// todo: try using shared arrays
|
||||
if (Entry != null)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(Entry);
|
||||
Entry = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid() => EntryIndex >= 0;
|
||||
|
|
|
@ -101,48 +101,53 @@ namespace LibHac.FsSystem
|
|||
|
||||
// Find the offset in our tree
|
||||
var visitor = new BucketTree.Visitor();
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
long entryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (entryOffset > 0 || !Table.Includes(entryOffset))
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Prepare to loop over entries
|
||||
long endOffset = offset + size;
|
||||
int count = 0;
|
||||
|
||||
ref Entry currentEntry = ref visitor.Get<Entry>();
|
||||
while (currentEntry.GetVirtualOffset() < endOffset)
|
||||
try
|
||||
{
|
||||
// Try to write the entry to the out list
|
||||
if (entryBuffer.Length != 0)
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
long entryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (entryOffset > 0 || !Table.Includes(entryOffset))
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Prepare to loop over entries
|
||||
long endOffset = offset + size;
|
||||
int count = 0;
|
||||
|
||||
ref Entry currentEntry = ref visitor.Get<Entry>();
|
||||
while (currentEntry.GetVirtualOffset() < endOffset)
|
||||
{
|
||||
if (count >= entryBuffer.Length)
|
||||
// Try to write the entry to the out list
|
||||
if (entryBuffer.Length != 0)
|
||||
{
|
||||
if (count >= entryBuffer.Length)
|
||||
break;
|
||||
|
||||
entryBuffer[count] = currentEntry;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
// Advance
|
||||
if (visitor.CanMoveNext())
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentEntry = ref visitor.Get<Entry>();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
|
||||
entryBuffer[count] = currentEntry;
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
// Advance
|
||||
if (visitor.CanMoveNext())
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentEntry = ref visitor.Get<Entry>();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Write the entry count
|
||||
outputEntryCount = count;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
// Write the entry count
|
||||
outputEntryCount = count;
|
||||
return Result.Success;
|
||||
finally { visitor.Dispose(); }
|
||||
}
|
||||
|
||||
protected override unsafe Result DoRead(long offset, Span<byte> destination)
|
||||
|
@ -216,84 +221,88 @@ namespace LibHac.FsSystem
|
|||
// Find the offset in our tree
|
||||
var visitor = new BucketTree.Visitor();
|
||||
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
long entryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (entryOffset < 0 || !Table.Includes(entryOffset))
|
||||
return ResultFs.InvalidIndirectEntryStorageIndex.Log();
|
||||
|
||||
// Prepare to operate in chunks
|
||||
long currentOffset = offset;
|
||||
long endOffset = offset + size;
|
||||
|
||||
while (currentOffset < endOffset)
|
||||
try
|
||||
{
|
||||
// Get the current entry
|
||||
var currentEntry = visitor.Get<Entry>();
|
||||
Result rc = Table.Find(ref visitor, offset);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Get and validate the entry's offset
|
||||
long currentEntryOffset = currentEntry.GetVirtualOffset();
|
||||
if (currentEntryOffset > currentOffset)
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Validate the storage index
|
||||
if (currentEntry.StorageIndex < 0 || currentEntry.StorageIndex >= StorageCount)
|
||||
long entryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (entryOffset < 0 || !Table.Includes(entryOffset))
|
||||
return ResultFs.InvalidIndirectEntryStorageIndex.Log();
|
||||
|
||||
// todo: Implement continuous reading
|
||||
// Prepare to operate in chunks
|
||||
long currentOffset = offset;
|
||||
long endOffset = offset + size;
|
||||
|
||||
// Get and validate the next entry offset
|
||||
long nextEntryOffset;
|
||||
if (visitor.CanMoveNext())
|
||||
while (currentOffset < endOffset)
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
// Get the current entry
|
||||
var currentEntry = visitor.Get<Entry>();
|
||||
|
||||
nextEntryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (!Table.Includes(nextEntryOffset))
|
||||
// Get and validate the entry's offset
|
||||
long currentEntryOffset = currentEntry.GetVirtualOffset();
|
||||
if (currentEntryOffset > currentOffset)
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Validate the storage index
|
||||
if (currentEntry.StorageIndex < 0 || currentEntry.StorageIndex >= StorageCount)
|
||||
return ResultFs.InvalidIndirectEntryStorageIndex.Log();
|
||||
|
||||
// todo: Implement continuous reading
|
||||
|
||||
// Get and validate the next entry offset
|
||||
long nextEntryOffset;
|
||||
if (visitor.CanMoveNext())
|
||||
{
|
||||
rc = visitor.MoveNext();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
nextEntryOffset = visitor.Get<Entry>().GetVirtualOffset();
|
||||
if (!Table.Includes(nextEntryOffset))
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEntryOffset = Table.GetEnd();
|
||||
}
|
||||
|
||||
if (currentOffset >= nextEntryOffset)
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Get the offset of the entry in the data we read
|
||||
long dataOffset = currentOffset - currentEntryOffset;
|
||||
long dataSize = nextEntryOffset - currentEntryOffset - dataOffset;
|
||||
Assert.AssertTrue(dataSize > 0);
|
||||
|
||||
// Determine how much is left
|
||||
long remainingSize = endOffset - currentOffset;
|
||||
long currentSize = Math.Min(remainingSize, dataSize);
|
||||
Assert.AssertTrue(currentSize <= size);
|
||||
|
||||
{
|
||||
SubStorage2 currentStorage = DataStorage[currentEntry.StorageIndex];
|
||||
|
||||
// Get the current data storage's size.
|
||||
rc = currentStorage.GetSize(out long currentDataStorageSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Ensure that we remain within range.
|
||||
long currentEntryPhysicalOffset = currentEntry.GetPhysicalOffset();
|
||||
|
||||
if (currentEntryPhysicalOffset < 0 || currentEntryPhysicalOffset > currentDataStorageSize)
|
||||
return ResultFs.IndirectStorageCorrupted.Log();
|
||||
|
||||
if (currentDataStorageSize < currentEntryPhysicalOffset + dataOffset + currentSize)
|
||||
return ResultFs.IndirectStorageCorrupted.Log();
|
||||
|
||||
rc = func(currentStorage, currentEntryPhysicalOffset + dataOffset, currentOffset, currentSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
currentOffset += currentSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEntryOffset = Table.GetEnd();
|
||||
}
|
||||
|
||||
if (currentOffset >= nextEntryOffset)
|
||||
return ResultFs.InvalidIndirectEntryOffset.Log();
|
||||
|
||||
// Get the offset of the entry in the data we read
|
||||
long dataOffset = currentOffset - currentEntryOffset;
|
||||
long dataSize = nextEntryOffset - currentEntryOffset - dataOffset;
|
||||
Assert.AssertTrue(dataSize > 0);
|
||||
|
||||
// Determine how much is left
|
||||
long remainingSize = endOffset - currentOffset;
|
||||
long currentSize = Math.Min(remainingSize, dataSize);
|
||||
Assert.AssertTrue(currentSize <= size);
|
||||
|
||||
{
|
||||
SubStorage2 currentStorage = DataStorage[currentEntry.StorageIndex];
|
||||
|
||||
// Get the current data storage's size.
|
||||
rc = currentStorage.GetSize(out long currentDataStorageSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Ensure that we remain within range.
|
||||
long currentEntryPhysicalOffset = currentEntry.GetPhysicalOffset();
|
||||
|
||||
if (currentEntryPhysicalOffset < 0 || currentEntryPhysicalOffset > currentDataStorageSize)
|
||||
return ResultFs.IndirectStorageCorrupted.Log();
|
||||
|
||||
if (currentDataStorageSize < currentEntryPhysicalOffset + dataOffset + currentSize)
|
||||
return ResultFs.IndirectStorageCorrupted.Log();
|
||||
|
||||
rc = func(currentStorage, currentEntryPhysicalOffset + dataOffset, currentOffset, currentSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
currentOffset += currentSize;
|
||||
}
|
||||
finally { visitor.Dispose(); }
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue