diff --git a/src/LibHac/Fs/FileBase2.cs b/src/LibHac/Fs/FileBase.cs similarity index 98% rename from src/LibHac/Fs/FileBase2.cs rename to src/LibHac/Fs/FileBase.cs index 07cfed1a..5caa7829 100644 --- a/src/LibHac/Fs/FileBase2.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -3,7 +3,7 @@ using System.Threading; namespace LibHac.Fs { - public abstract class FileBase2 : IFile + public abstract class FileBase : IFile { // 0 = not disposed; 1 = disposed private int _disposedState; diff --git a/src/LibHac/FsService/Permissions.cs b/src/LibHac/FsService/Permissions.cs index aa773235..2163df8b 100644 --- a/src/LibHac/FsService/Permissions.cs +++ b/src/LibHac/FsService/Permissions.cs @@ -3,7 +3,7 @@ namespace LibHac.FsService { /// - /// Permissions that control which storages or filesystems can be mounted or opened. + /// Permissions that control which filesystems or storages can be mounted or opened. /// public enum AccessPermissions { diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index bd70578f..00fb3403 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -10,6 +10,7 @@ namespace LibHac.FsSystem private byte[] KekSeed { get; } private byte[] VerificationKey { get; } private int BlockSize { get; } + private OpenMode Mode { get; } private AesXtsFileHeader Header { get; } private IStorage BaseStorage { get; } @@ -52,23 +53,31 @@ namespace LibHac.FsSystem return key; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Write(offset, source); + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } + + rc = BaseStorage.Write(offset, source); if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) @@ -79,18 +88,18 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Header.Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { Header.SetSize(size, VerificationKey); @@ -99,5 +108,13 @@ namespace LibHac.FsSystem return BaseStorage.SetSize(size); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + BaseFile?.Dispose(); + } + } } } diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index a5de6e98..ccfca772 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -107,8 +107,6 @@ namespace LibHac.FsSystem var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); - xtsFile.ToDispose.Add(baseFile); - file = xtsFile; return Result.Success; } diff --git a/src/LibHac/FsSystem/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs index 88ee7589..81f2598d 100644 --- a/src/LibHac/FsSystem/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -12,6 +12,7 @@ namespace LibHac.FsSystem private string FilePath { get; } private List Sources { get; } private long SubFileSize { get; } + private OpenMode Mode { get; } internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable sources, long subFileSize, OpenMode mode) { @@ -30,17 +31,17 @@ namespace LibHac.FsSystem throw new ArgumentException($"Source file must have size {subFileSize}"); } } - - ToDispose.AddRange(Sources); } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; long inPos = offset; int outPos = 0; - int remaining = ValidateReadParamsAndGetSize(destination, offset); + + Result rc = ValidateReadParams(out long remaining, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; GetSize(out long fileSize).ThrowIfFailure(); @@ -53,12 +54,12 @@ namespace LibHac.FsSystem long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining); - Result rc = file.Read(out long subFileBytesRead, fileOffset, destination.Slice(outPos, bytesToRead), options); + 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; + remaining -= subFileBytesRead; if (bytesRead < bytesToRead) break; } @@ -68,9 +69,10 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); + if (rc.IsFailure()) return rc; int inPos = 0; long outPos = offset; @@ -87,7 +89,7 @@ namespace LibHac.FsSystem long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining); - Result rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); + rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); if (rc.IsFailure()) return rc; outPos += bytesToWrite; @@ -95,7 +97,7 @@ namespace LibHac.FsSystem remaining -= bytesToWrite; } - if ((options & WriteOption.Flush) != 0) + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -103,7 +105,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { foreach (IFile file in Sources) { @@ -114,7 +116,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = default; @@ -129,7 +131,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { Result rc = GetSize(out long currentSize); if (rc.IsFailure()) return rc; @@ -183,6 +185,19 @@ namespace LibHac.FsSystem return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + foreach (IFile file in Sources) + { + file?.Dispose(); + } + + Sources.Clear(); + } + } + private int GetSubFileIndexFromOffset(long offset) { return (int)(offset / SubFileSize); diff --git a/src/LibHac/FsSystem/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs index 1a420ae3..053c4c75 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -3,7 +3,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class DirectorySaveDataFile : FileBase2 + public class DirectorySaveDataFile : FileBase { private IFile BaseFile { get; } private DirectorySaveDataFileSystem ParentFs { get; } diff --git a/src/LibHac/FsSystem/FileBase.cs b/src/LibHac/FsSystem/FileBase.cs deleted file mode 100644 index 4079ca85..00000000 --- a/src/LibHac/FsSystem/FileBase.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using LibHac.Fs; - -namespace LibHac.FsSystem -{ - public abstract class FileBase : IFile - { - protected bool IsDisposed { get; private set; } - internal List ToDispose { get; } = new List(); - - public abstract Result Read(out long bytesRead, long offset, Span destination, ReadOption options); - public abstract Result Write(long offset, ReadOnlySpan source, WriteOption options); - public abstract Result Flush(); - public abstract Result GetSize(out long size); - public abstract Result SetSize(long size); - - public OpenMode Mode { get; protected set; } - - protected int ValidateReadParamsAndGetSize(ReadOnlySpan span, long offset) - { - if (IsDisposed) throw new ObjectDisposedException(null); - - if ((Mode & OpenMode.Read) == 0) ThrowHelper.ThrowResult(ResultFs.InvalidOpenModeForRead, "File does not allow reading."); - if (span == null) throw new ArgumentNullException(nameof(span)); - if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - - Result sizeResult = GetSize(out long fileSize); - sizeResult.ThrowIfFailure(); - - int size = span.Length; - - if (offset > fileSize) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be less than the file size."); - - return (int)Math.Min(fileSize - offset, size); - } - - protected void ValidateWriteParams(ReadOnlySpan span, long offset) - { - if (IsDisposed) throw new ObjectDisposedException(null); - - if ((Mode & OpenMode.Write) == 0) ThrowHelper.ThrowResult(ResultFs.InvalidOpenModeForWrite, "File does not allow writing."); - - if (span == null) throw new ArgumentNullException(nameof(span)); - if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - - Result sizeResult = GetSize(out long fileSize); - sizeResult.ThrowIfFailure(); - - int size = span.Length; - - if (offset + size > fileSize) - { - if ((Mode & OpenMode.AllowAppend) == 0) - { - ThrowHelper.ThrowResult(ResultFs.AllowAppendRequiredForImplicitExtension); - } - - SetSize(offset + size); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (IsDisposed) return; - - if (disposing) - { - Flush(); - - foreach (IDisposable item in ToDispose) - { - item?.Dispose(); - } - } - - IsDisposed = true; - } - } -} diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index 370de75d..b4f02612 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -4,7 +4,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class LocalFile : FileBase2 + public class LocalFile : FileBase { private const int ErrorHandleDiskFull = unchecked((int)0x80070027); private const int ErrorDiskFull = unchecked((int)0x80070070); diff --git a/src/LibHac/FsSystem/NullFile.cs b/src/LibHac/FsSystem/NullFile.cs index a3d12591..44c79721 100644 --- a/src/LibHac/FsSystem/NullFile.cs +++ b/src/LibHac/FsSystem/NullFile.cs @@ -5,6 +5,8 @@ namespace LibHac.FsSystem { public class NullFile : FileBase { + private OpenMode Mode { get; } + public NullFile() { Mode = OpenMode.ReadWrite; @@ -14,32 +16,36 @@ namespace LibHac.FsSystem private long Length { get; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { - int toRead = ValidateReadParamsAndGetSize(destination, offset); - destination.Slice(0, toRead).Clear(); + bytesRead = 0; + + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + + destination.Slice(0, (int)toRead).Clear(); bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Length; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperation.Log(); } diff --git a/src/LibHac/FsSystem/PartitionFile.cs b/src/LibHac/FsSystem/PartitionFile.cs index 0c734f13..12468d96 100644 --- a/src/LibHac/FsSystem/PartitionFile.cs +++ b/src/LibHac/FsSystem/PartitionFile.cs @@ -8,6 +8,7 @@ namespace LibHac.FsSystem private IStorage BaseStorage { get; } private long Offset { get; } private long Size { get; } + private OpenMode Mode { get; } public PartitionFile(IStorage baseStorage, long offset, long size, OpenMode mode) { @@ -17,27 +18,34 @@ namespace LibHac.FsSystem Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { - bytesRead = default; + bytesRead = 0; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; long storageOffset = Offset + offset; - BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + BaseStorage.Read(storageOffset, destination.Slice(0, (int)toRead)); bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); - - Result rc = BaseStorage.Write(offset, source); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; - if ((options & WriteOption.Flush) != 0) + if (isResizeNeeded) return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); + + if (offset > Size) return ResultFs.ValueOutOfRange.Log(); + + rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; + + // N doesn't flush if the flag is set + if (options.HasFlag(WriteOption.Flush)) { return BaseStorage.Flush(); } @@ -45,9 +53,9 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { - if ((Mode & OpenMode.Write) != 0) + if (!Mode.HasFlag(OpenMode.Write)) { return BaseStorage.Flush(); } @@ -55,14 +63,19 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { + if (!Mode.HasFlag(OpenMode.Write)) + { + return ResultFs.InvalidOpenModeForWrite.Log(); + } + return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); } } diff --git a/src/LibHac/FsSystem/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs index 07611c3f..8945f1be 100644 --- a/src/LibHac/FsSystem/ReadOnlyFile.cs +++ b/src/LibHac/FsSystem/ReadOnlyFile.cs @@ -12,29 +12,29 @@ namespace LibHac.FsSystem BaseFile = baseFile; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { return BaseFile.Read(out bytesRead, offset, destination, options); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + return ResultFs.InvalidOpenModeForWrite.Log(); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { - return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + return ResultFs.InvalidOpenModeForWrite.Log(); } } } diff --git a/src/LibHac/FsSystem/RomFs/RomFsFile.cs b/src/LibHac/FsSystem/RomFs/RomFsFile.cs index d069d860..3f304868 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFile.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFile.cs @@ -11,21 +11,21 @@ namespace LibHac.FsSystem.RomFs public RomFsFile(IStorage baseStorage, long offset, long size) { - Mode = OpenMode.Read; BaseStorage = baseStorage; Offset = offset; Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, OpenMode.Read); + if (rc.IsFailure()) return rc; long storageOffset = Offset + offset; - Result rc = BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + rc = BaseStorage.Read(storageOffset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; @@ -33,23 +33,23 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } diff --git a/src/LibHac/FsSystem/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs index 56a56ec5..93b7d07e 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -10,6 +10,7 @@ namespace LibHac.FsSystem.Save private string Path { get; } private HierarchicalSaveFileTable FileTable { get; } private long Size { get; set; } + private OpenMode Mode { get; } public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) { @@ -20,22 +21,36 @@ namespace LibHac.FsSystem.Save Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (toRead == 0) + { + bytesRead = 0; + return Result.Success; + } + + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); + if (rc.IsFailure()) return rc; + + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } BaseStorage.Write(offset, source); @@ -47,18 +62,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); if (Size == size) return Result.Success; diff --git a/src/LibHac/FsSystem/StorageFile.cs b/src/LibHac/FsSystem/StorageFile.cs index 08f460ce..604dfd6c 100644 --- a/src/LibHac/FsSystem/StorageFile.cs +++ b/src/LibHac/FsSystem/StorageFile.cs @@ -6,6 +6,7 @@ namespace LibHac.FsSystem public class StorageFile : FileBase { private IStorage BaseStorage { get; } + private OpenMode Mode { get; } public StorageFile(IStorage baseStorage, OpenMode mode) { @@ -13,26 +14,41 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + + if (toRead == 0) + { + bytesRead = 0; + return Result.Success; + } + + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); - - Result rc = BaseStorage.Write(offset, source); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; - if ((options & WriteOption.Flush) != 0) + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } + + rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; + + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -40,18 +56,24 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { + if (!Mode.HasFlag(OpenMode.Write)) + return Result.Success; + return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return BaseStorage.GetSize(out size); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { + if (!Mode.HasFlag(OpenMode.Write)) + return ResultFs.InvalidOpenModeForWrite.Log(); + return BaseStorage.SetSize(size); } } diff --git a/src/LibHac/FsSystem/StreamFile.cs b/src/LibHac/FsSystem/StreamFile.cs index c2308049..90db129d 100644 --- a/src/LibHac/FsSystem/StreamFile.cs +++ b/src/LibHac/FsSystem/StreamFile.cs @@ -1,6 +1,7 @@ using System; using System.IO; using LibHac.Fs; + #if !STREAM_SPAN using System.Buffers; #endif @@ -14,6 +15,7 @@ namespace LibHac.FsSystem { // todo: handle Stream exceptions + private OpenMode Mode { get; } private Stream BaseStream { get; } private object Locker { get; } = new object(); @@ -23,8 +25,13 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + #if STREAM_SPAN lock (Locker) { @@ -33,11 +40,11 @@ namespace LibHac.FsSystem BaseStream.Position = offset; } - bytesRead = BaseStream.Read(destination); + bytesRead = BaseStream.Read(destination.Slice(0, (int)toRead)); return Result.Success; } #else - byte[] buffer = ArrayPool.Shared.Rent(destination.Length); + byte[] buffer = ArrayPool.Shared.Rent((int)toRead); try { lock (Locker) @@ -47,10 +54,10 @@ namespace LibHac.FsSystem BaseStream.Position = offset; } - bytesRead = BaseStream.Read(buffer, 0, destination.Length); + bytesRead = BaseStream.Read(buffer, 0, (int)toRead); } - new Span(buffer, 0, destination.Length).CopyTo(destination); + new Span(buffer, 0, (int)bytesRead).CopyTo(destination); return Result.Success; } @@ -58,8 +65,11 @@ namespace LibHac.FsSystem #endif } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { + Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); + if (rc.IsFailure()) return rc; + #if STREAM_SPAN lock (Locker) { @@ -81,7 +91,7 @@ namespace LibHac.FsSystem finally { ArrayPool.Shared.Return(buffer); } #endif - if ((options & WriteOption.Flush) != 0) + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -89,7 +99,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { lock (Locker) { @@ -98,7 +108,7 @@ namespace LibHac.FsSystem } } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { lock (Locker) { @@ -107,7 +117,7 @@ namespace LibHac.FsSystem } } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { lock (Locker) {