mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Move IStorage classes to the new StorageBase
This commit is contained in:
parent
bfc343e801
commit
162fb4e389
25 changed files with 324 additions and 195 deletions
|
@ -21,7 +21,7 @@ namespace LibHac.Fs
|
||||||
FsClient = Handle.File.Parent.FsClient;
|
FsClient = Handle.File.Parent.FsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ namespace LibHac.Fs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
|
@ -51,19 +51,19 @@ namespace LibHac.Fs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result FlushImpl()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return FsClient.FlushFile(Handle);
|
return FsClient.FlushFile(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSizeImpl(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
FileSize = InvalidSize;
|
FileSize = InvalidSize;
|
||||||
|
|
||||||
return FsClient.SetFileSize(Handle, size);
|
return FsClient.SetFileSize(Handle, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSizeImpl(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = default;
|
size = default;
|
||||||
|
|
||||||
|
|
|
@ -105,10 +105,10 @@
|
||||||
|
|
||||||
public static Result UnsupportedOperation => new Result(ModuleFs, 6300);
|
public static Result UnsupportedOperation => new Result(ModuleFs, 6300);
|
||||||
public static Result SubStorageNotResizable => new Result(ModuleFs, 6302);
|
public static Result SubStorageNotResizable => new Result(ModuleFs, 6302);
|
||||||
public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6302);
|
public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303);
|
||||||
public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6316);
|
public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6304);
|
||||||
public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6304);
|
|
||||||
public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310);
|
public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310);
|
||||||
|
public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6316);
|
||||||
public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324);
|
public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324);
|
||||||
public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325);
|
public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325);
|
||||||
public static Result UnsupportedOperationInRoGameCardStorageWrite => new Result(ModuleFs, 6350);
|
public static Result UnsupportedOperationInRoGameCardStorageWrite => new Result(ModuleFs, 6350);
|
||||||
|
|
|
@ -9,11 +9,11 @@ namespace LibHac.Fs
|
||||||
private int _disposedState;
|
private int _disposedState;
|
||||||
private bool IsDisposed => _disposedState != 0;
|
private bool IsDisposed => _disposedState != 0;
|
||||||
|
|
||||||
public abstract Result ReadImpl(long offset, Span<byte> destination);
|
protected abstract Result ReadImpl(long offset, Span<byte> destination);
|
||||||
public abstract Result WriteImpl(long offset, ReadOnlySpan<byte> source);
|
protected abstract Result WriteImpl(long offset, ReadOnlySpan<byte> source);
|
||||||
public abstract Result FlushImpl();
|
protected abstract Result FlushImpl();
|
||||||
public abstract Result GetSizeImpl(out long size);
|
protected abstract Result GetSizeImpl(out long size);
|
||||||
public abstract Result SetSizeImpl(long size);
|
protected abstract Result SetSizeImpl(long size);
|
||||||
|
|
||||||
public Result Read(long offset, Span<byte> destination)
|
public Result Read(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace LibHac.Fs
|
||||||
Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
||||||
if (destination.Length == 0) return Result.Success;
|
if (destination.Length == 0) return Result.Success;
|
||||||
|
@ -33,7 +33,7 @@ namespace LibHac.Fs
|
||||||
return BaseStorage.Read(Offset + offset, destination);
|
return BaseStorage.Read(Offset + offset, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
||||||
{
|
{
|
||||||
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
||||||
if (source.Length == 0) return Result.Success;
|
if (source.Length == 0) return Result.Success;
|
||||||
|
@ -43,14 +43,14 @@ namespace LibHac.Fs
|
||||||
return BaseStorage.Write(Offset + offset, source);
|
return BaseStorage.Write(Offset + offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result FlushImpl()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
||||||
|
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSizeImpl(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
||||||
if (!IsResizable) return ResultFs.SubStorageNotResizable.Log();
|
if (!IsResizable) return ResultFs.SubStorageNotResizable.Log();
|
||||||
|
@ -72,7 +72,7 @@ namespace LibHac.Fs
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSizeImpl(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = default;
|
size = default;
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace LibHac.FsService.Creators
|
||||||
imageHash.CopyTo(ImageHash);
|
imageHash.CopyTo(ImageHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
// In secure mode, if Handle is old and the card's device ID and
|
// In secure mode, if Handle is old and the card's device ID and
|
||||||
// header hash are still the same, Handle is updated to the new handle
|
// header hash are still the same, Handle is updated to the new handle
|
||||||
|
@ -95,22 +95,22 @@ namespace LibHac.FsService.Creators
|
||||||
return GameCard.Read(Handle, offset, destination);
|
return GameCard.Read(Handle, offset, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
||||||
{
|
{
|
||||||
return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log();
|
return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result FlushImpl()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSizeImpl(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log();
|
return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSizeImpl(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace LibHac.FsSystem
|
||||||
return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log();
|
return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace LibHac.FsSystem
|
||||||
return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size));
|
return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace LibHac.FsSystem
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private int BlockSize { get; }
|
private int BlockSize { get; }
|
||||||
private long _length;
|
private long Length { get; set; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
private LinkedList<CacheBlock> Blocks { get; } = new LinkedList<CacheBlock>();
|
private LinkedList<CacheBlock> Blocks { get; } = new LinkedList<CacheBlock>();
|
||||||
private Dictionary<long, LinkedListNode<CacheBlock>> BlockDict { get; } = new Dictionary<long, LinkedListNode<CacheBlock>>();
|
private Dictionary<long, LinkedListNode<CacheBlock>> BlockDict { get; } = new Dictionary<long, LinkedListNode<CacheBlock>>();
|
||||||
|
@ -17,9 +18,10 @@ namespace LibHac.FsSystem
|
||||||
{
|
{
|
||||||
BaseStorage = baseStorage;
|
BaseStorage = baseStorage;
|
||||||
BlockSize = blockSize;
|
BlockSize = blockSize;
|
||||||
BaseStorage.GetSize(out _length).ThrowIfFailure();
|
LeaveOpen = leaveOpen;
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStorage);
|
BaseStorage.GetSize(out long baseSize).ThrowIfFailure();
|
||||||
|
Length = baseSize;
|
||||||
|
|
||||||
for (int i = 0; i < cacheSize; i++)
|
for (int i = 0; i < cacheSize; i++)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +39,9 @@ namespace LibHac.FsSystem
|
||||||
long inOffset = offset;
|
long inOffset = offset;
|
||||||
int outOffset = 0;
|
int outOffset = 0;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, destination.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
lock (Blocks)
|
lock (Blocks)
|
||||||
{
|
{
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
|
@ -64,6 +69,9 @@ namespace LibHac.FsSystem
|
||||||
long inOffset = offset;
|
long inOffset = offset;
|
||||||
int outOffset = 0;
|
int outOffset = 0;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, source.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
lock (Blocks)
|
lock (Blocks)
|
||||||
{
|
{
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
|
@ -87,7 +95,7 @@ namespace LibHac.FsSystem
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
lock (Blocks)
|
lock (Blocks)
|
||||||
{
|
{
|
||||||
|
@ -100,13 +108,13 @@ namespace LibHac.FsSystem
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
Result rc = BaseStorage.SetSize(size);
|
Result rc = BaseStorage.SetSize(size);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
@ -114,11 +122,19 @@ namespace LibHac.FsSystem
|
||||||
rc = BaseStorage.GetSize(out long newSize);
|
rc = BaseStorage.GetSize(out long newSize);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
_length = newSize;
|
Length = newSize;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStorage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CacheBlock GetBlock(long blockIndex)
|
private CacheBlock GetBlock(long blockIndex)
|
||||||
{
|
{
|
||||||
if (BlockDict.TryGetValue(blockIndex, out LinkedListNode<CacheBlock> node))
|
if (BlockDict.TryGetValue(blockIndex, out LinkedListNode<CacheBlock> node))
|
||||||
|
@ -157,9 +173,9 @@ namespace LibHac.FsSystem
|
||||||
long offset = index * BlockSize;
|
long offset = index * BlockSize;
|
||||||
int length = BlockSize;
|
int length = BlockSize;
|
||||||
|
|
||||||
if (_length != -1)
|
if (Length != -1)
|
||||||
{
|
{
|
||||||
length = (int)Math.Min(_length - offset, length);
|
length = (int)Math.Min(Length - offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseStorage.Read(offset, block.Buffer.AsSpan(0, length)).ThrowIfFailure();
|
BaseStorage.Read(offset, block.Buffer.AsSpan(0, length)).ThrowIfFailure();
|
||||||
|
|
|
@ -7,12 +7,13 @@ namespace LibHac.FsSystem
|
||||||
public class ConcatenationStorage : StorageBase
|
public class ConcatenationStorage : StorageBase
|
||||||
{
|
{
|
||||||
private ConcatSource[] Sources { get; }
|
private ConcatSource[] Sources { get; }
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public ConcatenationStorage(IList<IStorage> sources, bool leaveOpen)
|
public ConcatenationStorage(IList<IStorage> sources, bool leaveOpen)
|
||||||
{
|
{
|
||||||
Sources = new ConcatSource[sources.Count];
|
Sources = new ConcatSource[sources.Count];
|
||||||
if (!leaveOpen) ToDispose.AddRange(sources);
|
LeaveOpen = leaveOpen;
|
||||||
|
|
||||||
long length = 0;
|
long length = 0;
|
||||||
for (int i = 0; i < sources.Count; i++)
|
for (int i = 0; i < sources.Count; i++)
|
||||||
|
@ -24,7 +25,7 @@ namespace LibHac.FsSystem
|
||||||
length += sourceSize;
|
length += sourceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = length;
|
Length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -32,6 +33,10 @@ namespace LibHac.FsSystem
|
||||||
long inPos = offset;
|
long inPos = offset;
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = destination.Length;
|
int remaining = destination.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, destination.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
int sourceIndex = FindSource(inPos);
|
int sourceIndex = FindSource(inPos);
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
|
@ -59,6 +64,10 @@ namespace LibHac.FsSystem
|
||||||
long inPos = offset;
|
long inPos = offset;
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = source.Length;
|
int remaining = source.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, source.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
int sourceIndex = FindSource(inPos);
|
int sourceIndex = FindSource(inPos);
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
|
@ -81,7 +90,7 @@ namespace LibHac.FsSystem
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
foreach (ConcatSource source in Sources)
|
foreach (ConcatSource source in Sources)
|
||||||
{
|
{
|
||||||
|
@ -92,15 +101,34 @@ namespace LibHac.FsSystem
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen && Sources != null)
|
||||||
|
{
|
||||||
|
foreach (ConcatSource source in Sources)
|
||||||
|
{
|
||||||
|
source?.Storage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int FindSource(long offset)
|
private int FindSource(long offset)
|
||||||
{
|
{
|
||||||
if (offset < 0 || offset >= _length)
|
if (offset < 0 || offset >= Length)
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The Storage does not contain this offset.");
|
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The Storage does not contain this offset.");
|
||||||
|
|
||||||
int lo = 0;
|
int lo = 0;
|
||||||
|
|
|
@ -22,17 +22,17 @@ namespace LibHac.FsSystem
|
||||||
return BaseFile.Write(offset, source);
|
return BaseFile.Write(offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseFile.Flush();
|
return BaseFile.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
return BaseFile.GetSize(out size);
|
return BaseFile.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
return BaseFile.SetSize(size);
|
return BaseFile.SetSize(size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ namespace LibHac.FsSystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Validity[][] LevelValidities { get; }
|
public Validity[][] LevelValidities { get; }
|
||||||
|
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
private IntegrityVerificationStorage[] IntegrityStorages { get; }
|
private IntegrityVerificationStorage[] IntegrityStorages { get; }
|
||||||
|
|
||||||
|
@ -44,9 +45,10 @@ namespace LibHac.FsSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
DataLevel = Levels[Levels.Length - 1];
|
DataLevel = Levels[Levels.Length - 1];
|
||||||
DataLevel.GetSize(out _length).ThrowIfFailure();
|
DataLevel.GetSize(out long dataSize).ThrowIfFailure();
|
||||||
|
Length = dataSize;
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.Add(DataLevel);
|
LeaveOpen = leaveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HierarchicalIntegrityVerificationStorage(IvfcHeader header, IStorage masterHash, IStorage data,
|
public HierarchicalIntegrityVerificationStorage(IvfcHeader header, IStorage masterHash, IStorage data,
|
||||||
|
@ -104,17 +106,33 @@ namespace LibHac.FsSystem
|
||||||
return DataLevel.Write(offset, source);
|
return DataLevel.Write(offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return DataLevel.Flush();
|
return DataLevel.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.UnsupportedOperationInHierarchicalIvfcStorageSetSize.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
DataLevel?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks the hashes of any unchecked blocks and returns the <see cref="Validity"/> of the data.
|
/// Checks the hashes of any unchecked blocks and returns the <see cref="Validity"/> of the data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -127,7 +145,7 @@ namespace LibHac.FsSystem
|
||||||
IntegrityVerificationStorage storage = IntegrityStorages[IntegrityStorages.Length - 1];
|
IntegrityVerificationStorage storage = IntegrityStorages[IntegrityStorages.Length - 1];
|
||||||
|
|
||||||
long blockSize = storage.SectorSize;
|
long blockSize = storage.SectorSize;
|
||||||
int blockCount = (int)Util.DivideByRoundUp(_length, blockSize);
|
int blockCount = (int)Util.DivideByRoundUp(Length, blockSize);
|
||||||
|
|
||||||
var buffer = new byte[blockSize];
|
var buffer = new byte[blockSize];
|
||||||
var result = Validity.Valid;
|
var result = Validity.Valid;
|
||||||
|
|
|
@ -12,20 +12,21 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
private List<IStorage> Sources { get; } = new List<IStorage>();
|
private List<IStorage> Sources { get; } = new List<IStorage>();
|
||||||
private BucketTree<RelocationEntry> BucketTree { get; }
|
private BucketTree<RelocationEntry> BucketTree { get; }
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public IndirectStorage(IStorage bucketTreeData, bool leaveOpen, params IStorage[] sources)
|
public IndirectStorage(IStorage bucketTreeData, bool leaveOpen, params IStorage[] sources)
|
||||||
{
|
{
|
||||||
Sources.AddRange(sources);
|
Sources.AddRange(sources);
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.AddRange(sources);
|
LeaveOpen = leaveOpen;
|
||||||
|
|
||||||
BucketTree = new BucketTree<RelocationEntry>(bucketTreeData);
|
BucketTree = new BucketTree<RelocationEntry>(bucketTreeData);
|
||||||
|
|
||||||
RelocationEntries = BucketTree.GetEntryList();
|
RelocationEntries = BucketTree.GetEntryList();
|
||||||
RelocationOffsets = RelocationEntries.Select(x => x.Offset).ToList();
|
RelocationOffsets = RelocationEntries.Select(x => x.Offset).ToList();
|
||||||
|
|
||||||
_length = BucketTree.BucketOffsets.OffsetEnd;
|
Length = BucketTree.BucketOffsets.OffsetEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -68,22 +69,36 @@ namespace LibHac.FsSystem
|
||||||
return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log();
|
return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log();
|
return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen && Sources != null)
|
||||||
|
{
|
||||||
|
foreach (IStorage storage in Sources)
|
||||||
|
{
|
||||||
|
storage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private RelocationEntry GetRelocationEntry(long offset)
|
private RelocationEntry GetRelocationEntry(long offset)
|
||||||
{
|
{
|
||||||
int index = RelocationOffsets.BinarySearch(offset);
|
int index = RelocationOffsets.BinarySearch(offset);
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
public Result Read(long offset, Span<byte> destination, IntegrityCheckLevel integrityCheckLevel)
|
public Result Read(long offset, Span<byte> destination, IntegrityCheckLevel integrityCheckLevel)
|
||||||
{
|
{
|
||||||
ValidateParameters(destination, offset);
|
// ValidateParameters(destination, offset);
|
||||||
return ReadImpl(offset, destination, integrityCheckLevel);
|
return ReadImpl(offset, destination, integrityCheckLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,12 +188,12 @@ namespace LibHac.FsSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
Result rc = HashStorage.Flush();
|
Result rc = HashStorage.Flush();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return base.Flush();
|
return base.FlushImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FsTrim()
|
public void FsTrim()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsSystem
|
namespace LibHac.FsSystem
|
||||||
{
|
{
|
||||||
|
@ -16,9 +17,6 @@ namespace LibHac.FsSystem
|
||||||
Path = path;
|
Path = path;
|
||||||
Stream = new FileStream(Path, mode, access);
|
Stream = new FileStream(Path, mode, access);
|
||||||
Storage = new StreamStorage(Stream, false);
|
Storage = new StreamStorage(Stream, false);
|
||||||
|
|
||||||
ToDispose.Add(Storage);
|
|
||||||
ToDispose.Add(Stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -31,14 +29,28 @@ namespace LibHac.FsSystem
|
||||||
return Storage.Write(offset, source);
|
return Storage.Write(offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return Storage.Flush();
|
return Storage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
|
{
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
return Storage.GetSize(out size);
|
return Storage.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Storage?.Dispose();
|
||||||
|
Stream?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace LibHac.FsSystem
|
||||||
private int _length;
|
private int _length;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
private bool _isExpandable;
|
private bool _isExpandable;
|
||||||
|
|
||||||
public MemoryStorage() : this(0) { }
|
public MemoryStorage() : this(0) { }
|
||||||
|
|
||||||
public MemoryStorage(int capacity)
|
public MemoryStorage(int capacity)
|
||||||
|
@ -19,7 +19,6 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
_capacity = capacity;
|
_capacity = capacity;
|
||||||
_isExpandable = true;
|
_isExpandable = true;
|
||||||
CanAutoExpand = true;
|
|
||||||
_buffer = new byte[capacity];
|
_buffer = new byte[capacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +40,9 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
|
if (!IsRangeValid(offset, destination.Length, _length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
_buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination);
|
_buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -48,6 +50,9 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
||||||
{
|
{
|
||||||
|
if (!IsRangeValid(offset, source.Length, _length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
long requiredCapacity = _start + offset + source.Length;
|
long requiredCapacity = _start + offset + source.Length;
|
||||||
|
|
||||||
if (requiredCapacity > _length)
|
if (requiredCapacity > _length)
|
||||||
|
@ -97,15 +102,15 @@ namespace LibHac.FsSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush() => Result.Success;
|
protected override Result FlushImpl() => Result.Success;
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = _length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log();
|
return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ namespace LibHac.FsSystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NullStorage : StorageBase
|
public class NullStorage : StorageBase
|
||||||
{
|
{
|
||||||
public NullStorage() { }
|
private long Length { get; }
|
||||||
public NullStorage(long length) => _length = length;
|
|
||||||
|
public NullStorage() { }
|
||||||
|
public NullStorage(long length) => Length = length;
|
||||||
|
|
||||||
private long _length;
|
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
{
|
{
|
||||||
|
@ -24,14 +25,19 @@ namespace LibHac.FsSystem
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,18 +83,18 @@ namespace LibHac.FsSystem.Save
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = _length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize);
|
int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize);
|
||||||
int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize);
|
int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize);
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace LibHac.FsSystem.Save
|
||||||
private IStorage DataB { get; }
|
private IStorage DataB { get; }
|
||||||
private DuplexBitmap Bitmap { get; }
|
private DuplexBitmap Bitmap { get; }
|
||||||
|
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
|
||||||
public DuplexStorage(IStorage dataA, IStorage dataB, IStorage bitmap, int blockSize)
|
public DuplexStorage(IStorage dataA, IStorage dataB, IStorage bitmap, int blockSize)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,8 @@ namespace LibHac.FsSystem.Save
|
||||||
bitmap.GetSize(out long bitmapSize).ThrowIfFailure();
|
bitmap.GetSize(out long bitmapSize).ThrowIfFailure();
|
||||||
|
|
||||||
Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmapSize * 8));
|
Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmapSize * 8));
|
||||||
DataA.GetSize(out _length).ThrowIfFailure();
|
DataA.GetSize(out long dataSize).ThrowIfFailure();
|
||||||
|
Length = dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -32,6 +33,9 @@ namespace LibHac.FsSystem.Save
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = destination.Length;
|
int remaining = destination.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, destination.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
int blockNum = (int)(inPos / BlockSize);
|
int blockNum = (int)(inPos / BlockSize);
|
||||||
|
@ -58,6 +62,9 @@ namespace LibHac.FsSystem.Save
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = source.Length;
|
int remaining = source.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, source.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
int blockNum = (int)(inPos / BlockSize);
|
int blockNum = (int)(inPos / BlockSize);
|
||||||
|
@ -78,7 +85,7 @@ namespace LibHac.FsSystem.Save
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
Result rc = BitmapStorage.Flush();
|
Result rc = BitmapStorage.Flush();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
@ -92,9 +99,14 @@ namespace LibHac.FsSystem.Save
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace LibHac.FsSystem.Save
|
||||||
{
|
{
|
||||||
private DuplexStorage[] Layers { get; }
|
private DuplexStorage[] Layers { get; }
|
||||||
private DuplexStorage DataLayer { get; }
|
private DuplexStorage DataLayer { get; }
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
|
||||||
public HierarchicalDuplexStorage(DuplexFsLayerInfo[] layers, bool masterBit)
|
public HierarchicalDuplexStorage(DuplexFsLayerInfo[] layers, bool masterBit)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,8 @@ namespace LibHac.FsSystem.Save
|
||||||
}
|
}
|
||||||
|
|
||||||
DataLayer = Layers[Layers.Length - 1];
|
DataLayer = Layers[Layers.Length - 1];
|
||||||
DataLayer.GetSize(out _length).ThrowIfFailure();
|
DataLayer.GetSize(out long dataSize).ThrowIfFailure();
|
||||||
|
Length = dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -43,14 +44,19 @@ namespace LibHac.FsSystem.Save
|
||||||
return DataLayer.Write(offset, source);
|
return DataLayer.Write(offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return DataLayer.Flush();
|
return DataLayer.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ namespace LibHac.FsSystem.Save
|
||||||
|
|
||||||
public int BlockSize { get; }
|
public int BlockSize { get; }
|
||||||
|
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public JournalStorage(IStorage baseStorage, IStorage header, JournalMapParams mapInfo, bool leaveOpen)
|
public JournalStorage(IStorage baseStorage, IStorage header, JournalMapParams mapInfo, bool leaveOpen)
|
||||||
{
|
{
|
||||||
|
@ -27,9 +28,9 @@ namespace LibHac.FsSystem.Save
|
||||||
Map = new JournalMap(mapHeader, mapInfo);
|
Map = new JournalMap(mapHeader, mapInfo);
|
||||||
|
|
||||||
BlockSize = (int)Header.BlockSize;
|
BlockSize = (int)Header.BlockSize;
|
||||||
_length = Header.TotalSize - Header.JournalSize;
|
Length = Header.TotalSize - Header.JournalSize;
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.Add(baseStorage);
|
LeaveOpen = leaveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -38,6 +39,9 @@ namespace LibHac.FsSystem.Save
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = destination.Length;
|
int remaining = destination.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, destination.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
int blockNum = (int)(inPos / BlockSize);
|
int blockNum = (int)(inPos / BlockSize);
|
||||||
|
@ -64,6 +68,9 @@ namespace LibHac.FsSystem.Save
|
||||||
int outPos = 0;
|
int outPos = 0;
|
||||||
int remaining = source.Length;
|
int remaining = source.Length;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, source.Length, Length))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
int blockNum = (int)(inPos / BlockSize);
|
int blockNum = (int)(inPos / BlockSize);
|
||||||
|
@ -84,17 +91,33 @@ namespace LibHac.FsSystem.Save
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStorage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace LibHac.FsSystem.Save
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private IStorage HeaderStorage { get; }
|
private IStorage HeaderStorage { get; }
|
||||||
private IStorage MapEntryStorage { get; }
|
private IStorage MapEntryStorage { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
private RemapHeader Header { get; }
|
private RemapHeader Header { get; }
|
||||||
public MapEntry[] MapEntries { get; set; }
|
public MapEntry[] MapEntries { get; set; }
|
||||||
|
@ -42,7 +43,7 @@ namespace LibHac.FsSystem.Save
|
||||||
MapEntries[i] = new MapEntry(reader);
|
MapEntries[i] = new MapEntry(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStorage);
|
LeaveOpen = leaveOpen;
|
||||||
|
|
||||||
Segments = InitSegments(Header, MapEntries);
|
Segments = InitSegments(Header, MapEntries);
|
||||||
}
|
}
|
||||||
|
@ -109,18 +110,34 @@ namespace LibHac.FsSystem.Save
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
|
{
|
||||||
|
return ResultFs.UnsupportedOperationInHierarchicalIvfcStorageSetSize.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
// todo: Different result code
|
// todo: Different result code
|
||||||
size = -1;
|
size = -1;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStorage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly();
|
public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly();
|
||||||
|
|
|
@ -10,7 +10,8 @@ namespace LibHac.FsSystem
|
||||||
public int SectorSize { get; }
|
public int SectorSize { get; }
|
||||||
public int SectorCount { get; private set; }
|
public int SectorCount { get; private set; }
|
||||||
|
|
||||||
private long _length;
|
private long Length { get; set; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public SectorStorage(IStorage baseStorage, int sectorSize, bool leaveOpen)
|
public SectorStorage(IStorage baseStorage, int sectorSize, bool leaveOpen)
|
||||||
{
|
{
|
||||||
|
@ -20,9 +21,9 @@ namespace LibHac.FsSystem
|
||||||
baseStorage.GetSize(out long baseSize).ThrowIfFailure();
|
baseStorage.GetSize(out long baseSize).ThrowIfFailure();
|
||||||
|
|
||||||
SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize);
|
SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize);
|
||||||
_length = baseSize;
|
Length = baseSize;
|
||||||
|
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStorage);
|
LeaveOpen = leaveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -37,18 +38,18 @@ namespace LibHac.FsSystem
|
||||||
return BaseStorage.Write(offset, source);
|
return BaseStorage.Write(offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
Result rc = BaseStorage.SetSize(size);
|
Result rc = BaseStorage.SetSize(size);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
@ -57,11 +58,22 @@ namespace LibHac.FsSystem
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize);
|
SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize);
|
||||||
_length = newSize;
|
Length = newSize;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStorage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validates that the size is a multiple of the sector size
|
/// Validates that the size is a multiple of the sector size
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using LibHac.Fs;
|
|
||||||
|
|
||||||
namespace LibHac.FsSystem
|
|
||||||
{
|
|
||||||
public abstract class StorageBase : IStorage
|
|
||||||
{
|
|
||||||
private bool _isDisposed;
|
|
||||||
protected internal List<IDisposable> ToDispose { get; } = new List<IDisposable>();
|
|
||||||
protected bool CanAutoExpand { get; set; }
|
|
||||||
|
|
||||||
protected abstract Result ReadImpl(long offset, Span<byte> destination);
|
|
||||||
protected abstract Result WriteImpl(long offset, ReadOnlySpan<byte> source);
|
|
||||||
public abstract Result Flush();
|
|
||||||
public abstract Result GetSize(out long size);
|
|
||||||
|
|
||||||
public Result Read(long offset, Span<byte> destination)
|
|
||||||
{
|
|
||||||
ValidateParameters(destination, offset);
|
|
||||||
return ReadImpl(offset, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result Write(long offset, ReadOnlySpan<byte> source)
|
|
||||||
{
|
|
||||||
ValidateParameters(source, offset);
|
|
||||||
return WriteImpl(offset, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result SetSize(long size)
|
|
||||||
{
|
|
||||||
return ResultFs.NotImplemented.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
Flush();
|
|
||||||
foreach (IDisposable item in ToDispose)
|
|
||||||
{
|
|
||||||
item?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void ValidateParameters(ReadOnlySpan<byte> span, long offset)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(null);
|
|
||||||
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
|
|
||||||
|
|
||||||
Result sizeResult = GetSize(out long length);
|
|
||||||
sizeResult.ThrowIfFailure();
|
|
||||||
|
|
||||||
if (length != -1 && !CanAutoExpand)
|
|
||||||
{
|
|
||||||
if (offset + span.Length > length) throw new ArgumentException("The given offset and count exceed the length of the Storage");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
#if !STREAM_SPAN
|
#if !STREAM_SPAN
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
@ -13,13 +14,14 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
private Stream BaseStream { get; }
|
private Stream BaseStream { get; }
|
||||||
private object Locker { get; } = new object();
|
private object Locker { get; } = new object();
|
||||||
private long _length;
|
private long Length { get; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public StreamStorage(Stream baseStream, bool leaveOpen)
|
public StreamStorage(Stream baseStream, bool leaveOpen)
|
||||||
{
|
{
|
||||||
BaseStream = baseStream;
|
BaseStream = baseStream;
|
||||||
_length = BaseStream.Length;
|
Length = BaseStream.Length;
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStream);
|
LeaveOpen = leaveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result ReadImpl(long offset, Span<byte> destination)
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
@ -90,7 +92,7 @@ namespace LibHac.FsSystem
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
lock (Locker)
|
lock (Locker)
|
||||||
{
|
{
|
||||||
|
@ -100,10 +102,26 @@ namespace LibHac.FsSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStream?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,26 +9,27 @@ namespace LibHac.FsSystem
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private long Offset { get; }
|
private long Offset { get; }
|
||||||
private FileAccess Access { get; } = FileAccess.ReadWrite;
|
private FileAccess Access { get; } = FileAccess.ReadWrite;
|
||||||
private long _length;
|
private long Length { get; set; }
|
||||||
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public SubStorage(IStorage baseStorage, long offset, long length)
|
public SubStorage(IStorage baseStorage, long offset, long length)
|
||||||
{
|
{
|
||||||
BaseStorage = baseStorage;
|
BaseStorage = baseStorage;
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
_length = length;
|
Length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubStorage(SubStorage baseStorage, long offset, long length)
|
public SubStorage(SubStorage baseStorage, long offset, long length)
|
||||||
{
|
{
|
||||||
BaseStorage = baseStorage.BaseStorage;
|
BaseStorage = baseStorage.BaseStorage;
|
||||||
Offset = baseStorage.Offset + offset;
|
Offset = baseStorage.Offset + offset;
|
||||||
_length = length;
|
Length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen)
|
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen)
|
||||||
: this(baseStorage, offset, length)
|
: this(baseStorage, offset, length)
|
||||||
{
|
{
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStorage);
|
LeaveOpen = leaveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen, FileAccess access)
|
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen, FileAccess access)
|
||||||
|
@ -49,18 +50,18 @@ namespace LibHac.FsSystem
|
||||||
return BaseStorage.Write(offset + Offset, source);
|
return BaseStorage.Write(offset + Offset, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
protected override Result FlushImpl()
|
||||||
{
|
{
|
||||||
return BaseStorage.Flush();
|
return BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result GetSize(out long size)
|
protected override Result GetSizeImpl(out long size)
|
||||||
{
|
{
|
||||||
size = _length;
|
size = Length;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result SetSize(long size)
|
protected override Result SetSizeImpl(long size)
|
||||||
{
|
{
|
||||||
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ namespace LibHac.FsSystem
|
||||||
Result rc = BaseStorage.GetSize(out long baseSize);
|
Result rc = BaseStorage.GetSize(out long baseSize);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (baseSize != Offset + _length)
|
if (baseSize != Offset + Length)
|
||||||
{
|
{
|
||||||
// SubStorage cannot be resized unless it is located at the end of the base storage.
|
// SubStorage cannot be resized unless it is located at the end of the base storage.
|
||||||
return ResultFs.SubStorageNotResizableMiddleOfFile.Log();
|
return ResultFs.SubStorageNotResizableMiddleOfFile.Log();
|
||||||
|
@ -81,9 +82,20 @@ namespace LibHac.FsSystem
|
||||||
rc = BaseStorage.SetSize(Offset + size);
|
rc = BaseStorage.SetSize(Offset + size);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
_length = size;
|
Length = size;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (!LeaveOpen)
|
||||||
|
{
|
||||||
|
BaseStorage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue