Remove the old FileBase class

This commit is contained in:
Alex Barney 2019-09-23 00:36:47 -05:00
parent 6a449b7da1
commit fd40b2fd77
15 changed files with 188 additions and 178 deletions

View file

@ -3,7 +3,7 @@ using System.Threading;
namespace LibHac.Fs namespace LibHac.Fs
{ {
public abstract class FileBase2 : IFile public abstract class FileBase : IFile
{ {
// 0 = not disposed; 1 = disposed // 0 = not disposed; 1 = disposed
private int _disposedState; private int _disposedState;

View file

@ -3,7 +3,7 @@
namespace LibHac.FsService namespace LibHac.FsService
{ {
/// <summary> /// <summary>
/// Permissions that control which storages or filesystems can be mounted or opened. /// Permissions that control which filesystems or storages can be mounted or opened.
/// </summary> /// </summary>
public enum AccessPermissions public enum AccessPermissions
{ {

View file

@ -10,6 +10,7 @@ namespace LibHac.FsSystem
private byte[] KekSeed { get; } private byte[] KekSeed { get; }
private byte[] VerificationKey { get; } private byte[] VerificationKey { get; }
private int BlockSize { get; } private int BlockSize { get; }
private OpenMode Mode { get; }
private AesXtsFileHeader Header { get; } private AesXtsFileHeader Header { get; }
private IStorage BaseStorage { get; } private IStorage BaseStorage { get; }
@ -52,23 +53,31 @@ namespace LibHac.FsSystem
return key; return key;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default; 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; if (rc.IsFailure()) return rc;
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> 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 (rc.IsFailure()) return rc;
if ((options & WriteOption.Flush) != 0) if ((options & WriteOption.Flush) != 0)
@ -79,18 +88,18 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
return BaseStorage.Flush(); return BaseStorage.Flush();
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = Header.Size; size = Header.Size;
return Result.Success; return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
Header.SetSize(size, VerificationKey); Header.SetSize(size, VerificationKey);
@ -99,5 +108,13 @@ namespace LibHac.FsSystem
return BaseStorage.SetSize(size); return BaseStorage.SetSize(size);
} }
protected override void Dispose(bool disposing)
{
if (disposing)
{
BaseFile?.Dispose();
}
}
} }
} }

View file

@ -107,8 +107,6 @@ namespace LibHac.FsSystem
var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize);
xtsFile.ToDispose.Add(baseFile);
file = xtsFile; file = xtsFile;
return Result.Success; return Result.Success;
} }

View file

@ -12,6 +12,7 @@ namespace LibHac.FsSystem
private string FilePath { get; } private string FilePath { get; }
private List<IFile> Sources { get; } private List<IFile> Sources { get; }
private long SubFileSize { get; } private long SubFileSize { get; }
private OpenMode Mode { get; }
internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable<IFile> sources, long subFileSize, OpenMode mode) internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable<IFile> sources, long subFileSize, OpenMode mode)
{ {
@ -30,17 +31,17 @@ namespace LibHac.FsSystem
throw new ArgumentException($"Source file must have size {subFileSize}"); throw new ArgumentException($"Source file must have size {subFileSize}");
} }
} }
ToDispose.AddRange(Sources);
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default; bytesRead = default;
long inPos = offset; long inPos = offset;
int outPos = 0; 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(); GetSize(out long fileSize).ThrowIfFailure();
@ -53,12 +54,12 @@ namespace LibHac.FsSystem
long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize);
int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining); 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; if (rc.IsFailure()) return rc;
outPos += (int)subFileBytesRead; outPos += (int)subFileBytesRead;
inPos += subFileBytesRead; inPos += subFileBytesRead;
remaining -= (int)subFileBytesRead; remaining -= subFileBytesRead;
if (bytesRead < bytesToRead) break; if (bytesRead < bytesToRead) break;
} }
@ -68,9 +69,10 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
ValidateWriteParams(source, offset); Result rc = ValidateWriteParams(offset, source.Length, Mode, out _);
if (rc.IsFailure()) return rc;
int inPos = 0; int inPos = 0;
long outPos = offset; long outPos = offset;
@ -87,7 +89,7 @@ namespace LibHac.FsSystem
long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize);
int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining); 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; if (rc.IsFailure()) return rc;
outPos += bytesToWrite; outPos += bytesToWrite;
@ -95,7 +97,7 @@ namespace LibHac.FsSystem
remaining -= bytesToWrite; remaining -= bytesToWrite;
} }
if ((options & WriteOption.Flush) != 0) if (options.HasFlag(WriteOption.Flush))
{ {
return Flush(); return Flush();
} }
@ -103,7 +105,7 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
foreach (IFile file in Sources) foreach (IFile file in Sources)
{ {
@ -114,7 +116,7 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = default; size = default;
@ -129,7 +131,7 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
Result rc = GetSize(out long currentSize); Result rc = GetSize(out long currentSize);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
@ -183,6 +185,19 @@ namespace LibHac.FsSystem
return Result.Success; 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) private int GetSubFileIndexFromOffset(long offset)
{ {
return (int)(offset / SubFileSize); return (int)(offset / SubFileSize);

View file

@ -3,7 +3,7 @@ using LibHac.Fs;
namespace LibHac.FsSystem namespace LibHac.FsSystem
{ {
public class DirectorySaveDataFile : FileBase2 public class DirectorySaveDataFile : FileBase
{ {
private IFile BaseFile { get; } private IFile BaseFile { get; }
private DirectorySaveDataFileSystem ParentFs { get; } private DirectorySaveDataFileSystem ParentFs { get; }

View file

@ -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<IDisposable> ToDispose { get; } = new List<IDisposable>();
public abstract Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options);
public abstract Result Write(long offset, ReadOnlySpan<byte> 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<byte> 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<byte> 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;
}
}
}

View file

@ -4,7 +4,7 @@ using LibHac.Fs;
namespace LibHac.FsSystem namespace LibHac.FsSystem
{ {
public class LocalFile : FileBase2 public class LocalFile : FileBase
{ {
private const int ErrorHandleDiskFull = unchecked((int)0x80070027); private const int ErrorHandleDiskFull = unchecked((int)0x80070027);
private const int ErrorDiskFull = unchecked((int)0x80070070); private const int ErrorDiskFull = unchecked((int)0x80070070);

View file

@ -5,6 +5,8 @@ namespace LibHac.FsSystem
{ {
public class NullFile : FileBase public class NullFile : FileBase
{ {
private OpenMode Mode { get; }
public NullFile() public NullFile()
{ {
Mode = OpenMode.ReadWrite; Mode = OpenMode.ReadWrite;
@ -14,32 +16,36 @@ namespace LibHac.FsSystem
private long Length { get; } private long Length { get; }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
int toRead = ValidateReadParamsAndGetSize(destination, offset); bytesRead = 0;
destination.Slice(0, toRead).Clear();
Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode);
if (rc.IsFailure()) return rc;
destination.Slice(0, (int)toRead).Clear();
bytesRead = toRead; bytesRead = toRead;
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
return Result.Success; return Result.Success;
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = Length; size = Length;
return Result.Success; return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
return ResultFs.UnsupportedOperation.Log(); return ResultFs.UnsupportedOperation.Log();
} }

View file

@ -8,6 +8,7 @@ namespace LibHac.FsSystem
private IStorage BaseStorage { get; } private IStorage BaseStorage { get; }
private long Offset { get; } private long Offset { get; }
private long Size { get; } private long Size { get; }
private OpenMode Mode { get; }
public PartitionFile(IStorage baseStorage, long offset, long size, OpenMode mode) public PartitionFile(IStorage baseStorage, long offset, long size, OpenMode mode)
{ {
@ -17,27 +18,34 @@ namespace LibHac.FsSystem
Size = size; Size = size;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> 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; long storageOffset = Offset + offset;
BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); BaseStorage.Read(storageOffset, destination.Slice(0, (int)toRead));
bytesRead = toRead; bytesRead = toRead;
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
ValidateWriteParams(source, offset); Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded);
Result rc = BaseStorage.Write(offset, source);
if (rc.IsFailure()) return rc; 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(); return BaseStorage.Flush();
} }
@ -45,9 +53,9 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
if ((Mode & OpenMode.Write) != 0) if (!Mode.HasFlag(OpenMode.Write))
{ {
return BaseStorage.Flush(); return BaseStorage.Flush();
} }
@ -55,14 +63,19 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = Size; size = Size;
return Result.Success; 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(); return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log();
} }
} }

View file

@ -12,29 +12,29 @@ namespace LibHac.FsSystem
BaseFile = baseFile; BaseFile = baseFile;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
return BaseFile.Read(out bytesRead, offset, destination, 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); return BaseFile.GetSize(out size);
} }
public override Result Flush() public override Result FlushImpl()
{ {
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> 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();
} }
} }
} }

View file

@ -11,21 +11,21 @@ namespace LibHac.FsSystem.RomFs
public RomFsFile(IStorage baseStorage, long offset, long size) public RomFsFile(IStorage baseStorage, long offset, long size)
{ {
Mode = OpenMode.Read;
BaseStorage = baseStorage; BaseStorage = baseStorage;
Offset = offset; Offset = offset;
Size = size; Size = size;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default; 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; 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; if (rc.IsFailure()) return rc;
bytesRead = toRead; bytesRead = toRead;
@ -33,23 +33,23 @@ namespace LibHac.FsSystem.RomFs
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); return ResultFs.UnsupportedOperationModifyRomFsFile.Log();
} }
public override Result Flush() public override Result FlushImpl()
{ {
return Result.Success; return Result.Success;
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = Size; size = Size;
return Result.Success; return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); return ResultFs.UnsupportedOperationModifyRomFsFile.Log();
} }

View file

@ -10,6 +10,7 @@ namespace LibHac.FsSystem.Save
private string Path { get; } private string Path { get; }
private HierarchicalSaveFileTable FileTable { get; } private HierarchicalSaveFileTable FileTable { get; }
private long Size { get; set; } private long Size { get; set; }
private OpenMode Mode { get; }
public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode)
{ {
@ -20,22 +21,36 @@ namespace LibHac.FsSystem.Save
Size = size; Size = size;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default; 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; if (rc.IsFailure()) return rc;
bytesRead = toRead; bytesRead = toRead;
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> 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); BaseStorage.Write(offset, source);
@ -47,18 +62,18 @@ namespace LibHac.FsSystem.Save
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
return BaseStorage.Flush(); return BaseStorage.Flush();
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = Size; size = Size;
return Result.Success; 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 < 0) throw new ArgumentOutOfRangeException(nameof(size));
if (Size == size) return Result.Success; if (Size == size) return Result.Success;

View file

@ -6,6 +6,7 @@ namespace LibHac.FsSystem
public class StorageFile : FileBase public class StorageFile : FileBase
{ {
private IStorage BaseStorage { get; } private IStorage BaseStorage { get; }
private OpenMode Mode { get; }
public StorageFile(IStorage baseStorage, OpenMode mode) public StorageFile(IStorage baseStorage, OpenMode mode)
{ {
@ -13,26 +14,41 @@ namespace LibHac.FsSystem
Mode = mode; Mode = mode;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default; 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; if (rc.IsFailure()) return rc;
bytesRead = toRead; bytesRead = toRead;
return Result.Success; return Result.Success;
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
ValidateWriteParams(source, offset); Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded);
Result rc = BaseStorage.Write(offset, source);
if (rc.IsFailure()) return rc; 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(); return Flush();
} }
@ -40,18 +56,24 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
if (!Mode.HasFlag(OpenMode.Write))
return Result.Success;
return BaseStorage.Flush(); return BaseStorage.Flush();
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
return BaseStorage.GetSize(out 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); return BaseStorage.SetSize(size);
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using LibHac.Fs; using LibHac.Fs;
#if !STREAM_SPAN #if !STREAM_SPAN
using System.Buffers; using System.Buffers;
#endif #endif
@ -14,6 +15,7 @@ namespace LibHac.FsSystem
{ {
// todo: handle Stream exceptions // todo: handle Stream exceptions
private OpenMode Mode { get; }
private Stream BaseStream { get; } private Stream BaseStream { get; }
private object Locker { get; } = new object(); private object Locker { get; } = new object();
@ -23,8 +25,13 @@ namespace LibHac.FsSystem
Mode = mode; Mode = mode;
} }
public override Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options) public override Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
{ {
bytesRead = default;
Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode);
if (rc.IsFailure()) return rc;
#if STREAM_SPAN #if STREAM_SPAN
lock (Locker) lock (Locker)
{ {
@ -33,11 +40,11 @@ namespace LibHac.FsSystem
BaseStream.Position = offset; BaseStream.Position = offset;
} }
bytesRead = BaseStream.Read(destination); bytesRead = BaseStream.Read(destination.Slice(0, (int)toRead));
return Result.Success; return Result.Success;
} }
#else #else
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length); byte[] buffer = ArrayPool<byte>.Shared.Rent((int)toRead);
try try
{ {
lock (Locker) lock (Locker)
@ -47,10 +54,10 @@ namespace LibHac.FsSystem
BaseStream.Position = offset; BaseStream.Position = offset;
} }
bytesRead = BaseStream.Read(buffer, 0, destination.Length); bytesRead = BaseStream.Read(buffer, 0, (int)toRead);
} }
new Span<byte>(buffer, 0, destination.Length).CopyTo(destination); new Span<byte>(buffer, 0, (int)bytesRead).CopyTo(destination);
return Result.Success; return Result.Success;
} }
@ -58,8 +65,11 @@ namespace LibHac.FsSystem
#endif #endif
} }
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
Result rc = ValidateWriteParams(offset, source.Length, Mode, out _);
if (rc.IsFailure()) return rc;
#if STREAM_SPAN #if STREAM_SPAN
lock (Locker) lock (Locker)
{ {
@ -81,7 +91,7 @@ namespace LibHac.FsSystem
finally { ArrayPool<byte>.Shared.Return(buffer); } finally { ArrayPool<byte>.Shared.Return(buffer); }
#endif #endif
if ((options & WriteOption.Flush) != 0) if (options.HasFlag(WriteOption.Flush))
{ {
return Flush(); return Flush();
} }
@ -89,7 +99,7 @@ namespace LibHac.FsSystem
return Result.Success; return Result.Success;
} }
public override Result Flush() public override Result FlushImpl()
{ {
lock (Locker) 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) lock (Locker)
{ {
@ -107,7 +117,7 @@ namespace LibHac.FsSystem
} }
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
lock (Locker) lock (Locker)
{ {