mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Remove IFile.Mode and create a new FileBase class
This commit is contained in:
parent
22940f20e5
commit
6a449b7da1
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.Fs.Accessors
|
||||
{
|
||||
@ -11,10 +10,6 @@ namespace LibHac.Fs.Accessors
|
||||
public WriteState WriteState { get; private set; }
|
||||
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;
|
||||
|
131
src/LibHac/Fs/FileBase2.cs
Normal file
131
src/LibHac/Fs/FileBase2.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public abstract class FileBase2 : IFile
|
||||
{
|
||||
// 0 = not disposed; 1 = disposed
|
||||
private int _disposedState;
|
||||
private bool IsDisposed => _disposedState != 0;
|
||||
|
||||
public abstract Result ReadImpl(out long bytesRead, long offset, Span<byte> destination, ReadOption options);
|
||||
public abstract Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options);
|
||||
public abstract Result FlushImpl();
|
||||
public abstract Result GetSizeImpl(out long size);
|
||||
public abstract Result SetSizeImpl(long size);
|
||||
|
||||
public Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption options)
|
||||
{
|
||||
bytesRead = default;
|
||||
|
||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
if (destination.Length == 0) return Result.Success;
|
||||
if (offset < 0) return ResultFs.ValueOutOfRange.Log();
|
||||
|
||||
return ReadImpl(out bytesRead, offset, destination, options);
|
||||
}
|
||||
|
||||
public Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options)
|
||||
{
|
||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
if (source.Length == 0)
|
||||
{
|
||||
if (options.HasFlag(WriteOption.Flush))
|
||||
{
|
||||
return Flush();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (offset < 0) return ResultFs.ValueOutOfRange.Log();
|
||||
|
||||
return WriteImpl(offset, source, options);
|
||||
}
|
||||
|
||||
public Result Flush()
|
||||
{
|
||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
return FlushImpl();
|
||||
}
|
||||
|
||||
public Result GetSize(out long size)
|
||||
{
|
||||
size = 0;
|
||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
return GetSizeImpl(out size);
|
||||
}
|
||||
|
||||
public Result SetSize(long size)
|
||||
{
|
||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||
if (size < 0) return ResultFs.ValueOutOfRange.Log();
|
||||
|
||||
return SetSizeImpl(size);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Make sure Dispose is only called once
|
||||
if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0)
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) { }
|
||||
|
||||
protected Result ValidateReadParams(out long bytesToRead, long offset, int size, OpenMode openMode)
|
||||
{
|
||||
bytesToRead = default;
|
||||
|
||||
if (!openMode.HasFlag(OpenMode.Read))
|
||||
{
|
||||
return ResultFs.InvalidOpenModeForRead.Log();
|
||||
}
|
||||
|
||||
Result rc = GetSize(out long fileSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (offset > fileSize)
|
||||
{
|
||||
return ResultFs.ValueOutOfRange.Log();
|
||||
}
|
||||
|
||||
bytesToRead = Math.Min(fileSize - offset, size);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected Result ValidateWriteParams(long offset, int size, OpenMode openMode, out bool isResizeNeeded)
|
||||
{
|
||||
isResizeNeeded = false;
|
||||
|
||||
if (!openMode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
return ResultFs.InvalidOpenModeForWrite.Log();
|
||||
}
|
||||
|
||||
Result rc = GetSize(out long fileSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (offset + size > fileSize)
|
||||
{
|
||||
isResizeNeeded = true;
|
||||
|
||||
if (!openMode.HasFlag(OpenMode.AllowAppend))
|
||||
{
|
||||
return ResultFs.AllowAppendRequiredForImplicitExtension.Log();
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
|
@ -1,5 +1,3 @@
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public partial class FileSystemClient
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace LibHac.Fs
|
||||
using System;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public enum BisPartitionId
|
||||
{
|
||||
@ -92,4 +94,29 @@
|
||||
Nand = 0,
|
||||
SdCard = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies which operations are available on an <see cref="IFile"/>.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum OpenMode
|
||||
{
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
AllowAppend = 4,
|
||||
ReadWrite = Read | Write
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ReadOption
|
||||
{
|
||||
None = 0
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum WriteOption
|
||||
{
|
||||
None = 0,
|
||||
Flush = 1
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
@ -19,11 +18,6 @@ namespace LibHac.Fs
|
||||
/// the file will be expanded so that it is large enough to contain the written data.</remarks>
|
||||
public interface IFile : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The permissions mode for the current file.
|
||||
/// </summary>
|
||||
OpenMode Mode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes from the current <see cref="IFile"/>.
|
||||
/// </summary>
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.FsSystem.Save;
|
||||
|
||||
namespace LibHac.FsService.Creators
|
||||
|
@ -3,57 +3,49 @@ using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSystem
|
||||
{
|
||||
public class DirectorySaveDataFile : FileBase
|
||||
public class DirectorySaveDataFile : FileBase2
|
||||
{
|
||||
private IFile BaseFile { get; }
|
||||
private DirectorySaveDataFileSystem ParentFs { get; }
|
||||
private object DisposeLocker { get; } = new object();
|
||||
private OpenMode Mode { get; }
|
||||
|
||||
public DirectorySaveDataFile(DirectorySaveDataFileSystem parentFs, IFile baseFile)
|
||||
public DirectorySaveDataFile(DirectorySaveDataFileSystem parentFs, IFile baseFile, OpenMode mode)
|
||||
{
|
||||
ParentFs = parentFs;
|
||||
BaseFile = baseFile;
|
||||
Mode = BaseFile.Mode;
|
||||
ToDispose.Add(BaseFile);
|
||||
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)
|
||||
{
|
||||
return BaseFile.Read(out bytesRead, offset, destination, options);
|
||||
}
|
||||
|
||||
public override Result Write(long offset, ReadOnlySpan<byte> source, WriteOption options)
|
||||
public override Result WriteImpl(long offset, ReadOnlySpan<byte> source, WriteOption options)
|
||||
{
|
||||
return BaseFile.Write(offset, source, options);
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
public override Result FlushImpl()
|
||||
{
|
||||
return BaseFile.Flush();
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
public override Result GetSizeImpl(out long size)
|
||||
{
|
||||
return BaseFile.GetSize(out size);
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
public override Result SetSizeImpl(long size)
|
||||
{
|
||||
return BaseFile.SetSize(size);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
lock (DisposeLocker)
|
||||
if (Mode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
if (IsDisposed) return;
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (Mode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
ParentFs.NotifyCloseWritableFile();
|
||||
}
|
||||
ParentFs.NotifyCloseWritableFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ namespace LibHac.FsSystem
|
||||
Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new DirectorySaveDataFile(this, baseFile);
|
||||
file = new DirectorySaveDataFile(this, baseFile, mode);
|
||||
|
||||
if (mode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
|
@ -83,29 +83,4 @@ namespace LibHac.FsSystem
|
||||
IsDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies which operations are available on an <see cref="IFile"/>.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum OpenMode
|
||||
{
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
AllowAppend = 4,
|
||||
ReadWrite = Read | Write
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ReadOption
|
||||
{
|
||||
None = 0
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum WriteOption
|
||||
{
|
||||
None = 0,
|
||||
Flush = 1
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
public static IStorage AsStorage(this IFile file) => new FileStorage(file);
|
||||
public static Stream AsStream(this IFile file) => new NxFileStream(file, true);
|
||||
public static Stream AsStream(this IFile file, bool keepOpen) => new NxFileStream(file, keepOpen);
|
||||
public static Stream AsStream(this IFile file, OpenMode mode, bool keepOpen) => new NxFileStream(file, mode, keepOpen);
|
||||
|
||||
public static IFile AsIFile(this Stream stream, OpenMode mode) => new StreamFile(stream, mode);
|
||||
|
||||
|
@ -4,49 +4,51 @@ using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSystem
|
||||
{
|
||||
public class LocalFile : FileBase
|
||||
public class LocalFile : FileBase2
|
||||
{
|
||||
private const int ErrorHandleDiskFull = unchecked((int)0x80070027);
|
||||
private const int ErrorDiskFull = unchecked((int)0x80070070);
|
||||
|
||||
private FileStream Stream { get; }
|
||||
private StreamFile File { get; }
|
||||
private OpenMode Mode { get; }
|
||||
|
||||
public LocalFile(string path, OpenMode mode)
|
||||
{
|
||||
Mode = mode;
|
||||
Stream = OpenFile(path, mode);
|
||||
File = new StreamFile(Stream, mode);
|
||||
|
||||
ToDispose.Add(File);
|
||||
ToDispose.Add(Stream);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return File.Read(out bytesRead, offset, destination.Slice(0, toRead), options);
|
||||
Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return File.Read(out bytesRead, offset, destination.Slice(0, (int)toRead), options);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return File.Write(offset, source, options);
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
public override Result FlushImpl()
|
||||
{
|
||||
return File.Flush();
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
public override Result GetSizeImpl(out long size)
|
||||
{
|
||||
return File.GetSize(out size);
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
public override Result SetSizeImpl(long size)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -60,6 +62,16 @@ namespace LibHac.FsSystem
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
File?.Dispose();
|
||||
}
|
||||
|
||||
Stream?.Dispose();
|
||||
}
|
||||
|
||||
private static FileAccess GetFileAccess(OpenMode mode)
|
||||
{
|
||||
// FileAccess and OpenMode have the same flags
|
||||
|
@ -8,11 +8,15 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
private IFile BaseFile { get; }
|
||||
private bool LeaveOpen { get; }
|
||||
private OpenMode Mode { get; }
|
||||
private long _length;
|
||||
|
||||
public NxFileStream(IFile baseFile, bool leaveOpen)
|
||||
public NxFileStream(IFile baseFile, bool leaveOpen) : this(baseFile, OpenMode.ReadWrite, leaveOpen) { }
|
||||
|
||||
public NxFileStream(IFile baseFile, OpenMode mode, bool leaveOpen)
|
||||
{
|
||||
BaseFile = baseFile;
|
||||
Mode = mode;
|
||||
LeaveOpen = leaveOpen;
|
||||
|
||||
baseFile.GetSize(out _length).ThrowIfFailure();
|
||||
@ -63,9 +67,9 @@ namespace LibHac.FsSystem
|
||||
BaseFile.GetSize(out _length).ThrowIfFailure();
|
||||
}
|
||||
|
||||
public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read);
|
||||
public override bool CanRead => Mode.HasFlag(OpenMode.Read);
|
||||
public override bool CanSeek => true;
|
||||
public override bool CanWrite => BaseFile.Mode.HasFlag(OpenMode.Write);
|
||||
public override bool CanWrite => Mode.HasFlag(OpenMode.Write);
|
||||
public override long Length => _length;
|
||||
public override long Position { get; set; }
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSystem.Save
|
||||
{
|
||||
|
@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
[Serializable]
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
public struct Result : IEquatable<Result>
|
||||
{
|
||||
public readonly int Value;
|
||||
@ -43,6 +45,11 @@ namespace LibHac
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return IsSuccess() ? "Success" : ErrorCode;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Result result && Equals(result);
|
||||
|
Loading…
x
Reference in New Issue
Block a user