diff --git a/src/LibHac/Fs/FileHandleStorage.cs b/src/LibHac/Fs/FileHandleStorage.cs index 83c379c9..c9389681 100644 --- a/src/LibHac/Fs/FileHandleStorage.cs +++ b/src/LibHac/Fs/FileHandleStorage.cs @@ -21,7 +21,7 @@ namespace LibHac.Fs FsClient = Handle.File.Parent.FsClient; } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { lock (_locker) { @@ -36,7 +36,7 @@ namespace LibHac.Fs } } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { lock (_locker) { @@ -51,19 +51,19 @@ namespace LibHac.Fs } } - public override Result FlushImpl() + protected override Result FlushImpl() { return FsClient.FlushFile(Handle); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { FileSize = InvalidSize; return FsClient.SetFileSize(Handle, size); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = default; diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index c4b1173f..ae3e247d 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -105,10 +105,10 @@ public static Result UnsupportedOperation => new Result(ModuleFs, 6300); public static Result SubStorageNotResizable => new Result(ModuleFs, 6302); - public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6302); - public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6316); - public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6304); + public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303); + public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6304); 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 UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325); public static Result UnsupportedOperationInRoGameCardStorageWrite => new Result(ModuleFs, 6350); diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs index 60fe4f93..33044952 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/Fs/StorageBase.cs @@ -9,11 +9,11 @@ namespace LibHac.Fs private int _disposedState; private bool IsDisposed => _disposedState != 0; - public abstract Result ReadImpl(long offset, Span destination); - public abstract Result WriteImpl(long offset, ReadOnlySpan source); - public abstract Result FlushImpl(); - public abstract Result GetSizeImpl(out long size); - public abstract Result SetSizeImpl(long size); + protected abstract Result ReadImpl(long offset, Span destination); + protected abstract Result WriteImpl(long offset, ReadOnlySpan source); + protected abstract Result FlushImpl(); + protected abstract Result GetSizeImpl(out long size); + protected abstract Result SetSizeImpl(long size); public Result Read(long offset, Span destination) { diff --git a/src/LibHac/Fs/SubStorage2.cs b/src/LibHac/Fs/SubStorage2.cs index 0c9790f4..2cbe06a1 100644 --- a/src/LibHac/Fs/SubStorage2.cs +++ b/src/LibHac/Fs/SubStorage2.cs @@ -23,7 +23,7 @@ namespace LibHac.Fs Size = size; } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (destination.Length == 0) return Result.Success; @@ -33,7 +33,7 @@ namespace LibHac.Fs return BaseStorage.Read(Offset + offset, destination); } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (source.Length == 0) return Result.Success; @@ -43,14 +43,14 @@ namespace LibHac.Fs return BaseStorage.Write(Offset + offset, source); } - public override Result FlushImpl() + protected override Result FlushImpl() { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); return BaseStorage.Flush(); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); @@ -72,7 +72,7 @@ namespace LibHac.Fs return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = default; diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs index f224cb80..c8dc4bb7 100644 --- a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs @@ -87,7 +87,7 @@ namespace LibHac.FsService.Creators imageHash.CopyTo(ImageHash); } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { // 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 @@ -95,22 +95,22 @@ namespace LibHac.FsService.Creators return GameCard.Read(Handle, offset, destination); } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log(); } - public override Result FlushImpl() + protected override Result FlushImpl() { return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = 0; diff --git a/src/LibHac/FsSystem/Aes128CtrExStorage.cs b/src/LibHac/FsSystem/Aes128CtrExStorage.cs index d91b889b..491b7ac2 100644 --- a/src/LibHac/FsSystem/Aes128CtrExStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrExStorage.cs @@ -69,7 +69,7 @@ namespace LibHac.FsSystem return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log(); } - public override Result Flush() + protected override Result FlushImpl() { return Result.Success; } diff --git a/src/LibHac/FsSystem/Aes128XtsStorage.cs b/src/LibHac/FsSystem/Aes128XtsStorage.cs index 865e366f..b879dc92 100644 --- a/src/LibHac/FsSystem/Aes128XtsStorage.cs +++ b/src/LibHac/FsSystem/Aes128XtsStorage.cs @@ -67,7 +67,7 @@ namespace LibHac.FsSystem return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size)); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } diff --git a/src/LibHac/FsSystem/CachedStorage.cs b/src/LibHac/FsSystem/CachedStorage.cs index bc6485fb..d3303aed 100644 --- a/src/LibHac/FsSystem/CachedStorage.cs +++ b/src/LibHac/FsSystem/CachedStorage.cs @@ -8,7 +8,8 @@ namespace LibHac.FsSystem { private IStorage BaseStorage { get; } private int BlockSize { get; } - private long _length; + private long Length { get; set; } + private bool LeaveOpen { get; } private LinkedList Blocks { get; } = new LinkedList(); private Dictionary> BlockDict { get; } = new Dictionary>(); @@ -17,9 +18,10 @@ namespace LibHac.FsSystem { BaseStorage = baseStorage; 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++) { @@ -37,6 +39,9 @@ namespace LibHac.FsSystem long inOffset = offset; int outOffset = 0; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + lock (Blocks) { while (remaining > 0) @@ -64,6 +69,9 @@ namespace LibHac.FsSystem long inOffset = offset; int outOffset = 0; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + lock (Blocks) { while (remaining > 0) @@ -87,7 +95,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { lock (Blocks) { @@ -100,13 +108,13 @@ namespace LibHac.FsSystem return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { Result rc = BaseStorage.SetSize(size); if (rc.IsFailure()) return rc; @@ -114,11 +122,19 @@ namespace LibHac.FsSystem rc = BaseStorage.GetSize(out long newSize); if (rc.IsFailure()) return rc; - _length = newSize; + Length = newSize; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + private CacheBlock GetBlock(long blockIndex) { if (BlockDict.TryGetValue(blockIndex, out LinkedListNode node)) @@ -157,9 +173,9 @@ namespace LibHac.FsSystem long offset = index * 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(); diff --git a/src/LibHac/FsSystem/ConcatenationStorage.cs b/src/LibHac/FsSystem/ConcatenationStorage.cs index 9bce2554..13ef9c5e 100644 --- a/src/LibHac/FsSystem/ConcatenationStorage.cs +++ b/src/LibHac/FsSystem/ConcatenationStorage.cs @@ -7,12 +7,13 @@ namespace LibHac.FsSystem public class ConcatenationStorage : StorageBase { private ConcatSource[] Sources { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public ConcatenationStorage(IList sources, bool leaveOpen) { Sources = new ConcatSource[sources.Count]; - if (!leaveOpen) ToDispose.AddRange(sources); + LeaveOpen = leaveOpen; long length = 0; for (int i = 0; i < sources.Count; i++) @@ -24,7 +25,7 @@ namespace LibHac.FsSystem length += sourceSize; } - _length = length; + Length = length; } protected override Result ReadImpl(long offset, Span destination) @@ -32,6 +33,10 @@ namespace LibHac.FsSystem long inPos = offset; int outPos = 0; int remaining = destination.Length; + + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + int sourceIndex = FindSource(inPos); while (remaining > 0) @@ -59,6 +64,10 @@ namespace LibHac.FsSystem long inPos = offset; int outPos = 0; int remaining = source.Length; + + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + int sourceIndex = FindSource(inPos); while (remaining > 0) @@ -81,7 +90,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { foreach (ConcatSource source in Sources) { @@ -92,15 +101,34 @@ namespace LibHac.FsSystem 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; } + 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) { - if (offset < 0 || offset >= _length) + if (offset < 0 || offset >= Length) throw new ArgumentOutOfRangeException(nameof(offset), offset, "The Storage does not contain this offset."); int lo = 0; diff --git a/src/LibHac/FsSystem/FileStorage.cs b/src/LibHac/FsSystem/FileStorage.cs index a1865732..d9cc1f88 100644 --- a/src/LibHac/FsSystem/FileStorage.cs +++ b/src/LibHac/FsSystem/FileStorage.cs @@ -22,17 +22,17 @@ namespace LibHac.FsSystem return BaseFile.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return BaseFile.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { return BaseFile.SetSize(size); } diff --git a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs index 4d6d14be..520436ea 100644 --- a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs @@ -18,7 +18,8 @@ namespace LibHac.FsSystem /// public Validity[][] LevelValidities { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } private IntegrityVerificationStorage[] IntegrityStorages { get; } @@ -44,9 +45,10 @@ namespace LibHac.FsSystem } 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, @@ -104,17 +106,33 @@ namespace LibHac.FsSystem return DataLevel.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { 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; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + DataLevel?.Dispose(); + } + } + } + /// /// Checks the hashes of any unchecked blocks and returns the of the data. /// @@ -127,7 +145,7 @@ namespace LibHac.FsSystem IntegrityVerificationStorage storage = IntegrityStorages[IntegrityStorages.Length - 1]; long blockSize = storage.SectorSize; - int blockCount = (int)Util.DivideByRoundUp(_length, blockSize); + int blockCount = (int)Util.DivideByRoundUp(Length, blockSize); var buffer = new byte[blockSize]; var result = Validity.Valid; diff --git a/src/LibHac/FsSystem/IndirectStorage.cs b/src/LibHac/FsSystem/IndirectStorage.cs index e2c0dc05..c1387d8e 100644 --- a/src/LibHac/FsSystem/IndirectStorage.cs +++ b/src/LibHac/FsSystem/IndirectStorage.cs @@ -12,20 +12,21 @@ namespace LibHac.FsSystem private List Sources { get; } = new List(); private BucketTree BucketTree { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public IndirectStorage(IStorage bucketTreeData, bool leaveOpen, params IStorage[] sources) { Sources.AddRange(sources); - if (!leaveOpen) ToDispose.AddRange(sources); + LeaveOpen = leaveOpen; BucketTree = new BucketTree(bucketTreeData); RelocationEntries = BucketTree.GetEntryList(); RelocationOffsets = RelocationEntries.Select(x => x.Offset).ToList(); - _length = BucketTree.BucketOffsets.OffsetEnd; + Length = BucketTree.BucketOffsets.OffsetEnd; } protected override Result ReadImpl(long offset, Span destination) @@ -68,22 +69,36 @@ namespace LibHac.FsSystem return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } - public override Result Flush() + protected override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { 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) { int index = RelocationOffsets.BinarySearch(offset); diff --git a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs index 49d14636..6f10630b 100644 --- a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs @@ -124,7 +124,7 @@ namespace LibHac.FsSystem public Result Read(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { - ValidateParameters(destination, offset); + // ValidateParameters(destination, offset); return ReadImpl(offset, destination, integrityCheckLevel); } @@ -188,12 +188,12 @@ namespace LibHac.FsSystem } } - public override Result Flush() + protected override Result FlushImpl() { Result rc = HashStorage.Flush(); if (rc.IsFailure()) return rc; - return base.Flush(); + return base.FlushImpl(); } public void FsTrim() diff --git a/src/LibHac/FsSystem/LocalStorage.cs b/src/LibHac/FsSystem/LocalStorage.cs index 7e8d6596..ebc47f58 100644 --- a/src/LibHac/FsSystem/LocalStorage.cs +++ b/src/LibHac/FsSystem/LocalStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { @@ -16,9 +17,6 @@ namespace LibHac.FsSystem Path = path; Stream = new FileStream(Path, mode, access); Storage = new StreamStorage(Stream, false); - - ToDispose.Add(Storage); - ToDispose.Add(Stream); } protected override Result ReadImpl(long offset, Span destination) @@ -31,14 +29,28 @@ namespace LibHac.FsSystem return Storage.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { 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); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Storage?.Dispose(); + Stream?.Dispose(); + } + } } } diff --git a/src/LibHac/FsSystem/MemoryStorage.cs b/src/LibHac/FsSystem/MemoryStorage.cs index 8ec783a5..b655b885 100644 --- a/src/LibHac/FsSystem/MemoryStorage.cs +++ b/src/LibHac/FsSystem/MemoryStorage.cs @@ -10,7 +10,7 @@ namespace LibHac.FsSystem private int _length; private int _capacity; private bool _isExpandable; - + public MemoryStorage() : this(0) { } public MemoryStorage(int capacity) @@ -19,7 +19,6 @@ namespace LibHac.FsSystem _capacity = capacity; _isExpandable = true; - CanAutoExpand = true; _buffer = new byte[capacity]; } @@ -41,6 +40,9 @@ namespace LibHac.FsSystem protected override Result ReadImpl(long offset, Span destination) { + if (!IsRangeValid(offset, destination.Length, _length)) + return ResultFs.ValueOutOfRange.Log(); + _buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination); return Result.Success; @@ -48,6 +50,9 @@ namespace LibHac.FsSystem protected override Result WriteImpl(long offset, ReadOnlySpan source) { + if (!IsRangeValid(offset, source.Length, _length)) + return ResultFs.ValueOutOfRange.Log(); + long requiredCapacity = _start + offset + source.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; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log(); } diff --git a/src/LibHac/FsSystem/NullStorage.cs b/src/LibHac/FsSystem/NullStorage.cs index ba78a51b..81b4d23e 100644 --- a/src/LibHac/FsSystem/NullStorage.cs +++ b/src/LibHac/FsSystem/NullStorage.cs @@ -8,10 +8,11 @@ namespace LibHac.FsSystem /// public class NullStorage : StorageBase { - public NullStorage() { } - public NullStorage(long length) => _length = length; + private long Length { get; } + + public NullStorage() { } + public NullStorage(long length) => Length = length; - private long _length; protected override Result ReadImpl(long offset, Span destination) { @@ -24,14 +25,19 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { 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; } } diff --git a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs index 1e8b60c0..f68dfe16 100644 --- a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs +++ b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs @@ -83,18 +83,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { size = _length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize); int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize); diff --git a/src/LibHac/FsSystem/Save/DuplexStorage.cs b/src/LibHac/FsSystem/Save/DuplexStorage.cs index 6ac63544..e36fa7cb 100644 --- a/src/LibHac/FsSystem/Save/DuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/DuplexStorage.cs @@ -11,7 +11,7 @@ namespace LibHac.FsSystem.Save private IStorage DataB { get; } private DuplexBitmap Bitmap { get; } - private long _length; + private long Length { get; } 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 = 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 destination) @@ -32,6 +33,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = destination.Length; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -58,6 +62,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = source.Length; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -78,7 +85,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { Result rc = BitmapStorage.Flush(); if (rc.IsFailure()) return rc; @@ -92,9 +99,14 @@ namespace LibHac.FsSystem.Save 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; } diff --git a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs index e942fbd6..132b3ad5 100644 --- a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs @@ -7,7 +7,7 @@ namespace LibHac.FsSystem.Save { private DuplexStorage[] Layers { get; } private DuplexStorage DataLayer { get; } - private long _length; + private long Length { get; } public HierarchicalDuplexStorage(DuplexFsLayerInfo[] layers, bool masterBit) { @@ -30,7 +30,8 @@ namespace LibHac.FsSystem.Save } 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 destination) @@ -43,14 +44,19 @@ namespace LibHac.FsSystem.Save return DataLayer.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { 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; } diff --git a/src/LibHac/FsSystem/Save/JournalStorage.cs b/src/LibHac/FsSystem/Save/JournalStorage.cs index 5897b145..1ac69416 100644 --- a/src/LibHac/FsSystem/Save/JournalStorage.cs +++ b/src/LibHac/FsSystem/Save/JournalStorage.cs @@ -15,7 +15,8 @@ namespace LibHac.FsSystem.Save 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) { @@ -27,9 +28,9 @@ namespace LibHac.FsSystem.Save Map = new JournalMap(mapHeader, mapInfo); 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 destination) @@ -38,6 +39,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = destination.Length; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -64,6 +68,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = source.Length; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -84,17 +91,33 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { 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; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/FsSystem/Save/RemapStorage.cs b/src/LibHac/FsSystem/Save/RemapStorage.cs index a392a63d..32432176 100644 --- a/src/LibHac/FsSystem/Save/RemapStorage.cs +++ b/src/LibHac/FsSystem/Save/RemapStorage.cs @@ -13,6 +13,7 @@ namespace LibHac.FsSystem.Save private IStorage BaseStorage { get; } private IStorage HeaderStorage { get; } private IStorage MapEntryStorage { get; } + private bool LeaveOpen { get; } private RemapHeader Header { get; } public MapEntry[] MapEntries { get; set; } @@ -42,7 +43,7 @@ namespace LibHac.FsSystem.Save MapEntries[i] = new MapEntry(reader); } - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; Segments = InitSegments(Header, MapEntries); } @@ -109,18 +110,34 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { 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 size = -1; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly(); diff --git a/src/LibHac/FsSystem/SectorStorage.cs b/src/LibHac/FsSystem/SectorStorage.cs index 1760ad3f..6e0a09bc 100644 --- a/src/LibHac/FsSystem/SectorStorage.cs +++ b/src/LibHac/FsSystem/SectorStorage.cs @@ -10,7 +10,8 @@ namespace LibHac.FsSystem public int SectorSize { get; } 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) { @@ -20,9 +21,9 @@ namespace LibHac.FsSystem baseStorage.GetSize(out long baseSize).ThrowIfFailure(); SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize); - _length = baseSize; + Length = baseSize; - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; } protected override Result ReadImpl(long offset, Span destination) @@ -37,18 +38,18 @@ namespace LibHac.FsSystem return BaseStorage.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { Result rc = BaseStorage.SetSize(size); if (rc.IsFailure()) return rc; @@ -57,11 +58,22 @@ namespace LibHac.FsSystem if (rc.IsFailure()) return rc; SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize); - _length = newSize; + Length = newSize; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + /// /// Validates that the size is a multiple of the sector size /// diff --git a/src/LibHac/FsSystem/StorageBase.cs b/src/LibHac/FsSystem/StorageBase.cs deleted file mode 100644 index 267bb83c..00000000 --- a/src/LibHac/FsSystem/StorageBase.cs +++ /dev/null @@ -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 ToDispose { get; } = new List(); - protected bool CanAutoExpand { get; set; } - - protected abstract Result ReadImpl(long offset, Span destination); - protected abstract Result WriteImpl(long offset, ReadOnlySpan source); - public abstract Result Flush(); - public abstract Result GetSize(out long size); - - public Result Read(long offset, Span destination) - { - ValidateParameters(destination, offset); - return ReadImpl(offset, destination); - } - - public Result Write(long offset, ReadOnlySpan 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 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"); - } - } - } -} diff --git a/src/LibHac/FsSystem/StreamStorage.cs b/src/LibHac/FsSystem/StreamStorage.cs index 7381f63a..85505e87 100644 --- a/src/LibHac/FsSystem/StreamStorage.cs +++ b/src/LibHac/FsSystem/StreamStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; #if !STREAM_SPAN using System.Buffers; @@ -13,13 +14,14 @@ namespace LibHac.FsSystem private Stream BaseStream { get; } private object Locker { get; } = new object(); - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public StreamStorage(Stream baseStream, bool leaveOpen) { BaseStream = baseStream; - _length = BaseStream.Length; - if (!leaveOpen) ToDispose.Add(BaseStream); + Length = BaseStream.Length; + LeaveOpen = leaveOpen; } protected override Result ReadImpl(long offset, Span destination) @@ -90,7 +92,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { 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; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStream?.Dispose(); + } + } + } } } diff --git a/src/LibHac/FsSystem/SubStorage.cs b/src/LibHac/FsSystem/SubStorage.cs index 24d4c67d..efaa4b7e 100644 --- a/src/LibHac/FsSystem/SubStorage.cs +++ b/src/LibHac/FsSystem/SubStorage.cs @@ -9,26 +9,27 @@ namespace LibHac.FsSystem private IStorage BaseStorage { get; } private long Offset { get; } 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) { BaseStorage = baseStorage; Offset = offset; - _length = length; + Length = length; } public SubStorage(SubStorage baseStorage, long offset, long length) { BaseStorage = baseStorage.BaseStorage; Offset = baseStorage.Offset + offset; - _length = length; + Length = length; } public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen) : this(baseStorage, offset, length) { - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; } 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); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); @@ -72,7 +73,7 @@ namespace LibHac.FsSystem Result rc = BaseStorage.GetSize(out long baseSize); 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. return ResultFs.SubStorageNotResizableMiddleOfFile.Log(); @@ -81,9 +82,20 @@ namespace LibHac.FsSystem rc = BaseStorage.SetSize(Offset + size); if (rc.IsFailure()) return rc; - _length = size; + Length = size; return Result.Success; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } } }