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)
{