From 69e77356669df0495cc2702e8deb146a58def0c7 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 3 Sep 2019 12:35:34 -0500 Subject: [PATCH] Change IFile and IStorage classes to return Result --- src/LibHac/Fs/Aes128CtrExStorage.cs | 16 ++-- src/LibHac/Fs/Aes128CtrStorage.cs | 14 +++- src/LibHac/Fs/Aes128XtsStorage.cs | 15 ++-- src/LibHac/Fs/AesXtsDirectory.cs | 11 ++- src/LibHac/Fs/AesXtsFile.cs | 38 ++++++---- src/LibHac/Fs/AesXtsFileHeader.cs | 4 +- src/LibHac/Fs/AesXtsFileSystem.cs | 4 +- src/LibHac/Fs/CachedStorage.cs | 38 +++++++--- src/LibHac/Fs/ConcatenationFile.cs | 73 +++++++++++++------ src/LibHac/Fs/ConcatenationStorage.cs | 37 +++++++--- src/LibHac/Fs/ConcatenationStorageBuilder.cs | 4 +- src/LibHac/Fs/Delta.cs | 8 +- src/LibHac/Fs/DirectorySaveDataFile.cs | 20 ++--- src/LibHac/Fs/FileReader.cs | 14 ++-- src/LibHac/Fs/FileStorage.cs | 23 +++--- src/LibHac/Fs/FileSystemExtensions.cs | 22 ++++-- ...ierarchicalIntegrityVerificationStorage.cs | 29 +++++--- src/LibHac/Fs/IFile.cs | 20 +++-- src/LibHac/Fs/IndirectStorage.cs | 33 ++++++--- src/LibHac/Fs/IntegrityVerificationStorage.cs | 51 +++++++------ src/LibHac/Fs/LocalFile.cs | 27 ++++--- src/LibHac/Fs/LocalStorage.cs | 17 +++-- src/LibHac/Fs/MemoryStorage.cs | 22 ++++-- src/LibHac/Fs/NcaUtils/Nca.cs | 8 +- src/LibHac/Fs/NcaUtils/NcaExtensions.cs | 4 +- src/LibHac/Fs/NcaUtils/NcaHeader.cs | 4 +- src/LibHac/Fs/NullFile.cs | 24 ++++-- src/LibHac/Fs/NullStorage.cs | 15 +++- src/LibHac/Fs/NxFileStream.cs | 16 ++-- src/LibHac/Fs/PartitionFile.cs | 33 ++++++--- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 11 ++- src/LibHac/Fs/ReadOnlyFile.cs | 25 ++++--- src/LibHac/Fs/ResultFs.cs | 4 + src/LibHac/Fs/RomFs/RomFsBuilder.cs | 8 +- src/LibHac/Fs/RomFs/RomFsFile.cs | 28 ++++--- src/LibHac/Fs/Save/AllocationTable.cs | 6 +- src/LibHac/Fs/Save/AllocationTableStorage.cs | 34 ++++++--- src/LibHac/Fs/Save/DuplexStorage.cs | 45 +++++++++--- .../Fs/Save/HierarchicalDuplexStorage.cs | 20 +++-- src/LibHac/Fs/Save/JournalStorage.cs | 24 ++++-- src/LibHac/Fs/Save/RemapStorage.cs | 33 ++++++--- src/LibHac/Fs/Save/SaveDataFile.cs | 36 +++++---- src/LibHac/Fs/Save/SaveFsList.cs | 16 ++-- src/LibHac/Fs/SectorStorage.cs | 41 +++++++---- src/LibHac/Fs/StorageExtensions.cs | 54 +++++++++----- src/LibHac/Fs/StorageFile.cs | 30 +++++--- src/LibHac/Fs/StorageStream.cs | 11 +-- src/LibHac/Fs/StreamFile.cs | 27 ++++--- src/LibHac/Fs/StreamStorage.cs | 20 ++++- src/LibHac/Fs/SubStorage.cs | 44 +++++++---- src/LibHac/FsClient/Accessors/FileAccessor.cs | 42 +++++++---- src/LibHac/FsClient/FileSystemManager.cs | 26 ++++--- .../Creators/EmulatedBisFileSystemCreator.cs | 4 +- src/LibHac/FsService/FileSystemProxy.cs | 8 +- src/LibHac/FsService/FileSystemProxyCore.cs | 55 +++++++------- src/LibHac/Keyset.cs | 2 +- src/LibHac/Kip.cs | 8 +- src/LibHac/Kvdb/ImkvdbReader.cs | 4 +- src/LibHac/Kvdb/KeyValueDatabase.cs | 8 +- src/LibHac/Nro.cs | 4 +- src/LibHac/Nso.cs | 2 +- src/LibHac/Package1.cs | 2 +- src/LibHac/Package2.cs | 4 +- src/hactoolnet/ProcessBench.cs | 4 +- src/hactoolnet/ProcessDelta.cs | 6 +- src/hactoolnet/ProcessFsBuild.cs | 10 ++- src/hactoolnet/ProcessNca.cs | 7 +- src/hactoolnet/ProcessPfs.cs | 6 +- src/hactoolnet/ProcessRomfs.cs | 4 +- src/hactoolnet/ProcessSave.cs | 7 +- 70 files changed, 868 insertions(+), 506 deletions(-) diff --git a/src/LibHac/Fs/Aes128CtrExStorage.cs b/src/LibHac/Fs/Aes128CtrExStorage.cs index 9dbd3398..de3c327e 100644 --- a/src/LibHac/Fs/Aes128CtrExStorage.cs +++ b/src/LibHac/Fs/Aes128CtrExStorage.cs @@ -30,7 +30,7 @@ namespace LibHac.Fs SubsectionOffsets = SubsectionEntries.Select(x => x.Offset).ToList(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { AesSubsectionEntry entry = GetSubsectionEntry(offset); @@ -45,7 +45,9 @@ namespace LibHac.Fs lock (_locker) { UpdateCounterSubsection(entry.Counter); - base.ReadImpl(destination.Slice(outPos, bytesToRead), inPos); + + Result rc = base.ReadImpl(inPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; } outPos += bytesToRead; @@ -57,16 +59,18 @@ namespace LibHac.Fs entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - throw new NotImplementedException(); + return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log(); } - public override void Flush() + public override Result Flush() { - throw new NotImplementedException(); + return Result.Success; } private AesSubsectionEntry GetSubsectionEntry(long offset) diff --git a/src/LibHac/Fs/Aes128CtrStorage.cs b/src/LibHac/Fs/Aes128CtrStorage.cs index c92467eb..99bb5a40 100644 --- a/src/LibHac/Fs/Aes128CtrStorage.cs +++ b/src/LibHac/Fs/Aes128CtrStorage.cs @@ -58,18 +58,21 @@ namespace LibHac.Fs Counter = _decryptor.Counter; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - base.ReadImpl(destination, offset); + Result rc = base.ReadImpl(offset, destination); + if (rc.IsFailure()) return rc; lock (_locker) { UpdateCounter(_counterOffset + offset); _decryptor.TransformBlock(destination); } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { byte[] encrypted = ArrayPool.Shared.Rent(source.Length); try @@ -83,12 +86,15 @@ namespace LibHac.Fs _decryptor.TransformBlock(encryptedSpan); } - base.WriteImpl(encryptedSpan, offset); + Result rc = base.WriteImpl(offset, encryptedSpan); + if (rc.IsFailure()) return rc; } finally { ArrayPool.Shared.Return(encrypted); } + + return Result.Success; } private void UpdateCounter(long offset) diff --git a/src/LibHac/Fs/Aes128XtsStorage.cs b/src/LibHac/Fs/Aes128XtsStorage.cs index e4d99161..3187a8ce 100644 --- a/src/LibHac/Fs/Aes128XtsStorage.cs +++ b/src/LibHac/Fs/Aes128XtsStorage.cs @@ -37,20 +37,23 @@ namespace LibHac.Fs _key2 = key2.ToArray(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { int size = destination.Length; long sectorIndex = offset / SectorSize; if (_decryptor == null) _decryptor = new Aes128XtsTransform(_key1, _key2, true); - base.ReadImpl(_tempBuffer.AsSpan(0, size), offset); + Result rc = base.ReadImpl(offset, _tempBuffer.AsSpan(0, size)); + if (rc.IsFailure()) return rc; _decryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex); _tempBuffer.AsSpan(0, size).CopyTo(destination); + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { int size = source.Length; long sectorIndex = offset / SectorSize; @@ -60,12 +63,12 @@ namespace LibHac.Fs source.CopyTo(_tempBuffer); _encryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex); - base.WriteImpl(_tempBuffer.AsSpan(0, size), offset); + return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size)); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } } } diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index e3400a65..d1b14e92 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -58,17 +58,20 @@ namespace LibHac.Fs { using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read)) { - if (file.GetSize() < 0x50) + file.GetSize(out long fileSize).ThrowIfFailure(); + + if (fileSize < 0x50) { return -1; } + // todo: Use result codes var buffer = new byte[8]; - file.Read(buffer, 0x20); - if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return 0; + file.Read(out long _, 0x20, buffer); + if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return -1; - file.Read(buffer, 0x48); + file.Read(out long _, 0x48, buffer); return BitConverter.ToInt64(buffer, 0); } } diff --git a/src/LibHac/Fs/AesXtsFile.cs b/src/LibHac/Fs/AesXtsFile.cs index 32c5b922..fcaa6335 100644 --- a/src/LibHac/Fs/AesXtsFile.cs +++ b/src/LibHac/Fs/AesXtsFile.cs @@ -26,12 +26,14 @@ namespace LibHac.Fs Header = new AesXtsFileHeader(BaseFile); + baseFile.GetSize(out long fileSize).ThrowIfFailure(); + if (!Header.TryDecryptHeader(Path, KekSeed, VerificationKey)) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys, "NAX0 key derivation failed."); } - if (HeaderLength + Util.AlignUp(Header.Size, 0x10) > baseFile.GetSize()) + if (HeaderLength + Util.AlignUp(Header.Size, 0x10) > fileSize) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort, "NAX0 key derivation failed."); } @@ -49,44 +51,52 @@ namespace LibHac.Fs return key; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return Header.Size; + size = Header.Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { Header.SetSize(size, VerificationKey); - BaseFile.Write(Header.ToBytes(false), 0); + Result rc = BaseFile.Write(0, Header.ToBytes(false)); + if (rc.IsFailure()) return rc; - BaseStorage.SetSize(size); + return BaseStorage.SetSize(size); } } } diff --git a/src/LibHac/Fs/AesXtsFileHeader.cs b/src/LibHac/Fs/AesXtsFileHeader.cs index 68776041..6c416179 100644 --- a/src/LibHac/Fs/AesXtsFileHeader.cs +++ b/src/LibHac/Fs/AesXtsFileHeader.cs @@ -21,7 +21,9 @@ namespace LibHac.Fs public AesXtsFileHeader(IFile aesXtsFile) { - if (aesXtsFile.GetSize() < 0x80) + aesXtsFile.GetSize(out long fileSize).ThrowIfFailure(); + + if (fileSize < 0x80) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderTooShort); } diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/Fs/AesXtsFileSystem.cs index facfbe5e..545c556f 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/Fs/AesXtsFileSystem.cs @@ -54,7 +54,7 @@ namespace LibHac.Fs using (IFile baseFile = BaseFileSystem.OpenFile(path, OpenMode.Write)) { - baseFile.Write(header.ToBytes(false), 0); + baseFile.Write(0, header.ToBytes(false)).ThrowIfFailure(); } } @@ -235,7 +235,7 @@ namespace LibHac.Fs using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.ReadWrite)) { - file.Write(header.ToBytes(false), 0, WriteOption.Flush); + file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure(); } } } diff --git a/src/LibHac/Fs/CachedStorage.cs b/src/LibHac/Fs/CachedStorage.cs index a6e874f3..964a4989 100644 --- a/src/LibHac/Fs/CachedStorage.cs +++ b/src/LibHac/Fs/CachedStorage.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs { BaseStorage = baseStorage; BlockSize = blockSize; - _length = BaseStorage.GetSize(); + BaseStorage.GetSize(out _length).ThrowIfFailure(); if (!leaveOpen) ToDispose.Add(BaseStorage); @@ -30,7 +30,7 @@ namespace LibHac.Fs public CachedStorage(SectorStorage baseStorage, int cacheSize, bool leaveOpen) : this(baseStorage, baseStorage.SectorSize, cacheSize, leaveOpen) { } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long remaining = destination.Length; long inOffset = offset; @@ -53,9 +53,11 @@ namespace LibHac.Fs remaining -= bytesToRead; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long remaining = source.Length; long inOffset = offset; @@ -80,9 +82,11 @@ namespace LibHac.Fs remaining -= bytesToWrite; } } + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Blocks) { @@ -92,16 +96,26 @@ namespace LibHac.Fs } } - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseStorage.SetSize(size); + size = _length; + return Result.Success; + } - _length = BaseStorage.GetSize(); + public override Result SetSize(long size) + { + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; + + rc = BaseStorage.GetSize(out long newSize); + if (rc.IsFailure()) return rc; + + _length = newSize; + + return Result.Success; } private CacheBlock GetBlock(long blockIndex) @@ -147,7 +161,7 @@ namespace LibHac.Fs length = (int)Math.Min(_length - offset, length); } - BaseStorage.Read(block.Buffer.AsSpan(0, length), offset); + BaseStorage.Read(offset, block.Buffer.AsSpan(0, length)).ThrowIfFailure(); block.Length = length; block.Index = index; block.Dirty = false; @@ -158,7 +172,7 @@ namespace LibHac.Fs if (!block.Dirty) return; long offset = block.Index * BlockSize; - BaseStorage.Write(block.Buffer.AsSpan(0, block.Length), offset); + BaseStorage.Write(offset, block.Buffer.AsSpan(0, block.Length)).ThrowIfFailure(); block.Dirty = false; } diff --git a/src/LibHac/Fs/ConcatenationFile.cs b/src/LibHac/Fs/ConcatenationFile.cs index ad738465..b50c7594 100644 --- a/src/LibHac/Fs/ConcatenationFile.cs +++ b/src/LibHac/Fs/ConcatenationFile.cs @@ -22,7 +22,9 @@ namespace LibHac.Fs for (int i = 0; i < Sources.Count - 1; i++) { - if (Sources[i].GetSize() != SubFileSize) + Sources[i].GetSize(out long actualSubFileSize).ThrowIfFailure(); + + if (actualSubFileSize != SubFileSize) { throw new ArgumentException($"Source file must have size {subFileSize}"); } @@ -31,33 +33,41 @@ namespace LibHac.Fs ToDispose.AddRange(Sources); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + long inPos = offset; int outPos = 0; int remaining = ValidateReadParamsAndGetSize(destination, offset); + GetSize(out long fileSize).ThrowIfFailure(); + while (remaining > 0) { int fileIndex = GetSubFileIndexFromOffset(offset); IFile file = Sources[fileIndex]; long fileOffset = offset - fileIndex * SubFileSize; - long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize()); + long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining); - int bytesRead = file.Read(destination.Slice(outPos, bytesToRead), fileOffset, options); - outPos += bytesRead; - inPos += bytesRead; - remaining -= bytesRead; + Result rc = file.Read(out long subFileBytesRead, fileOffset, destination.Slice(outPos, bytesToRead), options); + if (rc.IsFailure()) return rc; + + outPos += (int)subFileBytesRead; + inPos += subFileBytesRead; + remaining -= (int)subFileBytesRead; if (bytesRead < bytesToRead) break; } - return outPos; + bytesRead = outPos; + + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); @@ -65,15 +75,19 @@ namespace LibHac.Fs long outPos = offset; int remaining = source.Length; + GetSize(out long fileSize).ThrowIfFailure(); + while (remaining > 0) { int fileIndex = GetSubFileIndexFromOffset(outPos); IFile file = Sources[fileIndex]; long fileOffset = outPos - fileIndex * SubFileSize; - long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize()); + long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining); - file.Write(source.Slice(inPos, bytesToWrite), fileOffset, options); + + Result rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; @@ -82,35 +96,43 @@ namespace LibHac.Fs if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { foreach (IFile file in Sources) { - file.Flush(); + Result rc = file.Flush(); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - long size = 0; + size = default; foreach (IFile file in Sources) { - size += file.GetSize(); + Result rc = file.GetSize(out long subFileSize); + if (rc.IsFailure()) return rc; + + size += subFileSize; } - return size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - long currentSize = GetSize(); + GetSize(out long currentSize).ThrowIfFailure(); - if (currentSize == size) return; + if (currentSize == size) return Result.Success; int currentSubFileCount = QuerySubFileCount(currentSize, SubFileSize); int newSubFileCount = QuerySubFileCount(size, SubFileSize); @@ -120,7 +142,8 @@ namespace LibHac.Fs IFile currentLastSubFile = Sources[currentSubFileCount - 1]; long newSubFileSize = QuerySubFileSize(currentSubFileCount - 1, size, SubFileSize); - currentLastSubFile.SetSize(newSubFileSize); + Result rc = currentLastSubFile.SetSize(newSubFileSize); + if (rc.IsFailure()) return rc; for (int i = currentSubFileCount; i < newSubFileCount; i++) { @@ -143,8 +166,12 @@ namespace LibHac.Fs } long newLastFileSize = QuerySubFileSize(newSubFileCount - 1, size, SubFileSize); - Sources[newSubFileCount - 1].SetSize(newLastFileSize); + + Result rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); + if (rc.IsFailure()) return rc; } + + return Result.Success; } private int GetSubFileIndexFromOffset(long offset) diff --git a/src/LibHac/Fs/ConcatenationStorage.cs b/src/LibHac/Fs/ConcatenationStorage.cs index a6a6978a..af907d2f 100644 --- a/src/LibHac/Fs/ConcatenationStorage.cs +++ b/src/LibHac/Fs/ConcatenationStorage.cs @@ -16,15 +16,17 @@ namespace LibHac.Fs long length = 0; for (int i = 0; i < sources.Count; i++) { - if (sources[i].GetSize() < 0) throw new ArgumentException("Sources must have an explicit length."); - Sources[i] = new ConcatSource(sources[i], length, sources[i].GetSize()); - length += sources[i].GetSize(); + sources[i].GetSize(out long sourceSize).ThrowIfFailure(); + + if (sourceSize < 0) throw new ArgumentException("Sources must have an explicit length."); + Sources[i] = new ConcatSource(sources[i], length, sourceSize); + length += sourceSize; } _length = length; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -38,16 +40,20 @@ namespace LibHac.Fs long entryRemain = entry.StartOffset + entry.Size - inPos; int bytesToRead = (int)Math.Min(entryRemain, remaining); - entry.Storage.Read(destination.Slice(outPos, bytesToRead), entryPos); + + Result rc = entry.Storage.Read(entryPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; sourceIndex++; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -61,24 +67,35 @@ namespace LibHac.Fs long entryRemain = entry.StartOffset + entry.Size - inPos; int bytesToWrite = (int)Math.Min(entryRemain, remaining); - entry.Storage.Write(source.Slice(outPos, bytesToWrite), entryPos); + + Result rc = entry.Storage.Write(entryPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; sourceIndex++; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { foreach (ConcatSource source in Sources) { - source.Storage.Flush(); + Result rc = source.Storage.Flush(); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } private int FindSource(long offset) { diff --git a/src/LibHac/Fs/ConcatenationStorageBuilder.cs b/src/LibHac/Fs/ConcatenationStorageBuilder.cs index 3ea5f670..86749565 100644 --- a/src/LibHac/Fs/ConcatenationStorageBuilder.cs +++ b/src/LibHac/Fs/ConcatenationStorageBuilder.cs @@ -41,8 +41,10 @@ namespace LibHac.Fs sources.Add(new NullStorage(paddingNeeded)); } + segment.Storage.GetSize(out long segmentSize).ThrowIfFailure(); + sources.Add(segment.Storage); - offset = segment.Offset + segment.Storage.GetSize(); + offset = segment.Offset + segmentSize; } return new ConcatenationStorage(sources, true); diff --git a/src/LibHac/Fs/Delta.cs b/src/LibHac/Fs/Delta.cs index 26fc43d9..3a70cdd7 100644 --- a/src/LibHac/Fs/Delta.cs +++ b/src/LibHac/Fs/Delta.cs @@ -20,15 +20,16 @@ namespace LibHac.Fs public Delta(IStorage deltaStorage) { DeltaStorage = deltaStorage; + deltaStorage.GetSize(out long deltaSize).ThrowIfFailure(); - if (DeltaStorage.GetSize() < 0x40) throw new InvalidDataException("Delta file is too small."); + if (deltaSize < 0x40) throw new InvalidDataException("Delta file is too small."); Header = new DeltaHeader(deltaStorage.AsFile(OpenMode.Read)); if (Header.Magic != Ndv0Magic) throw new InvalidDataException("NDV0 magic value is missing."); long fragmentSize = Header.HeaderSize + Header.BodySize; - if (DeltaStorage.GetSize() < fragmentSize) + if (deltaSize < fragmentSize) { throw new InvalidDataException($"Delta file is smaller than the header indicates. (0x{fragmentSize} bytes)"); } @@ -39,8 +40,9 @@ namespace LibHac.Fs public void SetBaseStorage(IStorage baseStorage) { OriginalStorage = baseStorage; + baseStorage.GetSize(out long storageSize).ThrowIfFailure(); - if (OriginalStorage.GetSize() != Header.OriginalSize) + if (storageSize != Header.OriginalSize) { throw new InvalidDataException($"Original file size does not match the size in the delta header. (0x{Header.OriginalSize} bytes)"); } diff --git a/src/LibHac/Fs/DirectorySaveDataFile.cs b/src/LibHac/Fs/DirectorySaveDataFile.cs index 7bda0da9..2c68ad92 100644 --- a/src/LibHac/Fs/DirectorySaveDataFile.cs +++ b/src/LibHac/Fs/DirectorySaveDataFile.cs @@ -16,29 +16,29 @@ namespace LibHac.Fs ToDispose.Add(BaseFile); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { - return BaseFile.Read(destination, offset, options); + return BaseFile.Read(out bytesRead, offset, destination, options); } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { - BaseFile.Write(source, offset, options); + return BaseFile.Write(offset, source, options); } - public override void Flush() + public override Result Flush() { - BaseFile.Flush(); + return BaseFile.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseFile.GetSize(); + return BaseFile.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { - BaseFile.SetSize(size); + return BaseFile.SetSize(size); } protected override void Dispose(bool disposing) diff --git a/src/LibHac/Fs/FileReader.cs b/src/LibHac/Fs/FileReader.cs index 5a7779f1..25f54ea9 100644 --- a/src/LibHac/Fs/FileReader.cs +++ b/src/LibHac/Fs/FileReader.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs { Debug.Assert(count <= BufferSize); - _file.Read(_buffer.AsSpan(0, count), _start + offset); + _file.Read(out long _, _start + offset, _buffer.AsSpan(0, count)).ThrowIfFailure(); if (updatePosition) Position = offset + count; } @@ -101,7 +101,7 @@ namespace LibHac.Fs public long ReadInt64(long offset, bool updatePosition) { FillBuffer(offset, sizeof(long), updatePosition); - + return MemoryMarshal.Read(_buffer); } @@ -121,16 +121,16 @@ namespace LibHac.Fs public byte[] ReadBytes(long offset, int length, bool updatePosition) { - var result = new byte[length]; - _file.Read(result, offset); + var bytes = new byte[length]; + _file.Read(out long _, offset, bytes).ThrowIfFailure(); if (updatePosition) Position = offset + length; - return result; + return bytes; } public void ReadBytes(Span destination, long offset, bool updatePosition) { - _file.Read(destination, offset); + _file.Read(out long _, offset, destination).ThrowIfFailure(); if (updatePosition) Position = offset + destination.Length; } @@ -138,7 +138,7 @@ namespace LibHac.Fs public string ReadAscii(long offset, int length, bool updatePosition) { var bytes = new byte[length]; - _file.Read(bytes, offset); + _file.Read(out long _, offset, bytes).ThrowIfFailure(); if (updatePosition) Position = offset + length; return Encoding.ASCII.GetString(bytes); diff --git a/src/LibHac/Fs/FileStorage.cs b/src/LibHac/Fs/FileStorage.cs index 80c8e6bc..1b0ae864 100644 --- a/src/LibHac/Fs/FileStorage.cs +++ b/src/LibHac/Fs/FileStorage.cs @@ -11,26 +11,29 @@ namespace LibHac.Fs BaseFile = baseFile; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - BaseFile.Read(destination, offset); + return BaseFile.Read(out long _, offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - BaseFile.Write(source, offset); + return BaseFile.Write(offset, source); } - public override void Flush() + public override Result Flush() { - BaseFile.Flush(); + return BaseFile.Flush(); } - public override long GetSize() => BaseFile.GetSize(); - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseFile.SetSize(size); + return BaseFile.GetSize(out size); + } + + public override Result SetSize(long size) + { + return BaseFile.SetSize(size); } } } diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 8669d230..22643be6 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -103,17 +103,23 @@ namespace LibHac.Fs public static void CopyTo(this IFile file, IFile dest, IProgressReport logger = null) { const int bufferSize = 0x8000; - logger?.SetTotal(file.GetSize()); + + file.GetSize(out long fileSize).ThrowIfFailure(); + + logger?.SetTotal(fileSize); byte[] buffer = ArrayPool.Shared.Rent(bufferSize); try { long inOffset = 0; - int bytesRead; - while ((bytesRead = file.Read(buffer, inOffset)) != 0) + // todo: use result for loop condition + while (true) { - dest.Write(buffer.AsSpan(0, bytesRead), inOffset); + file.Read(out long bytesRead, inOffset, buffer).ThrowIfFailure(); + if (bytesRead == 0) break; + + dest.Write(inOffset, buffer.AsSpan(0, (int)bytesRead)).ThrowIfFailure(); inOffset += bytesRead; logger?.ReportAdd(bytesRead); } @@ -190,14 +196,14 @@ namespace LibHac.Fs } } - public static int Read(this IFile file, Span destination, long offset) + public static Result Read(this IFile file, out long bytesRead, long offset, Span destination) { - return file.Read(destination, offset, ReadOption.None); + return file.Read(out bytesRead, offset, destination, ReadOption.None); } - public static void Write(this IFile file, ReadOnlySpan source, long offset) + public static Result Write(this IFile file, long offset, ReadOnlySpan source) { - file.Write(source, offset, WriteOption.None); + return file.Write(offset, source, WriteOption.None); } public static bool DirectoryExists(this IFileSystem fs, string path) diff --git a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs index a81f438a..92001edf 100644 --- a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs @@ -33,8 +33,9 @@ namespace LibHac.Fs for (int i = 1; i < Levels.Length; i++) { var levelData = new IntegrityVerificationStorage(levelInfo[i], Levels[i - 1], integrityCheckLevel, leaveOpen); + levelData.GetSize(out long levelSize).ThrowIfFailure(); - int cacheCount = Math.Min((int)Util.DivideByRoundUp(levelData.GetSize(), levelInfo[i].BlockSize), 4); + int cacheCount = Math.Min((int)Util.DivideByRoundUp(levelSize, levelInfo[i].BlockSize), 4); Levels[i] = new CachedStorage(levelData, cacheCount, leaveOpen); LevelValidities[i - 1] = levelData.BlockValidities; @@ -42,7 +43,7 @@ namespace LibHac.Fs } DataLevel = Levels[Levels.Length - 1]; - _length = DataLevel.GetSize(); + DataLevel.GetSize(out _length).ThrowIfFailure(); if (!leaveOpen) ToDispose.Add(DataLevel); } @@ -92,22 +93,26 @@ namespace LibHac.Fs return initInfo; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - DataLevel.Read(destination, offset); + return DataLevel.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - DataLevel.Write(source, offset); + return DataLevel.Write(offset, source); } - public override void Flush() + public override Result Flush() { - DataLevel.Flush(); + return DataLevel.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } /// /// Checks the hashes of any unchecked blocks and returns the of the data. @@ -132,8 +137,10 @@ namespace LibHac.Fs { if (validities[i] == Validity.Unchecked) { - int toRead = (int)Math.Min(storage.GetSize() - blockSize * i, buffer.Length); - storage.Read(buffer.AsSpan(0, toRead), blockSize * i, IntegrityCheckLevel.IgnoreOnInvalid); + storage.GetSize(out long storageSize).ThrowIfFailure(); + int toRead = (int)Math.Min(storageSize - blockSize * i, buffer.Length); + + storage.Read(blockSize * i, buffer.AsSpan(0, toRead), IntegrityCheckLevel.IgnoreOnInvalid); } if (validities[i] == Validity.Invalid) diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index 08da0ddd..da2a5644 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -26,24 +26,22 @@ namespace LibHac.Fs /// /// Reads a sequence of bytes from the current . /// + /// If the operation returns successfully, The total number of bytes read into + /// the buffer. This can be less than the size of the buffer if the IFile is too short to fulfill the request. + /// The offset in the at which to begin reading. /// The buffer where the read bytes will be stored. /// The number of bytes read will be no larger than the length of the buffer. - /// The offset in the at which to begin reading. /// Options for reading from the . - /// The total number of bytes read into the buffer. This can be less than the - /// size of the buffer if the IFile is too short to fulfill the request. - /// is invalid. - /// The file's does not allow reading. + /// The of the requested operation. Result Read(out long bytesRead, long offset, Span destination, ReadOption options); /// /// Writes a sequence of bytes to the current . /// - /// The buffer containing the bytes to be written. /// The offset in the at which to begin writing. + /// The buffer containing the bytes to be written. /// Options for writing to the . - /// is negative. - /// The file's does not allow this request. + /// The of the requested operation. Result Write(long offset, ReadOnlySpan source, WriteOption options); /// @@ -54,15 +52,15 @@ namespace LibHac.Fs /// /// Gets the number of bytes in the file. /// - /// The length of the file in bytes. + /// If the operation returns successfully, the length of the file in bytes. + /// The of the requested operation. Result GetSize(out long size); /// /// Sets the size of the file in bytes. /// /// The desired size of the file in bytes. - /// If increasing the file size, The file's - /// does not allow this appending. + /// The of the requested operation. Result SetSize(long size); } } \ No newline at end of file diff --git a/src/LibHac/Fs/IndirectStorage.cs b/src/LibHac/Fs/IndirectStorage.cs index 443e9c1a..f49336b0 100644 --- a/src/LibHac/Fs/IndirectStorage.cs +++ b/src/LibHac/Fs/IndirectStorage.cs @@ -27,13 +27,13 @@ namespace LibHac.Fs _length = BucketTree.BucketOffsets.OffsetEnd; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { RelocationEntry entry = GetRelocationEntry(offset); if (entry.SourceIndex > Sources.Count) { - ThrowHelper.ThrowResult(ResultFs.InvalidIndirectStorageSource); + return ResultFs.InvalidIndirectStorageSource.Log(); } long inPos = offset; @@ -45,7 +45,9 @@ namespace LibHac.Fs long entryPos = inPos - entry.Offset; int bytesToRead = (int)Math.Min(entry.OffsetEnd - inPos, remaining); - Sources[entry.SourceIndex].Read(destination.Slice(outPos, bytesToRead), entry.SourceOffset + entryPos); + + Result rc = Sources[entry.SourceIndex].Read(entry.SourceOffset + entryPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; @@ -56,20 +58,29 @@ namespace LibHac.Fs entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInIndirectStorageWrite); + return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } - public override void Flush() { } - - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result Flush() { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInIndirectStorageSetSize); + return Result.Success; + } + + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } private RelocationEntry GetRelocationEntry(long offset) diff --git a/src/LibHac/Fs/IntegrityVerificationStorage.cs b/src/LibHac/Fs/IntegrityVerificationStorage.cs index e03db3df..4adbab58 100644 --- a/src/LibHac/Fs/IntegrityVerificationStorage.cs +++ b/src/LibHac/Fs/IntegrityVerificationStorage.cs @@ -32,7 +32,7 @@ namespace LibHac.Fs BlockValidities = new Validity[SectorCount]; } - private void ReadImpl(Span destination, long offset, IntegrityCheckLevel integrityCheckLevel) + private Result ReadImpl(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { int count = destination.Length; @@ -52,13 +52,13 @@ namespace LibHac.Fs if (Type != IntegrityStorageType.Save && !needsHashCheck) { - BaseStorage.Read(destination, offset); - return; + BaseStorage.Read(offset, destination); + return Result.Success; } Span hashBuffer = stackalloc byte[DigestSize]; long hashPos = blockIndex * DigestSize; - HashStorage.Read(hashBuffer, hashPos); + HashStorage.Read(hashPos, hashBuffer); if (Type == IntegrityStorageType.Save) { @@ -66,23 +66,23 @@ namespace LibHac.Fs { destination.Clear(); BlockValidities[blockIndex] = Validity.Valid; - return; + return Result.Success; } if (!needsHashCheck) { - BaseStorage.Read(destination, offset); - return; + BaseStorage.Read(offset, destination); + return Result.Success; } } byte[] dataBuffer = ArrayPool.Shared.Rent(SectorSize); try { - BaseStorage.Read(destination, offset); + BaseStorage.Read(offset, destination); destination.CopyTo(dataBuffer); - if (BlockValidities[blockIndex] != Validity.Unchecked) return; + if (BlockValidities[blockIndex] != Validity.Unchecked) return Result.Success; int bytesToHash = SectorSize; @@ -112,25 +112,30 @@ namespace LibHac.Fs { ArrayPool.Shared.Return(dataBuffer); } + + return Result.Success; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - ReadImpl(destination, offset, IntegrityCheckLevel); + return ReadImpl(offset, destination, IntegrityCheckLevel); } - public void Read(Span destination, long offset, IntegrityCheckLevel integrityCheckLevel) + public Result Read(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { ValidateParameters(destination, offset); - ReadImpl(destination, offset, integrityCheckLevel); + return ReadImpl(offset, destination, integrityCheckLevel); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long blockIndex = offset / SectorSize; long hashPos = blockIndex * DigestSize; - int toWrite = (int)Math.Min(source.Length, GetSize() - offset); + Result rc = GetSize(out long storageSize); + if (rc.IsFailure()) return rc; + + int toWrite = (int)Math.Min(source.Length, storageSize - offset); byte[] dataBuffer = ArrayPool.Shared.Rent(SectorSize); try @@ -143,15 +148,17 @@ namespace LibHac.Fs Array.Clear(hash, 0, DigestSize); } - BaseStorage.Write(source, offset); + BaseStorage.Write(offset, source); - HashStorage.Write(hash, hashPos); + HashStorage.Write(hashPos, hash); BlockValidities[blockIndex] = Validity.Unchecked; } finally { ArrayPool.Shared.Return(dataBuffer); } + + return Result.Success; } private byte[] DoHash(byte[] buffer, int offset, int count) @@ -180,10 +187,12 @@ namespace LibHac.Fs } } - public override void Flush() + public override Result Flush() { - HashStorage.Flush(); - base.Flush(); + Result rc = HashStorage.Flush(); + if (rc.IsFailure()) return rc; + + return base.Flush(); } public void FsTrim() @@ -195,7 +204,7 @@ namespace LibHac.Fs for (int i = 0; i < SectorCount; i++) { long hashPos = i * DigestSize; - HashStorage.Read(digest, hashPos); + HashStorage.Read(hashPos, digest).ThrowIfFailure(); if (!Util.IsEmpty(digest)) continue; diff --git a/src/LibHac/Fs/LocalFile.cs b/src/LibHac/Fs/LocalFile.cs index 950af64f..4cb9e655 100644 --- a/src/LibHac/Fs/LocalFile.cs +++ b/src/LibHac/Fs/LocalFile.cs @@ -21,33 +21,31 @@ namespace LibHac.Fs ToDispose.Add(Stream); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { int toRead = ValidateReadParamsAndGetSize(destination, offset); - File.Read(destination.Slice(0, toRead), offset, options); - - return toRead; + return File.Read(out bytesRead, offset, destination.Slice(0, toRead), options); } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - - File.Write(source, offset, options); + + return File.Write(offset, source, options); } - public override void Flush() + public override Result Flush() { - File.Flush(); + return File.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return File.GetSize(); + return File.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { try { @@ -55,9 +53,10 @@ namespace LibHac.Fs } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } + + return Result.Success; } private static FileAccess GetFileAccess(OpenMode mode) diff --git a/src/LibHac/Fs/LocalStorage.cs b/src/LibHac/Fs/LocalStorage.cs index 6d990699..ea5b6e20 100644 --- a/src/LibHac/Fs/LocalStorage.cs +++ b/src/LibHac/Fs/LocalStorage.cs @@ -21,21 +21,24 @@ namespace LibHac.Fs ToDispose.Add(Stream); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - Storage.Read(destination, offset); + return Storage.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - Storage.Write(source, offset); + return Storage.Write(offset, source); } - public override void Flush() + public override Result Flush() { - Storage.Flush(); + return Storage.Flush(); } - public override long GetSize() => Storage.GetSize(); + public override Result GetSize(out long size) + { + return Storage.GetSize(out size); + } } } diff --git a/src/LibHac/Fs/MemoryStorage.cs b/src/LibHac/Fs/MemoryStorage.cs index fb88a181..23c025ff 100644 --- a/src/LibHac/Fs/MemoryStorage.cs +++ b/src/LibHac/Fs/MemoryStorage.cs @@ -38,12 +38,14 @@ namespace LibHac.Fs _isExpandable = false; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { _buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination); + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long requiredCapacity = _start + offset + source.Length; @@ -54,6 +56,8 @@ namespace LibHac.Fs } source.CopyTo(_buffer.AsSpan((int)(_start + offset), source.Length)); + + return Result.Success; } public byte[] ToArray() @@ -92,13 +96,17 @@ namespace LibHac.Fs } } - public override void Flush() { } + public override Result Flush() => Result.Success; - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInMemoryStorageSetSize); + size = _length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log(); } } } diff --git a/src/LibHac/Fs/NcaUtils/Nca.cs b/src/LibHac/Fs/NcaUtils/Nca.cs index 7296aa5c..ed892d26 100644 --- a/src/LibHac/Fs/NcaUtils/Nca.cs +++ b/src/LibHac/Fs/NcaUtils/Nca.cs @@ -117,10 +117,12 @@ namespace LibHac.Fs.NcaUtils long offset = Header.GetSectionStartOffset(index); long size = Header.GetSectionSize(index); - if (!Util.IsSubRange(offset, size, BaseStorage.GetSize())) + BaseStorage.GetSize(out long baseSize).ThrowIfFailure(); + + if (!Util.IsSubRange(offset, size, baseSize)) { throw new InvalidDataException( - $"Section offset (0x{offset:x}) and length (0x{size:x}) fall outside the total NCA length (0x{BaseStorage.GetSize():x})."); + $"Section offset (0x{offset:x}) and length (0x{size:x}) fall outside the total NCA length (0x{baseSize:x})."); } return BaseStorage.Slice(offset, size); @@ -492,7 +494,7 @@ namespace LibHac.Fs.NcaUtils private int ReadHeaderVersion(IStorage header) { Span buf = stackalloc byte[1]; - header.Read(buf, 0x203); + header.Read(0x203, buf).Log(); return buf[0] - '0'; } diff --git a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs b/src/LibHac/Fs/NcaUtils/NcaExtensions.cs index 42f8bb0e..72cbc384 100644 --- a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs +++ b/src/LibHac/Fs/NcaUtils/NcaExtensions.cs @@ -95,7 +95,7 @@ namespace LibHac.Fs.NcaUtils IStorage storage = nca.OpenRawStorage(index); var data = new byte[size]; - storage.Read(data, offset); + storage.Read(offset, data).ThrowIfFailure(); byte[] actualHash = Crypto.ComputeSha256(data, 0, data.Length); @@ -116,7 +116,7 @@ namespace LibHac.Fs.NcaUtils IStorage decryptedStorage = nca.OpenRawStorage(index); Span buffer = stackalloc byte[sizeof(long)]; - decryptedStorage.Read(buffer, header.EncryptionTreeOffset + 8); + decryptedStorage.Read(header.EncryptionTreeOffset + 8, buffer).ThrowIfFailure(); long readDataSize = BinaryPrimitives.ReadInt64LittleEndian(buffer); if (header.EncryptionTreeOffset != readDataSize) return Validity.Invalid; diff --git a/src/LibHac/Fs/NcaUtils/NcaHeader.cs b/src/LibHac/Fs/NcaUtils/NcaHeader.cs index d15dcbf9..d4580f9a 100644 --- a/src/LibHac/Fs/NcaUtils/NcaHeader.cs +++ b/src/LibHac/Fs/NcaUtils/NcaHeader.cs @@ -17,7 +17,7 @@ namespace LibHac.Fs.NcaUtils public NcaHeader(IStorage headerStorage) { _header = new byte[HeaderSize]; - headerStorage.Read(_header.Span, 0); + headerStorage.Read(0, _header.Span); } public NcaHeader(Keyset keyset, IStorage headerStorage) @@ -188,7 +188,7 @@ namespace LibHac.Fs.NcaUtils public static byte[] DecryptHeader(Keyset keyset, IStorage storage) { var buf = new byte[HeaderSize]; - storage.Read(buf, 0); + storage.Read(0, buf); byte[] key1 = keyset.HeaderKey.AsSpan(0, 0x10).ToArray(); byte[] key2 = keyset.HeaderKey.AsSpan(0x10, 0x10).ToArray(); diff --git a/src/LibHac/Fs/NullFile.cs b/src/LibHac/Fs/NullFile.cs index 71081c69..8c396639 100644 --- a/src/LibHac/Fs/NullFile.cs +++ b/src/LibHac/Fs/NullFile.cs @@ -13,26 +13,34 @@ namespace LibHac.Fs private long Length { get; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { int toRead = ValidateReadParamsAndGetSize(destination, offset); destination.Slice(0, toRead).Clear(); - return toRead; + + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { + return Result.Success; } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() => Length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - throw new NotSupportedException(); + size = Length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperation.Log(); } } } diff --git a/src/LibHac/Fs/NullStorage.cs b/src/LibHac/Fs/NullStorage.cs index 83c6dbfe..5643e70b 100644 --- a/src/LibHac/Fs/NullStorage.cs +++ b/src/LibHac/Fs/NullStorage.cs @@ -12,19 +12,26 @@ namespace LibHac.Fs private long _length; - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { destination.Clear(); + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { + return Result.Success; } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } } } diff --git a/src/LibHac/Fs/NxFileStream.cs b/src/LibHac/Fs/NxFileStream.cs index 5720e81e..fd2a0852 100644 --- a/src/LibHac/Fs/NxFileStream.cs +++ b/src/LibHac/Fs/NxFileStream.cs @@ -13,21 +13,21 @@ namespace LibHac.Fs { BaseFile = baseFile; LeaveOpen = leaveOpen; - _length = baseFile.GetSize(); + + baseFile.GetSize(out _length).ThrowIfFailure(); } public override int Read(byte[] buffer, int offset, int count) { - int toRead = (int)Math.Min(count, Length - Position); - BaseFile.Read(buffer.AsSpan(offset, toRead), Position); + BaseFile.Read(out long bytesRead, Position, buffer.AsSpan(offset, count)); - Position += toRead; - return toRead; + Position += bytesRead; + return (int)bytesRead; } public override void Write(byte[] buffer, int offset, int count) { - BaseFile.Write(buffer.AsSpan(offset, count), Position); + BaseFile.Write(Position, buffer.AsSpan(offset, count)); Position += count; } @@ -57,9 +57,9 @@ namespace LibHac.Fs public override void SetLength(long value) { - BaseFile.SetSize(value); + BaseFile.SetSize(value).ThrowIfFailure(); - _length = BaseFile.GetSize(); + BaseFile.GetSize(out _length).ThrowIfFailure(); } public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read); diff --git a/src/LibHac/Fs/PartitionFile.cs b/src/LibHac/Fs/PartitionFile.cs index 44416dd4..1802ea87 100644 --- a/src/LibHac/Fs/PartitionFile.cs +++ b/src/LibHac/Fs/PartitionFile.cs @@ -16,44 +16,53 @@ namespace LibHac.Fs Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); long storageOffset = Offset + offset; - BaseStorage.Read(destination.Slice(0, toRead), storageOffset); + BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - BaseStorage.Flush(); + return BaseStorage.Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { if ((Mode & OpenMode.Write) != 0) { - BaseStorage.Flush(); + return BaseStorage.Flush(); } + + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInPartitionFileSetSize); + return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); } } } diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index 5eed802a..d997dd0f 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -32,11 +32,13 @@ namespace LibHac.Fs public void AddFile(string filename, IFile file) { + file.GetSize(out long fileSize).ThrowIfFailure(); + var entry = new Entry { Name = filename, File = file, - Length = file.GetSize(), + Length = fileSize, Offset = CurrentOffset, NameLength = Encoding.UTF8.GetByteCount(filename), HashOffset = 0, @@ -148,7 +150,12 @@ namespace LibHac.Fs if (entry.HashLength == 0) entry.HashLength = 0x200; var data = new byte[entry.HashLength]; - entry.File.Read(data, entry.HashOffset); + entry.File.Read(out long bytesRead, entry.HashOffset, data); + + if (bytesRead != entry.HashLength) + { + throw new ArgumentOutOfRangeException(); + } entry.Hash = sha.ComputeHash(data); } diff --git a/src/LibHac/Fs/ReadOnlyFile.cs b/src/LibHac/Fs/ReadOnlyFile.cs index 14064046..f98b8b24 100644 --- a/src/LibHac/Fs/ReadOnlyFile.cs +++ b/src/LibHac/Fs/ReadOnlyFile.cs @@ -11,22 +11,29 @@ namespace LibHac.Fs BaseFile = baseFile; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { - return BaseFile.Read(destination, offset, options); + return BaseFile.Read(out bytesRead, offset, destination, options); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseFile.GetSize(); + return BaseFile.GetSize(out size); } - public override void Flush() { } + public override Result Flush() + { + return Result.Success; + } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFile); + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + { + return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + } - public override void SetSize(long size) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFile); + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + } } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 4cc73c86..a3733289 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -87,8 +87,11 @@ public static Result InvalidOpenModeForWrite => new Result(ModuleFs, 6203); 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 UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310); public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324); public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325); public static Result UnsupportedOperationInConcatFsQueryEntry => new Result(ModuleFs, 6359); @@ -108,6 +111,7 @@ public static Result AllocationTableInsufficientFreeBlocks => new Result(ModuleFs, 6707); + public static Result Result6902 => new Result(ModuleFs, 6902); public static Result MountNameNotFound => new Result(ModuleFs, 6905); } } diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index 0d745d31..8d067e6e 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -47,7 +47,7 @@ namespace LibHac.Fs.RomFs public void AddFile(string path, IFile file) { var fileInfo = new RomFileInfo(); - long fileSize = file.GetSize(); + file.GetSize(out long fileSize).ThrowIfFailure(); fileInfo.Offset = CurrentOffset; fileInfo.Length = fileSize; @@ -81,7 +81,11 @@ namespace LibHac.Fs.RomFs sources.Add(new MemoryStorage(header)); sources.AddRange(Sources); - long fileLength = sources.Sum(x => x.GetSize()); + long fileLength = sources.Sum(x => + { + x.GetSize(out long fileSize).ThrowIfFailure(); + return fileSize; + }); headerWriter.Write((long)HeaderSize); diff --git a/src/LibHac/Fs/RomFs/RomFsFile.cs b/src/LibHac/Fs/RomFs/RomFsFile.cs index 30e8a0c0..5f58a54a 100644 --- a/src/LibHac/Fs/RomFs/RomFsFile.cs +++ b/src/LibHac/Fs/RomFs/RomFsFile.cs @@ -16,33 +16,41 @@ namespace LibHac.Fs.RomFs Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); long storageOffset = Offset + offset; - BaseStorage.Read(destination.Slice(0, toRead), storageOffset); - return toRead; + Result rc = BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; + + bytesRead = toRead; + + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFile); + return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFile); + return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } } } diff --git a/src/LibHac/Fs/Save/AllocationTable.cs b/src/LibHac/Fs/Save/AllocationTable.cs index ad85e744..c43ec471 100644 --- a/src/LibHac/Fs/Save/AllocationTable.cs +++ b/src/LibHac/Fs/Save/AllocationTable.cs @@ -356,7 +356,7 @@ namespace LibHac.Fs.Save Span buffer = MemoryMarshal.Cast(entries.Slice(0, entriesToRead)); - BaseStorage.Read(buffer, offset); + BaseStorage.Read(offset, buffer).ThrowIfFailure(); } private AllocationTableEntry ReadEntry(int entryIndex) @@ -364,7 +364,7 @@ namespace LibHac.Fs.Save Span bytes = stackalloc byte[EntrySize]; int offset = entryIndex * EntrySize; - BaseStorage.Read(bytes, offset); + BaseStorage.Read(offset, bytes).ThrowIfFailure(); return GetEntryFromBytes(bytes); } @@ -377,7 +377,7 @@ namespace LibHac.Fs.Save ref AllocationTableEntry newEntry = ref GetEntryFromBytes(bytes); newEntry = entry; - BaseStorage.Write(bytes, offset); + BaseStorage.Write(offset, bytes).ThrowIfFailure(); } // ReSharper disable once UnusedMember.Local diff --git a/src/LibHac/Fs/Save/AllocationTableStorage.cs b/src/LibHac/Fs/Save/AllocationTableStorage.cs index d210bd10..c15102b1 100644 --- a/src/LibHac/Fs/Save/AllocationTableStorage.cs +++ b/src/LibHac/Fs/Save/AllocationTableStorage.cs @@ -22,7 +22,7 @@ namespace LibHac.Fs.Save _length = initialBlock == -1 ? 0 : table.GetListLength(initialBlock) * blockSize; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { var iterator = new AllocationTableIterator(Fat, InitialBlock); @@ -41,15 +41,18 @@ namespace LibHac.Fs.Save int remainingInSegment = iterator.CurrentSegmentSize * BlockSize - segmentPos; int bytesToRead = Math.Min(remaining, remainingInSegment); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), physicalOffset); + Result rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { var iterator = new AllocationTableIterator(Fat, InitialBlock); @@ -68,27 +71,34 @@ namespace LibHac.Fs.Save int remainingInSegment = iterator.CurrentSegmentSize * BlockSize - segmentPos; int bytesToWrite = Math.Min(remaining, remainingInSegment); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), physicalOffset); + Result rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } - public override void SetSize(long size) + public override Result SetSize(long size) { int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize); int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize); - if (oldBlockCount == newBlockCount) return; + if (oldBlockCount == newBlockCount) return Result.Success; if (oldBlockCount == 0) { @@ -97,7 +107,7 @@ namespace LibHac.Fs.Save _length = newBlockCount * BlockSize; - return; + return Result.Success; } if (newBlockCount == 0) @@ -107,7 +117,7 @@ namespace LibHac.Fs.Save InitialBlock = int.MinValue; _length = 0; - return; + return Result.Success; } if (newBlockCount > oldBlockCount) @@ -124,6 +134,8 @@ namespace LibHac.Fs.Save } _length = newBlockCount * BlockSize; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/Save/DuplexStorage.cs b/src/LibHac/Fs/Save/DuplexStorage.cs index 890a519c..874af711 100644 --- a/src/LibHac/Fs/Save/DuplexStorage.cs +++ b/src/LibHac/Fs/Save/DuplexStorage.cs @@ -19,11 +19,13 @@ namespace LibHac.Fs.Save BitmapStorage = bitmap; BlockSize = blockSize; - Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmap.GetSize() * 8)); - _length = DataA.GetSize(); + bitmap.GetSize(out long bitmapSize).ThrowIfFailure(); + + Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmapSize * 8)); + DataA.GetSize(out _length).ThrowIfFailure(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -38,15 +40,18 @@ namespace LibHac.Fs.Save IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA; - data.Read(destination.Slice(outPos, bytesToRead), inPos); + Result rc = data.Read(inPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -61,26 +66,42 @@ namespace LibHac.Fs.Save IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA; - data.Write(source.Slice(outPos, bytesToWrite), inPos); + Result rc = data.Write(inPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BitmapStorage?.Flush(); - DataA?.Flush(); - DataB?.Flush(); + Result rc = BitmapStorage.Flush(); + if (rc.IsFailure()) return rc; + + rc = DataA.Flush(); + if (rc.IsFailure()) return rc; + + rc = DataB.Flush(); + if (rc.IsFailure()) return rc; + + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public void FsTrim() { - int blockCount = (int)(DataA.GetSize() / BlockSize); + DataA.GetSize(out long dataSize).ThrowIfFailure(); + + int blockCount = (int)(dataSize / BlockSize); for (int i = 0; i < blockCount; i++) { diff --git a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs b/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs index df24abd4..75c6ecc8 100644 --- a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs @@ -29,25 +29,29 @@ namespace LibHac.Fs.Save } DataLayer = Layers[Layers.Length - 1]; - _length = DataLayer.GetSize(); + DataLayer.GetSize(out _length).ThrowIfFailure(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - DataLayer.Read(destination, offset); + return DataLayer.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - DataLayer.Write(source, offset); + return DataLayer.Write(offset, source); } - public override void Flush() + public override Result Flush() { - DataLayer.Flush(); + return DataLayer.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public void FsTrim() { diff --git a/src/LibHac/Fs/Save/JournalStorage.cs b/src/LibHac/Fs/Save/JournalStorage.cs index 91e4f809..ba4ac0bf 100644 --- a/src/LibHac/Fs/Save/JournalStorage.cs +++ b/src/LibHac/Fs/Save/JournalStorage.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs.Save if (!leaveOpen) ToDispose.Add(baseStorage); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -46,15 +46,18 @@ namespace LibHac.Fs.Save int bytesToRead = Math.Min(remaining, BlockSize - blockPos); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), physicalOffset); + Result rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -69,20 +72,27 @@ namespace LibHac.Fs.Save int bytesToWrite = Math.Min(remaining, BlockSize - blockPos); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), physicalOffset); + Result rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/Fs/Save/RemapStorage.cs b/src/LibHac/Fs/Save/RemapStorage.cs index d1de2442..885691f4 100644 --- a/src/LibHac/Fs/Save/RemapStorage.cs +++ b/src/LibHac/Fs/Save/RemapStorage.cs @@ -46,9 +46,9 @@ namespace LibHac.Fs.Save Segments = InitSegments(Header, MapEntries); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - if (destination.Length == 0) return; + if (destination.Length == 0) return Result.Success; MapEntry entry = GetMapEntry(offset); @@ -61,7 +61,7 @@ namespace LibHac.Fs.Save long entryPos = inPos - entry.VirtualOffset; int bytesToRead = (int)Math.Min(entry.VirtualOffsetEnd - inPos, remaining); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), entry.PhysicalOffset + entryPos); + BaseStorage.Read(entry.PhysicalOffset + entryPos, destination.Slice(outPos, bytesToRead)); outPos += bytesToRead; inPos += bytesToRead; @@ -72,11 +72,13 @@ namespace LibHac.Fs.Save entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - if (source.Length == 0) return; + if (source.Length == 0) return Result.Success; MapEntry entry = GetMapEntry(offset); @@ -89,7 +91,9 @@ namespace LibHac.Fs.Save long entryPos = inPos - entry.VirtualOffset; int bytesToWrite = (int)Math.Min(entry.VirtualOffsetEnd - inPos, remaining); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), entry.PhysicalOffset + entryPos); + + Result rc = BaseStorage.Write(entry.PhysicalOffset + entryPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; @@ -100,14 +104,21 @@ namespace LibHac.Fs.Save entry = entry.Next; } } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => -1; + public override Result GetSize(out long size) + { + // todo: Different result code + size = -1; + return Result.Success; + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); @@ -199,7 +210,7 @@ namespace LibHac.Fs.Save public class RemapHeader { public string Magic { get; } - public uint Verison { get; } + public uint Version { get; } public int MapEntryCount { get; } public int MapSegmentCount { get; } public int SegmentBits { get; } @@ -209,7 +220,7 @@ namespace LibHac.Fs.Save var reader = new BinaryReader(storage.AsStream()); Magic = reader.ReadAscii(4); - Verison = reader.ReadUInt32(); + Version = reader.ReadUInt32(); MapEntryCount = reader.ReadInt32(); MapSegmentCount = reader.ReadInt32(); SegmentBits = reader.ReadInt32(); diff --git a/src/LibHac/Fs/Save/SaveDataFile.cs b/src/LibHac/Fs/Save/SaveDataFile.cs index c6ba6bf1..784350d9 100644 --- a/src/LibHac/Fs/Save/SaveDataFile.cs +++ b/src/LibHac/Fs/Save/SaveDataFile.cs @@ -19,43 +19,51 @@ namespace LibHac.Fs.Save Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + BaseStorage.Write(offset, source); if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); - if (Size == size) return; + if (Size == size) return Result.Success; - BaseStorage.SetSize(size); + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; if (!FileTable.TryOpenFile(Path, out SaveFileInfo fileInfo)) { @@ -68,6 +76,8 @@ namespace LibHac.Fs.Save FileTable.AddFile(Path, ref fileInfo); Size = size; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/Save/SaveFsList.cs b/src/LibHac/Fs/Save/SaveFsList.cs index 0bf9d428..7870b119 100644 --- a/src/LibHac/Fs/Save/SaveFsList.cs +++ b/src/LibHac/Fs/Save/SaveFsList.cs @@ -101,10 +101,10 @@ namespace LibHac.Fs.Save if (capacity == 0 || length >= capacity) { - long currentSize = Storage.GetSize(); + Storage.GetSize(out long currentSize).ThrowIfFailure(); Storage.SetSize(currentSize + CapacityIncrement); - long newSize = Storage.GetSize(); + Storage.GetSize(out long newSize).ThrowIfFailure(); SetListCapacity((int)(newSize / _sizeOfEntry)); } @@ -282,7 +282,7 @@ namespace LibHac.Fs.Save private int GetListCapacity() { Span buf = stackalloc byte[sizeof(int)]; - Storage.Read(buf, 4); + Storage.Read(4, buf).ThrowIfFailure(); return MemoryMarshal.Read(buf); } @@ -290,7 +290,7 @@ namespace LibHac.Fs.Save private int GetListLength() { Span buf = stackalloc byte[sizeof(int)]; - Storage.Read(buf, 0); + Storage.Read(0, buf).ThrowIfFailure(); return MemoryMarshal.Read(buf); } @@ -300,7 +300,7 @@ namespace LibHac.Fs.Save Span buf = stackalloc byte[sizeof(int)]; MemoryMarshal.Write(buf, ref capacity); - Storage.Write(buf, 4); + Storage.Write(4, buf).ThrowIfFailure(); } private void SetListLength(int length) @@ -308,7 +308,7 @@ namespace LibHac.Fs.Save Span buf = stackalloc byte[sizeof(int)]; MemoryMarshal.Write(buf, ref length); - Storage.Write(buf, 0); + Storage.Write(0, buf).ThrowIfFailure(); } private void ReadEntry(int index, out SaveFsEntry entry) @@ -352,7 +352,7 @@ namespace LibHac.Fs.Save Debug.Assert(entry.Length == _sizeOfEntry); int offset = index * _sizeOfEntry; - Storage.Read(entry, offset); + Storage.Read(offset, entry); } private void WriteEntry(int index, Span entry) @@ -360,7 +360,7 @@ namespace LibHac.Fs.Save Debug.Assert(entry.Length == _sizeOfEntry); int offset = index * _sizeOfEntry; - Storage.Write(entry, offset); + Storage.Write(offset, entry); } private ref SaveFsEntry GetEntryFromBytes(Span entry) diff --git a/src/LibHac/Fs/SectorStorage.cs b/src/LibHac/Fs/SectorStorage.cs index 7e3efee7..16ef4898 100644 --- a/src/LibHac/Fs/SectorStorage.cs +++ b/src/LibHac/Fs/SectorStorage.cs @@ -15,37 +15,50 @@ namespace LibHac.Fs { BaseStorage = baseStorage; SectorSize = sectorSize; - SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); - _length = BaseStorage.GetSize(); + + baseStorage.GetSize(out long baseSize).ThrowIfFailure(); + + SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize); + _length = baseSize; if (!leaveOpen) ToDispose.Add(BaseStorage); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { ValidateSize(destination.Length, offset); - BaseStorage.Read(destination, offset); + return BaseStorage.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { ValidateSize(source.Length, offset); - BaseStorage.Write(source, offset); + return BaseStorage.Write(offset, source); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseStorage.SetSize(size); + size = _length; + return Result.Success; + } - SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); - _length = BaseStorage.GetSize(); + public override Result SetSize(long size) + { + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; + + rc = BaseStorage.GetSize(out long newSize); + if (rc.IsFailure()) return rc; + + SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize); + _length = newSize; + + return Result.Success; } /// diff --git a/src/LibHac/Fs/StorageExtensions.cs b/src/LibHac/Fs/StorageExtensions.cs index 16340ecf..a1f64dc7 100644 --- a/src/LibHac/Fs/StorageExtensions.cs +++ b/src/LibHac/Fs/StorageExtensions.cs @@ -7,15 +7,16 @@ namespace LibHac.Fs { public static class StorageExtensions { - public static void Read(this IStorage storage, byte[] buffer, long offset, int count, int bufferOffset) + public static Result Read(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset) { ValidateStorageParameters(buffer, offset, count, bufferOffset); - storage.Read(buffer.AsSpan(bufferOffset, count), offset); + return storage.Read(offset, buffer.AsSpan(bufferOffset, count)); } - public static void Write(this IStorage storage, byte[] buffer, long offset, int count, int bufferOffset) + + public static Result Write(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset) { ValidateStorageParameters(buffer, offset, count, bufferOffset); - storage.Write(buffer.AsSpan(bufferOffset, count), offset); + return storage.Write(offset, buffer.AsSpan(bufferOffset, count)); } private static void ValidateStorageParameters(byte[] buffer, long offset, int count, int bufferOffset) @@ -28,7 +29,7 @@ namespace LibHac.Fs public static IStorage Slice(this IStorage storage, long start) { - long length = storage.GetSize(); + storage.GetSize(out long length).ThrowIfFailure(); if (length == -1) { @@ -53,10 +54,10 @@ namespace LibHac.Fs return storage.AsReadOnly(true); } - // Todo: Move out of SubStorage public static IStorage AsReadOnly(this IStorage storage, bool leaveOpen) { - return new SubStorage(storage, 0, storage.GetSize(), leaveOpen, FileAccess.Read); + storage.GetSize(out long storageSize).ThrowIfFailure(); + return new SubStorage(storage, 0, storageSize, leaveOpen, FileAccess.Read); } public static Stream AsStream(this IStorage storage) => new StorageStream(storage, FileAccess.ReadWrite, true); @@ -68,7 +69,11 @@ namespace LibHac.Fs public static void CopyTo(this IStorage input, IStorage output, IProgressReport progress = null) { const int bufferSize = 81920; - long remaining = Math.Min(input.GetSize(), output.GetSize()); + + input.GetSize(out long inputSize).ThrowIfFailure(); + output.GetSize(out long outputSize).ThrowIfFailure(); + + long remaining = Math.Min(inputSize, outputSize); if (remaining < 0) throw new ArgumentException("Storage must have an explicit length"); progress?.SetTotal(remaining); @@ -81,8 +86,8 @@ namespace LibHac.Fs { int toCopy = (int)Math.Min(bufferSize, remaining); Span buf = buffer.AsSpan(0, toCopy); - input.Read(buf, pos); - output.Write(buf, pos); + input.Read(pos, buf); + output.Write(pos, buf); remaining -= toCopy; pos += toCopy; @@ -100,7 +105,8 @@ namespace LibHac.Fs public static void Fill(this IStorage input, byte value, IProgressReport progress = null) { - input.Fill(value, 0, input.GetSize(), progress); + input.GetSize(out long inputSize).ThrowIfFailure(); + input.Fill(value, 0, inputSize, progress); } public static void Fill(this IStorage input, byte value, long offset, long count, IProgressReport progress = null) @@ -116,7 +122,7 @@ namespace LibHac.Fs Span buf = stackalloc byte[(int)count]; buf.Fill(value); - input.Write(buf, offset); + input.Write(offset, buf); } private static void FillLarge(this IStorage input, byte value, long offset, long count, IProgressReport progress = null) @@ -139,7 +145,7 @@ namespace LibHac.Fs int toFill = (int)Math.Min(bufferSize, remaining); Span buf = buffer.AsSpan(0, toFill); - input.Write(buf, pos); + input.Write(pos, buf); remaining -= toFill; pos += toFill; @@ -157,9 +163,11 @@ namespace LibHac.Fs public static void WriteAllBytes(this IStorage input, string filename, IProgressReport progress = null) { + input.GetSize(out long inputSize).ThrowIfFailure(); + using (var outFile = new FileStream(filename, FileMode.Create, FileAccess.Write)) { - input.CopyToStream(outFile, input.GetSize(), progress); + input.CopyToStream(outFile, inputSize, progress); } } @@ -167,7 +175,9 @@ namespace LibHac.Fs { if (storage == null) return new byte[0]; - var arr = new byte[storage.GetSize()]; + storage.GetSize(out long storageSize).ThrowIfFailure(); + + var arr = new byte[storageSize]; storage.CopyTo(new MemoryStorage(arr)); return arr; } @@ -176,10 +186,12 @@ namespace LibHac.Fs { if (storage == null) return new T[0]; - var arr = new T[storage.GetSize() / Marshal.SizeOf()]; + storage.GetSize(out long storageSize).ThrowIfFailure(); + + var arr = new T[storageSize / Marshal.SizeOf()]; Span dest = MemoryMarshal.Cast(arr.AsSpan()); - storage.Read(dest, 0); + storage.Read(0, dest); return arr; } @@ -194,7 +206,7 @@ namespace LibHac.Fs while (remaining > 0) { int toWrite = (int)Math.Min(buffer.Length, remaining); - input.Read(buffer.AsSpan(0, toWrite), inOffset); + input.Read(inOffset, buffer.AsSpan(0, toWrite)); output.Write(buffer, 0, toWrite); remaining -= toWrite; @@ -203,7 +215,11 @@ namespace LibHac.Fs } } - public static void CopyToStream(this IStorage input, Stream output) => CopyToStream(input, output, input.GetSize()); + public static void CopyToStream(this IStorage input, Stream output) + { + input.GetSize(out long inputSize).ThrowIfFailure(); + CopyToStream(input, output, inputSize); + } public static IStorage AsStorage(this Stream stream) { diff --git a/src/LibHac/Fs/StorageFile.cs b/src/LibHac/Fs/StorageFile.cs index ce362ebe..176abdc5 100644 --- a/src/LibHac/Fs/StorageFile.cs +++ b/src/LibHac/Fs/StorageFile.cs @@ -12,40 +12,46 @@ namespace LibHac.Fs Mode = mode; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseStorage.GetSize(); + return BaseStorage.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { - BaseStorage.SetSize(size); + return BaseStorage.SetSize(size); } } } diff --git a/src/LibHac/Fs/StorageStream.cs b/src/LibHac/Fs/StorageStream.cs index bbd3d6e9..85cbef72 100644 --- a/src/LibHac/Fs/StorageStream.cs +++ b/src/LibHac/Fs/StorageStream.cs @@ -13,7 +13,8 @@ namespace LibHac.Fs { BaseStorage = baseStorage; LeaveOpen = leaveOpen; - _length = baseStorage.GetSize(); + + baseStorage.GetSize(out _length).ThrowIfFailure(); CanRead = access.HasFlag(FileAccess.Read); CanWrite = access.HasFlag(FileAccess.Write); @@ -22,7 +23,7 @@ namespace LibHac.Fs public override int Read(byte[] buffer, int offset, int count) { int toRead = (int)Math.Min(count, Length - Position); - BaseStorage.Read(buffer.AsSpan(offset, toRead), Position); + BaseStorage.Read(Position, buffer.AsSpan(offset, toRead)).ThrowIfFailure(); Position += toRead; return toRead; @@ -30,7 +31,7 @@ namespace LibHac.Fs public override void Write(byte[] buffer, int offset, int count) { - BaseStorage.Write(buffer.AsSpan(offset, count), Position); + BaseStorage.Write(Position, buffer.AsSpan(offset, count)).ThrowIfFailure(); Position += count; } @@ -59,9 +60,9 @@ namespace LibHac.Fs public override void SetLength(long value) { - BaseStorage.SetSize(value); + BaseStorage.SetSize(value).ThrowIfFailure(); - _length = BaseStorage.GetSize(); + BaseStorage.GetSize(out _length).ThrowIfFailure(); } public override bool CanRead { get; } diff --git a/src/LibHac/Fs/StreamFile.cs b/src/LibHac/Fs/StreamFile.cs index e81b642f..ba7305db 100644 --- a/src/LibHac/Fs/StreamFile.cs +++ b/src/LibHac/Fs/StreamFile.cs @@ -12,6 +12,8 @@ namespace LibHac.Fs /// public class StreamFile : FileBase { + // todo: handle Stream exceptions + private Stream BaseStream { get; } private object Locker { get; } = new object(); @@ -21,7 +23,7 @@ namespace LibHac.Fs Mode = mode; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { #if STREAM_SPAN lock (Locker) @@ -31,13 +33,13 @@ namespace LibHac.Fs BaseStream.Position = offset; } - return BaseStream.Read(destination); + bytesRead = BaseStream.Read(destination); + return Result.Success; } #else byte[] buffer = ArrayPool.Shared.Rent(destination.Length); try { - int bytesRead; lock (Locker) { if (BaseStream.Position != offset) @@ -50,13 +52,13 @@ namespace LibHac.Fs new Span(buffer, 0, destination.Length).CopyTo(destination); - return bytesRead; + return Result.Success; } finally { ArrayPool.Shared.Return(buffer); } #endif } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { #if STREAM_SPAN lock (Locker) @@ -81,31 +83,36 @@ namespace LibHac.Fs if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Locker) { BaseStream.Flush(); + return Result.Success; } } - public override long GetSize() + public override Result GetSize(out long size) { lock (Locker) { - return BaseStream.Length; + size = BaseStream.Length; + return Result.Success; } } - public override void SetSize(long size) + public override Result SetSize(long size) { lock (Locker) { BaseStream.SetLength(size); + return Result.Success; } } } diff --git a/src/LibHac/Fs/StreamStorage.cs b/src/LibHac/Fs/StreamStorage.cs index 154caa51..4784da48 100644 --- a/src/LibHac/Fs/StreamStorage.cs +++ b/src/LibHac/Fs/StreamStorage.cs @@ -9,6 +9,8 @@ namespace LibHac.Fs { public class StreamStorage : StorageBase { + // todo: handle Stream exceptions + private Stream BaseStream { get; } private object Locker { get; } = new object(); private long _length; @@ -20,7 +22,7 @@ namespace LibHac.Fs if (!leaveOpen) ToDispose.Add(BaseStream); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { #if STREAM_SPAN lock (Locker) @@ -50,9 +52,11 @@ namespace LibHac.Fs } finally { ArrayPool.Shared.Return(buffer); } #endif + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { #if STREAM_SPAN lock (Locker) @@ -82,16 +86,24 @@ namespace LibHac.Fs } finally { ArrayPool.Shared.Return(buffer); } #endif + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Locker) { BaseStream.Flush(); + + return Result.Success; } } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } } } diff --git a/src/LibHac/Fs/SubStorage.cs b/src/LibHac/Fs/SubStorage.cs index 710cce14..144b7ab0 100644 --- a/src/LibHac/Fs/SubStorage.cs +++ b/src/LibHac/Fs/SubStorage.cs @@ -36,41 +36,53 @@ namespace LibHac.Fs Access = access; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { if ((Access & FileAccess.Read) == 0) throw new InvalidOperationException("Storage is not readable"); - BaseStorage.Read(destination, offset + Offset); + return BaseStorage.Read(offset + Offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { if ((Access & FileAccess.Write) == 0) throw new InvalidOperationException("Storage is not writable"); - BaseStorage.Write(source, offset + Offset); + return BaseStorage.Write(offset + Offset, source); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - //if (!IsResizable) - // return 0x313802; + size = _length; + return Result.Success; + } - //if (Offset < 0 || size < 0) - // return 0x2F5C02; + public override Result SetSize(long size) + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); - if (BaseStorage.GetSize() != Offset + _length) + // todo: Add IsResizable member + // if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); + + if (Offset < 0 || size < 0) return ResultFs.InvalidSize.Log(); + + Result rc = BaseStorage.GetSize(out long baseSize); + if (rc.IsFailure()) return rc; + + if (baseSize != Offset + _length) { - throw new NotSupportedException("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(); } - BaseStorage.SetSize(Offset + size); + rc = BaseStorage.SetSize(Offset + size); + if (rc.IsFailure()) return rc; _length = size; + + return Result.Success; } } } diff --git a/src/LibHac/FsClient/Accessors/FileAccessor.cs b/src/LibHac/FsClient/Accessors/FileAccessor.cs index f69bec1f..9624c6ec 100644 --- a/src/LibHac/FsClient/Accessors/FileAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileAccessor.cs @@ -12,8 +12,9 @@ namespace LibHac.FsClient.Accessors public OpenMode OpenMode { get; } // Todo: Consider removing Mode from interface because OpenMode is in FileAccessor + // Todo: Set WriteState to Error based on returned results OpenMode IFile.Mode => OpenMode; - + public FileAccessor(IFile baseFile, FileSystemAccessor parent, OpenMode mode) { File = baseFile; @@ -21,14 +22,14 @@ namespace LibHac.FsClient.Accessors OpenMode = mode; } - public int Read(Span destination, long offset, ReadOption options) + public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { CheckIfDisposed(); - return File.Read(destination, offset, options); + return File.Read(out bytesRead, offset, destination, options); } - public void Write(ReadOnlySpan source, long offset, WriteOption options) + public Result Write(long offset, ReadOnlySpan source, WriteOption options) { CheckIfDisposed(); @@ -36,35 +37,46 @@ namespace LibHac.FsClient.Accessors { WriteState = (WriteState)(~options & WriteOption.Flush); - return; + return Result.Success; } - File.Write(source, offset, options); + // + Result rc = File.Write(offset, source, options); - WriteState = (WriteState)(~options & WriteOption.Flush); + if (rc.IsSuccess()) + { + WriteState = (WriteState)(~options & WriteOption.Flush); + } + + return rc; } - public void Flush() + public Result Flush() { CheckIfDisposed(); - File.Flush(); + Result rc = File.Flush(); - WriteState = WriteState.None; + if (rc.IsSuccess()) + { + WriteState = WriteState.None; + } + + return rc; } - public long GetSize() + public Result GetSize(out long size) { CheckIfDisposed(); - return File.GetSize(); + return File.GetSize(out size); } - public void SetSize(long size) + public Result SetSize(long size) { CheckIfDisposed(); - File.SetSize(size); + return File.SetSize(size); } public void Dispose() @@ -75,7 +87,7 @@ namespace LibHac.FsClient.Accessors { // Original FS code would return an error: // ThrowHelper.ThrowResult(ResultsFs.ResultFsWriteStateUnflushed); - + Flush(); } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index ecd228d0..10ca268f 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -364,22 +364,22 @@ namespace LibHac.FsClient public int ReadFile(FileHandle handle, Span destination, long offset, ReadOption option) { - int bytesRead; + long bytesRead; if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - bytesRead = handle.File.Read(destination, offset, option); + handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); } else { - bytesRead = handle.File.Read(destination, offset, option); + handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); } - return bytesRead; + return (int)bytesRead; } public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset) @@ -392,7 +392,7 @@ namespace LibHac.FsClient if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Write(source, offset, option); + handle.File.Write(offset, source, option); TimeSpan endTime = Time.GetCurrent(); string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; @@ -401,7 +401,7 @@ namespace LibHac.FsClient } else { - handle.File.Write(source, offset, option); + handle.File.Write(offset, source, option); } } @@ -423,7 +423,9 @@ namespace LibHac.FsClient public long GetFileSize(FileHandle handle) { - return handle.File.GetSize(); + handle.File.GetSize(out long fileSize).ThrowIfFailure(); + + return fileSize; } public void SetFileSize(FileHandle handle, long size) @@ -501,16 +503,16 @@ namespace LibHac.FsClient handle.Directory.Dispose(); } } - + internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) { fileSystem = default; - Result result = GetMountName(path, out ReadOnlySpan mountName, out subPath); - if (result.IsFailure()) return result; + Result rc = GetMountName(path, out ReadOnlySpan mountName, out subPath); + if (rc.IsFailure()) return rc; - result = MountTable.Find(mountName.ToString(), out fileSystem); - if (result.IsFailure()) return result; + rc = MountTable.Find(mountName.ToString(), out fileSystem); + if (rc.IsFailure()) return rc; return Result.Success; } diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs index 3f9c4d99..edba44ca 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -37,10 +37,10 @@ namespace LibHac.FsService.Creators string partitionPath = GetPartitionPath(partitionId); - Result subFsResult = + Result rc = Util.CreateSubFileSystem(out IFileSystem subFileSystem, Config.RootFileSystem, partitionPath, true); - if (subFsResult.IsFailure()) return subFsResult; + if (rc.IsFailure()) return rc; if (rootPath == string.Empty) { diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index f43fca19..80da9c15 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -103,9 +103,9 @@ namespace LibHac.FsService if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); - Result saveFsResult = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, + Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, attribute, false, true); - if (saveFsResult.IsFailure()) return saveFsResult.Log(); + if (rc.IsFailure()) return rc; // Missing check if the current title owns the save data or can open it @@ -121,8 +121,8 @@ namespace LibHac.FsService // Missing permission check - Result res = FsProxyCore.SetSdCardEncryptionSeed(seed); - if (res.IsFailure()) return res; + Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed); + if (rc.IsFailure()) return rc; // todo: Reset save data indexer diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 6f1a67a7..8c3e0e16 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -35,35 +35,35 @@ namespace LibHac.FsService string contentDirPath = default; IFileSystem baseFileSystem = default; bool isEncrypted = false; - Result baseFsResult; + Result rc; switch (storageId) { case ContentStorageId.System: - baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); + rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); contentDirPath = $"/{ContentDirectoryName}"; break; case ContentStorageId.User: - baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); + rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); contentDirPath = $"/{ContentDirectoryName}"; break; case ContentStorageId.SdCard: - baseFsResult = OpenSdCardFileSystem(out baseFileSystem); + rc = OpenSdCardFileSystem(out baseFileSystem); contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}"; isEncrypted = true; break; default: - baseFsResult = ResultFs.InvalidArgument; + rc = ResultFs.InvalidArgument; break; } - if (baseFsResult.IsFailure()) return baseFsResult; + if (rc.IsFailure()) return rc; baseFileSystem.EnsureDirectoryExists(contentDirPath); - Result subFsResult = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, + rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, baseFileSystem, contentDirPath); - if (subFsResult.IsFailure()) return subFsResult; + if (rc.IsFailure()) return rc; if (!isEncrypted) { @@ -93,8 +93,8 @@ namespace LibHac.FsService { fileSystem = default; - Result openSaveDirResult = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true); - if (openSaveDirResult.IsFailure()) return openSaveDirResult.Log(); + Result rc = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true); + if (rc.IsFailure()) return rc; bool allowDirectorySaveData = AllowDirectorySaveData(spaceId, saveDataRootPath); bool useDeviceUniqueMac = Util.UseDeviceUniqueSaveMac(spaceId); @@ -113,11 +113,11 @@ namespace LibHac.FsService // Missing save FS cache lookup - Result saveFsResult = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, + rc = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, out ISaveDataExtraDataAccessor extraDataAccessor, saveDirFs, saveDataId, allowDirectorySaveData, useDeviceUniqueMac, type, null); - if (saveFsResult.IsFailure()) return saveFsResult.Log(); + if (rc.IsFailure()) return rc; if (cacheExtraData) { @@ -133,12 +133,12 @@ namespace LibHac.FsService { if (openOnHostFs && AllowDirectorySaveData(spaceId, saveDataRootPath)) { - Result hostFsResult = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false); + Result rc = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false); - if (hostFsResult.IsFailure()) + if (rc.IsFailure()) { fileSystem = default; - return hostFsResult.Log(); + return rc; } return Util.CreateSubFileSystem(out fileSystem, hostFs, saveDataRootPath, true); @@ -152,44 +152,45 @@ namespace LibHac.FsService public Result OpenSaveDataDirectoryImpl(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDirName, bool createIfMissing) { fileSystem = default; + Result rc; switch (spaceId) { case SaveDataSpaceId.System: - Result sysFsResult = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System); - if (sysFsResult.IsFailure()) return sysFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, sysFs, saveDirName, createIfMissing); case SaveDataSpaceId.User: case SaveDataSpaceId.TemporaryStorage: - Result userFsResult = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.System); - if (userFsResult.IsFailure()) return userFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.User); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, userFs, saveDirName, createIfMissing); case SaveDataSpaceId.SdSystem: case SaveDataSpaceId.SdCache: - Result sdFsResult = OpenSdCardFileSystem(out IFileSystem sdFs); - if (sdFsResult.IsFailure()) return sdFsResult.Log(); + rc = OpenSdCardFileSystem(out IFileSystem sdFs); + if (rc.IsFailure()) return rc; string sdSaveDirPath = $"/{NintendoDirectoryName}{saveDirName}"; - Result sdSubResult = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing); - if (sdSubResult.IsFailure()) return sdSubResult.Log(); + rc = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing); + if (rc.IsFailure()) return rc; return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, sdSubFs, EncryptedFsKeyId.Save, SdEncryptionSeed); case SaveDataSpaceId.ProperSystem: - Result sysProperFsResult = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition); - if (sysProperFsResult.IsFailure()) return sysProperFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, sysProperFs, saveDirName, createIfMissing); case SaveDataSpaceId.Safe: - Result safeFsResult = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode); - if (safeFsResult.IsFailure()) return safeFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, safeFs, saveDirName, createIfMissing); diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs index 39b5538a..d48e625e 100644 --- a/src/LibHac/Keyset.cs +++ b/src/LibHac/Keyset.cs @@ -198,7 +198,7 @@ namespace LibHac using (var keyblobDec = new Aes128CtrStorage( new MemoryStorage(EncryptedKeyblobs[i], 0x20, Keyblobs[i].Length), KeyblobKeys[i], counter, false)) { - keyblobDec.Read(Keyblobs[i], 0); + keyblobDec.Read(0, Keyblobs[i]).ThrowIfFailure(); } } } diff --git a/src/LibHac/Kip.cs b/src/LibHac/Kip.cs index 0c154694..f007713d 100644 --- a/src/LibHac/Kip.cs +++ b/src/LibHac/Kip.cs @@ -43,9 +43,11 @@ namespace LibHac public byte[] DecompressSection(int index) { - IStorage compStream = OpenSection(index); - var compressed = new byte[compStream.GetSize()]; - compStream.Read(compressed, 0); + IStorage compStorage = OpenSection(index); + compStorage.GetSize(out long compressedSize).ThrowIfFailure(); + + var compressed = new byte[compressedSize]; + compStorage.Read(0, compressed).ThrowIfFailure(); return DecompressBlz(compressed); } diff --git a/src/LibHac/Kvdb/ImkvdbReader.cs b/src/LibHac/Kvdb/ImkvdbReader.cs index 28556809..e0d96df1 100644 --- a/src/LibHac/Kvdb/ImkvdbReader.cs +++ b/src/LibHac/Kvdb/ImkvdbReader.cs @@ -58,8 +58,8 @@ namespace LibHac.Kvdb key = default; value = default; - Result sizeResult = GetEntrySize(out int keySize, out int valueSize); - if (sizeResult.IsFailure()) return sizeResult; + Result rc = GetEntrySize(out int keySize, out int valueSize); + if (rc.IsFailure()) return rc; _position += Unsafe.SizeOf(); diff --git a/src/LibHac/Kvdb/KeyValueDatabase.cs b/src/LibHac/Kvdb/KeyValueDatabase.cs index f92d00fe..e2043074 100644 --- a/src/LibHac/Kvdb/KeyValueDatabase.cs +++ b/src/LibHac/Kvdb/KeyValueDatabase.cs @@ -37,13 +37,13 @@ namespace LibHac.Kvdb { var reader = new ImkvdbReader(data); - Result headerResult = reader.ReadHeader(out int entryCount); - if (headerResult.IsFailure()) return headerResult; + Result rc = reader.ReadHeader(out int entryCount); + if (rc.IsFailure()) return rc; for (int i = 0; i < entryCount; i++) { - Result entryResult = reader.ReadEntry(out ReadOnlySpan keyBytes, out ReadOnlySpan valueBytes); - if (entryResult.IsFailure()) return entryResult; + rc = reader.ReadEntry(out ReadOnlySpan keyBytes, out ReadOnlySpan valueBytes); + if (rc.IsFailure()) return rc; var key = new TKey(); var value = new TValue(); diff --git a/src/LibHac/Nro.cs b/src/LibHac/Nro.cs index 2e09ea80..c3e301db 100644 --- a/src/LibHac/Nro.cs +++ b/src/LibHac/Nro.cs @@ -21,7 +21,9 @@ namespace LibHac if (Header.Magic != "NRO0") throw new InvalidDataException("NRO0 magic is incorrect!"); - if (Header.Size < Storage.GetSize()) + Storage.GetSize(out long storageSize).ThrowIfFailure(); + + if (Header.Size < storageSize) { AssetStorage = Storage.Slice(Header.Size); var assetReader = new BinaryReader(AssetStorage.AsStream()); diff --git a/src/LibHac/Nso.cs b/src/LibHac/Nso.cs index d60a76ca..53c35063 100644 --- a/src/LibHac/Nso.cs +++ b/src/LibHac/Nso.cs @@ -82,7 +82,7 @@ namespace LibHac public byte[] DecompressSection() { var compressed = new byte[CompressedSize]; - OpenSection().Read(compressed, 0); + OpenSection().Read(0, compressed).ThrowIfFailure(); if (IsCompressed) return Lz4.Decompress(compressed, (int)DecompressedSize); diff --git a/src/LibHac/Package1.cs b/src/LibHac/Package1.cs index 6f57cf98..0c4efc20 100644 --- a/src/LibHac/Package1.cs +++ b/src/LibHac/Package1.cs @@ -40,7 +40,7 @@ namespace LibHac for (int i = 0; i < 0x20; i++) { var dec = new Aes128CtrStorage(encStorage, keyset.Package1Keys[i], Counter, true); - dec.Read(decBuffer, 0); + dec.Read(0, decBuffer).ThrowIfFailure(); if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic) { diff --git a/src/LibHac/Package2.cs b/src/LibHac/Package2.cs index 9714bc25..943dab71 100644 --- a/src/LibHac/Package2.cs +++ b/src/LibHac/Package2.cs @@ -109,12 +109,12 @@ namespace LibHac var counter = new byte[0x10]; var decBuffer = new byte[0x10]; - storage.Read(counter, 0x100); + storage.Read(0x100, counter).ThrowIfFailure(); for (int i = 0; i < 0x20; i++) { var dec = new Aes128CtrStorage(storage.Slice(0x100), keyset.Package2Keys[i], counter, false); - dec.Read(decBuffer, 0x50); + dec.Read(0x50, decBuffer).ThrowIfFailure(); if (BitConverter.ToUInt32(decBuffer, 0) == Pk21Magic) { diff --git a/src/hactoolnet/ProcessBench.cs b/src/hactoolnet/ProcessBench.cs index b68776a2..185006a4 100644 --- a/src/hactoolnet/ProcessBench.cs +++ b/src/hactoolnet/ProcessBench.cs @@ -25,7 +25,9 @@ namespace hactoolnet encryptWatch.Stop(); logger.SetTotal(0); - string rate = Util.GetBytesReadable((long)(src.GetSize() * iterations / encryptWatch.Elapsed.TotalSeconds)); + src.GetSize(out long srcSize).ThrowIfFailure(); + + string rate = Util.GetBytesReadable((long)(srcSize * iterations / encryptWatch.Elapsed.TotalSeconds)); logger.LogMessage($"{label}{rate}/s"); } diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index e59666c4..d8c1c4b7 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -19,7 +19,7 @@ namespace hactoolnet { IStorage deltaStorage = deltaFile; Span magic = stackalloc byte[4]; - deltaFile.Read(magic, 0); + deltaFile.Read(0, magic).ThrowIfFailure(); if (MemoryMarshal.Read(magic) != Ndv0Magic) { @@ -51,7 +51,9 @@ namespace hactoolnet using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { IStorage patchedStorage = delta.GetPatchedStorage(); - patchedStorage.CopyToStream(outFile, patchedStorage.GetSize(), ctx.Logger); + patchedStorage.GetSize(out long patchedStorageSize).ThrowIfFailure(); + + patchedStorage.CopyToStream(outFile, patchedStorageSize, ctx.Logger); } } } diff --git a/src/hactoolnet/ProcessFsBuild.cs b/src/hactoolnet/ProcessFsBuild.cs index 5d0d06ab..05a969f2 100644 --- a/src/hactoolnet/ProcessFsBuild.cs +++ b/src/hactoolnet/ProcessFsBuild.cs @@ -17,13 +17,15 @@ namespace hactoolnet var localFs = new LocalFileSystem(ctx.Options.InFile); var builder = new RomFsBuilder(localFs); - IStorage romfs = builder.Build(); + IStorage romFs = builder.Build(); ctx.Logger.LogMessage($"Building RomFS as {ctx.Options.OutFile}"); + romFs.GetSize(out long romFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.Create, FileAccess.ReadWrite)) { - romfs.CopyToStream(outFile, romfs.GetSize(), ctx.Logger); + romFs.CopyToStream(outFile, romFsSize, ctx.Logger); } ctx.Logger.LogMessage($"Finished writing {ctx.Options.OutFile}"); @@ -48,9 +50,11 @@ namespace hactoolnet ctx.Logger.LogMessage($"Building Partition FS as {ctx.Options.OutFile}"); + partitionFs.GetSize(out long partitionFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.Create, FileAccess.ReadWrite)) { - partitionFs.CopyToStream(outFile, partitionFs.GetSize(), ctx.Logger); + partitionFs.CopyToStream(outFile, partitionFsSize, ctx.Logger); } ctx.Logger.LogMessage($"Finished writing {ctx.Options.OutFile}"); diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index f7b7f09d..da1caf58 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -109,9 +109,12 @@ namespace hactoolnet { long bytesToRead = 1024L * 1024 * 1024 * 5; IStorage storage = OpenStorageByType(NcaSectionType.Data); - var dest = new NullStorage(storage.GetSize()); - int iterations = (int)(bytesToRead / storage.GetSize()) + 1; + storage.GetSize(out long sectionSize).ThrowIfFailure(); + + var dest = new NullStorage(sectionSize); + + int iterations = (int)(bytesToRead / sectionSize) + 1; ctx.Logger.LogMessage(iterations.ToString()); ctx.Logger.StartNewStopWatch(); diff --git a/src/hactoolnet/ProcessPfs.cs b/src/hactoolnet/ProcessPfs.cs index d36c2fec..fbabfad7 100644 --- a/src/hactoolnet/ProcessPfs.cs +++ b/src/hactoolnet/ProcessPfs.cs @@ -89,11 +89,13 @@ namespace hactoolnet Assembly thisAssembly = Assembly.GetExecutingAssembly(); Stream cert = thisAssembly.GetManifestResourceStream("hactoolnet.CA00000003_XS00000020"); builder.AddFile($"{ticket.RightsId.ToHexString()}.cert", cert.AsIFile(OpenMode.Read)); - + using (var outStream = new FileStream(ctx.Options.NspOut, FileMode.Create, FileAccess.ReadWrite)) { IStorage builtPfs = builder.Build(PartitionFileSystemType.Standard); - builtPfs.CopyToStream(outStream, builtPfs.GetSize(), ctx.Logger); + builtPfs.GetSize(out long pfsSize).ThrowIfFailure(); + + builtPfs.CopyToStream(outStream, pfsSize, ctx.Logger); } } } diff --git a/src/hactoolnet/ProcessRomfs.cs b/src/hactoolnet/ProcessRomfs.cs index cf53df5a..ac16b8df 100644 --- a/src/hactoolnet/ProcessRomfs.cs +++ b/src/hactoolnet/ProcessRomfs.cs @@ -28,9 +28,11 @@ namespace hactoolnet if (ctx.Options.RomfsOut != null) { + romfsStorage.GetSize(out long romFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite)) { - romfsStorage.CopyToStream(outFile, romfsStorage.GetSize(), ctx.Logger); + romfsStorage.CopyToStream(outFile, romFsSize, ctx.Logger); } } diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index c973401f..6be16758 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -64,9 +64,12 @@ namespace hactoolnet { using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite)) { - if (inFile.GetSize() != outFile.GetSize()) + inFile.GetSize(out long inFileSize).ThrowIfFailure(); + outFile.GetSize(out long outFileSize).ThrowIfFailure(); + + if (inFileSize != outFileSize) { - outFile.SetSize(inFile.GetSize()); + outFile.SetSize(inFileSize).ThrowIfFailure(); } inFile.CopyTo(outFile, ctx.Logger);