mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Introduce UniqueRef<T> and use it in IFileSystem
This commit is contained in:
parent
5f85c0b8e2
commit
01ca9e0412
80
src/LibHac/Common/UniqueRef.cs
Normal file
80
src/LibHac/Common/UniqueRef.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using static InlineIL.IL.Emit;
|
||||||
|
|
||||||
|
namespace LibHac.Common
|
||||||
|
{
|
||||||
|
public static class UniqueRefExtensions
|
||||||
|
{
|
||||||
|
// ReSharper disable once EntityNameCapturedOnly.Global
|
||||||
|
public static ref UniqueRef<T> Ref<T>(this in UniqueRef<T> value) where T : class, IDisposable
|
||||||
|
{
|
||||||
|
Ldarg(nameof(value));
|
||||||
|
Ret();
|
||||||
|
throw InlineIL.IL.Unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct UniqueRef<T> : IDisposable where T : class, IDisposable
|
||||||
|
{
|
||||||
|
private T _value;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Release()?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniqueRef(T value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniqueRef(ref UniqueRef<T> other)
|
||||||
|
{
|
||||||
|
_value = other.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T Get => _value;
|
||||||
|
|
||||||
|
public readonly bool HasValue => Get is not null;
|
||||||
|
|
||||||
|
public void Reset() => Reset(null);
|
||||||
|
|
||||||
|
public void Reset(T value)
|
||||||
|
{
|
||||||
|
T oldValue = _value;
|
||||||
|
_value = value;
|
||||||
|
|
||||||
|
oldValue?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset<TFrom>(TFrom value) where TFrom : class, T
|
||||||
|
{
|
||||||
|
T oldValue = _value;
|
||||||
|
_value = value;
|
||||||
|
|
||||||
|
oldValue?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(ref UniqueRef<T> other)
|
||||||
|
{
|
||||||
|
if (Unsafe.AreSame(ref this, ref other))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Reset(other.Release());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set<TFrom>(ref UniqueRef<TFrom> other) where TFrom : class, T
|
||||||
|
{
|
||||||
|
Reset(other.Release());
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Release()
|
||||||
|
{
|
||||||
|
T oldValue = _value;
|
||||||
|
_value = null;
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -137,7 +137,7 @@ namespace LibHac.Fs
|
|||||||
/// must not be reinitialized or disposed for the lifetime of the created <see cref="Path"/>.
|
/// must not be reinitialized or disposed for the lifetime of the created <see cref="Path"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The created <see cref="Path"/>.</returns>
|
/// <returns>The created <see cref="Path"/>.</returns>
|
||||||
public readonly Path GetPath()
|
public readonly Path DangerousGetPath()
|
||||||
{
|
{
|
||||||
return new Path
|
return new Path
|
||||||
{
|
{
|
||||||
@ -1113,6 +1113,20 @@ namespace LibHac.Fs
|
|||||||
return SetUpFixedPath(ref path, pathBuffer);
|
return SetUpFixedPath(ref path, pathBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /%s/%s
|
||||||
|
internal static Result SetUpFixedPathDoubleEntry(ref Path path, Span<byte> pathBuffer,
|
||||||
|
ReadOnlySpan<byte> entryName1, ReadOnlySpan<byte> entryName2)
|
||||||
|
{
|
||||||
|
var sb = new U8StringBuilder(pathBuffer);
|
||||||
|
sb.Append((byte)'/').Append(entryName1)
|
||||||
|
.Append((byte)'/').Append(entryName2);
|
||||||
|
|
||||||
|
if (sb.Overflowed)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
return SetUpFixedPath(ref path, pathBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
// /%016llx
|
// /%016llx
|
||||||
internal static Result SetUpFixedPathSaveId(ref Path path, Span<byte> pathBuffer, ulong saveDataId)
|
internal static Result SetUpFixedPathSaveId(ref Path path, Span<byte> pathBuffer, ulong saveDataId)
|
||||||
{
|
{
|
||||||
|
@ -5,22 +5,24 @@ namespace LibHac.Fs
|
|||||||
{
|
{
|
||||||
public class FileStorageBasedFileSystem : FileStorage2
|
public class FileStorageBasedFileSystem : FileStorage2
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<IFileSystem> BaseFileSystem { get; set; }
|
private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
|
||||||
private IFile BaseFile { get; set; }
|
private UniqueRef<IFile> _baseFile;
|
||||||
|
|
||||||
public FileStorageBasedFileSystem()
|
public FileStorageBasedFileSystem()
|
||||||
{
|
{
|
||||||
FileSize = SizeNotInitialized;
|
FileSize = SizeNotInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, U8Span path, OpenMode mode)
|
public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path,
|
||||||
|
OpenMode mode)
|
||||||
{
|
{
|
||||||
Result rc = baseFileSystem.Target.OpenFile(out IFile file, path, mode);
|
using var baseFile = new UniqueRef<IFile>();
|
||||||
|
Result rc = baseFileSystem.Target.OpenFile(ref baseFile.Ref(), in path, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
SetFile(file);
|
SetFile(baseFile.Get);
|
||||||
BaseFile = file;
|
_baseFileSystem = Shared.Move(ref baseFileSystem);
|
||||||
BaseFileSystem = Shared.Move(ref baseFileSystem);
|
_baseFile.Set(ref _baseFile.Ref());
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@ -29,8 +31,8 @@ namespace LibHac.Fs
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
BaseFile?.Dispose();
|
_baseFile.Dispose();
|
||||||
BaseFileSystem?.Dispose();
|
_baseFileSystem?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
@ -7,33 +7,33 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
internal class DirectoryAccessor : IDisposable
|
internal class DirectoryAccessor : IDisposable
|
||||||
{
|
{
|
||||||
private IDirectory _directory;
|
private UniqueRef<IDirectory> _directory;
|
||||||
private FileSystemAccessor _parentFileSystem;
|
private FileSystemAccessor _parentFileSystem;
|
||||||
|
|
||||||
public DirectoryAccessor(ref IDirectory directory, FileSystemAccessor parentFileSystem)
|
public DirectoryAccessor(ref UniqueRef<IDirectory> directory, FileSystemAccessor parentFileSystem)
|
||||||
{
|
{
|
||||||
_directory = Shared.Move(ref directory);
|
_directory = new UniqueRef<IDirectory>(ref directory);
|
||||||
_parentFileSystem = parentFileSystem;
|
_parentFileSystem = parentFileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
IDirectory directory = Shared.Move(ref _directory);
|
_directory.Reset();
|
||||||
directory?.Dispose();
|
|
||||||
|
|
||||||
_parentFileSystem.NotifyCloseDirectory(this);
|
_parentFileSystem.NotifyCloseDirectory(this);
|
||||||
|
|
||||||
|
_directory.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileSystemAccessor GetParent() => _parentFileSystem;
|
public FileSystemAccessor GetParent() => _parentFileSystem;
|
||||||
|
|
||||||
public Result Read(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
public Result Read(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
||||||
{
|
{
|
||||||
return _directory.Read(out entriesRead, entryBuffer);
|
return _directory.Get.Read(out entriesRead, entryBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result GetEntryCount(out long entryCount)
|
public Result GetEntryCount(out long entryCount)
|
||||||
{
|
{
|
||||||
return _directory.GetEntryCount(out entryCount);
|
return _directory.Get.GetEntryCount(out entryCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
private const string NeedFlushMessage = "Error: nn::fs::CloseFile() failed because the file was not flushed.\n";
|
private const string NeedFlushMessage = "Error: nn::fs::CloseFile() failed because the file was not flushed.\n";
|
||||||
|
|
||||||
private IFile _file;
|
private UniqueRef<IFile> _file;
|
||||||
private FileSystemAccessor _parentFileSystem;
|
private FileSystemAccessor _parentFileSystem;
|
||||||
private WriteState _writeState;
|
private WriteState _writeState;
|
||||||
private Result _lastResult;
|
private Result _lastResult;
|
||||||
@ -30,12 +30,12 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
internal HorizonClient Hos { get; }
|
internal HorizonClient Hos { get; }
|
||||||
|
|
||||||
public FileAccessor(HorizonClient hosClient, ref IFile file, FileSystemAccessor parentFileSystem,
|
public FileAccessor(HorizonClient hosClient, ref UniqueRef<IFile> file, FileSystemAccessor parentFileSystem,
|
||||||
OpenMode mode)
|
OpenMode mode)
|
||||||
{
|
{
|
||||||
Hos = hosClient;
|
Hos = hosClient;
|
||||||
|
|
||||||
_file = Shared.Move(ref file);
|
_file = new UniqueRef<IFile>(ref file);
|
||||||
_parentFileSystem = parentFileSystem;
|
_parentFileSystem = parentFileSystem;
|
||||||
_writeState = WriteState.None;
|
_writeState = WriteState.None;
|
||||||
_lastResult = Result.Success;
|
_lastResult = Result.Success;
|
||||||
@ -52,8 +52,7 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
_parentFileSystem?.NotifyCloseFile(this);
|
_parentFileSystem?.NotifyCloseFile(this);
|
||||||
|
|
||||||
IFile file = Shared.Move(ref _file);
|
_file.Dispose();
|
||||||
file?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenMode GetOpenMode() => _openMode;
|
public OpenMode GetOpenMode() => _openMode;
|
||||||
@ -77,7 +76,7 @@ namespace LibHac.Fs.Impl
|
|||||||
public Result ReadWithoutCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
public Result ReadWithoutCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||||
in ReadOption option)
|
in ReadOption option)
|
||||||
{
|
{
|
||||||
return _file.Read(out bytesRead, offset, destination, in option);
|
return _file.Get.Read(out bytesRead, offset, destination, in option);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result ReadWithCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
private Result ReadWithCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||||
@ -166,7 +165,7 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Result rc = UpdateLastResult(_file.Write(offset, source, in option));
|
Result rc = UpdateLastResult(_file.Get.Write(offset, source, in option));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +181,7 @@ namespace LibHac.Fs.Impl
|
|||||||
using ScopedSetter<WriteState> setter =
|
using ScopedSetter<WriteState> setter =
|
||||||
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
||||||
|
|
||||||
Result rc = UpdateLastResult(_file.Flush());
|
Result rc = UpdateLastResult(_file.Get.Flush());
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
setter.Set(WriteState.None);
|
setter.Set(WriteState.None);
|
||||||
@ -198,7 +197,7 @@ namespace LibHac.Fs.Impl
|
|||||||
using ScopedSetter<WriteState> setter =
|
using ScopedSetter<WriteState> setter =
|
||||||
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
||||||
|
|
||||||
Result rc = UpdateLastResult(_file.SetSize(size));
|
Result rc = UpdateLastResult(_file.Get.SetSize(size));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (_filePathHash.Data != 0)
|
if (_filePathHash.Data != 0)
|
||||||
@ -217,13 +216,13 @@ namespace LibHac.Fs.Impl
|
|||||||
if (_lastResult.IsFailure())
|
if (_lastResult.IsFailure())
|
||||||
return _lastResult;
|
return _lastResult;
|
||||||
|
|
||||||
return _file.GetSize(out size);
|
return _file.Get.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
public Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||||
ReadOnlySpan<byte> inBuffer)
|
ReadOnlySpan<byte> inBuffer)
|
||||||
{
|
{
|
||||||
return _file.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
return _file.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,76 +331,58 @@ namespace LibHac.Fs.Impl
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenFile(out FileAccessor file, U8Span path, OpenMode mode)
|
public Result OpenFile(ref UniqueRef<FileAccessor> outFile, U8Span path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IFile iFile = null;
|
using var file = new UniqueRef<IFile>();
|
||||||
try
|
rc = _fileSystem.OpenFile(ref file.Ref(), in pathNormalized, mode);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var accessor = new FileAccessor(Hos, ref file.Ref(), this, mode);
|
||||||
|
|
||||||
|
using (ScopedLock.Lock(ref _openListLock))
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenFile(out iFile, in pathNormalized, mode);
|
_openFiles.AddLast(accessor);
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
var fileAccessor = new FileAccessor(Hos, ref iFile, this, mode);
|
|
||||||
|
|
||||||
using (ScopedLock.Lock(ref _openListLock))
|
|
||||||
{
|
|
||||||
_openFiles.AddLast(fileAccessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_isPathCacheAttached)
|
|
||||||
{
|
|
||||||
if (mode.HasFlag(OpenMode.AllowAppend))
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file = Shared.Move(ref fileAccessor);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
if (_isPathCacheAttached)
|
||||||
{
|
{
|
||||||
iFile?.Dispose();
|
if (mode.HasFlag(OpenMode.AllowAppend))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outFile.Reset(accessor);
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenDirectory(out DirectoryAccessor directory, U8Span path, OpenDirectoryMode mode)
|
public Result OpenDirectory(ref UniqueRef<DirectoryAccessor> outDirectory, U8Span path, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IDirectory iDirectory = null;
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
try
|
rc = _fileSystem.OpenDirectory(ref directory.Ref(), in pathNormalized, mode);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var accessor = new DirectoryAccessor(ref directory.Ref(), this);
|
||||||
|
|
||||||
|
using (ScopedLock.Lock(ref _openListLock))
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenDirectory(out iDirectory, in pathNormalized, mode);
|
_openDirectories.AddLast(accessor);
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
var directoryAccessor = new DirectoryAccessor(ref iDirectory, this);
|
|
||||||
|
|
||||||
using (ScopedLock.Lock(ref _openListLock))
|
|
||||||
{
|
|
||||||
_openDirectories.AddLast(directoryAccessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
directory = Shared.Move(ref directoryAccessor);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
iDirectory?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outDirectory.Reset(accessor);
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Commit()
|
public Result Commit()
|
||||||
|
@ -203,10 +203,8 @@ namespace LibHac.Fs.Fsa
|
|||||||
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
|
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
|
||||||
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
||||||
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns>
|
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns>
|
||||||
public Result OpenFile(out IFile file, U8Span path, OpenMode mode)
|
public Result OpenFile(ref UniqueRef<IFile> file, U8Span path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
if (path.IsNull())
|
if (path.IsNull())
|
||||||
return ResultFs.NullptrArgument.Log();
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
@ -214,7 +212,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
Result rs = pathNormalized.InitializeWithNormalization(path);
|
Result rs = pathNormalized.InitializeWithNormalization(path);
|
||||||
if (rs.IsFailure()) return rs;
|
if (rs.IsFailure()) return rs;
|
||||||
|
|
||||||
return DoOpenFile(out file, in pathNormalized, mode);
|
return DoOpenFile(ref file, in pathNormalized, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -228,7 +226,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
|
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
|
||||||
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
||||||
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns>
|
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns>
|
||||||
public Result OpenFile(out IFile file, in Path path, OpenMode mode)
|
public Result OpenFile(ref UniqueRef<IFile> file, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
if ((mode & OpenMode.ReadWrite) == 0 || (mode & ~OpenMode.All) != 0)
|
if ((mode & OpenMode.ReadWrite) == 0 || (mode & ~OpenMode.All) != 0)
|
||||||
{
|
{
|
||||||
@ -236,28 +234,24 @@ namespace LibHac.Fs.Fsa
|
|||||||
return ResultFs.InvalidOpenMode.Log();
|
return ResultFs.InvalidOpenMode.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
return DoOpenFile(out file, in path, mode);
|
return DoOpenFile(ref file, in path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an <see cref="IDirectory"/> instance for enumerating the specified directory.
|
/// Creates an <see cref="IDirectory"/> instance for enumerating the specified directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="directory">If the operation returns successfully,
|
/// <param name="outDirectory"></param>
|
||||||
/// An <see cref="IDirectory"/> instance for the specified directory.</param>
|
|
||||||
/// <param name="path">The directory's full path.</param>
|
/// <param name="path">The directory's full path.</param>
|
||||||
/// <param name="mode">Specifies which sub-entries should be enumerated.</param>
|
/// <param name="mode">Specifies which sub-entries should be enumerated.</param>
|
||||||
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
|
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
|
||||||
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a file.</returns>
|
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a file.</returns>
|
||||||
public Result OpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
public Result OpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
if ((mode & OpenDirectoryMode.All) == 0 ||
|
if ((mode & OpenDirectoryMode.All) == 0 ||
|
||||||
(mode & ~(OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize)) != 0)
|
(mode & ~(OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize)) != 0)
|
||||||
{
|
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
return ResultFs.InvalidOpenMode.Log();
|
return ResultFs.InvalidOpenMode.Log();
|
||||||
}
|
|
||||||
|
|
||||||
return DoOpenDirectory(out directory, in path, mode);
|
return DoOpenDirectory(ref outDirectory, in path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -325,8 +319,9 @@ namespace LibHac.Fs.Fsa
|
|||||||
return ResultFs.NotImplemented.Log();
|
return ResultFs.NotImplemented.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Result DoOpenFile(out IFile file, in Path path, OpenMode mode);
|
protected abstract Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode);
|
||||||
protected abstract Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode);
|
protected abstract Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode);
|
||||||
protected abstract Result DoCommit();
|
protected abstract Result DoCommit();
|
||||||
|
|
||||||
protected virtual Result DoCommitProvisionally(long counter) => ResultFs.NotImplemented.Log();
|
protected virtual Result DoCommitProvisionally(long counter) => ResultFs.NotImplemented.Log();
|
||||||
|
@ -508,27 +508,27 @@ namespace LibHac.Fs.Fsa
|
|||||||
fs.Impl.AbortIfNeeded(rc);
|
fs.Impl.AbortIfNeeded(rc);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
FileAccessor accessor;
|
using var file = new UniqueRef<FileAccessor>();
|
||||||
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
||||||
{
|
{
|
||||||
Tick start = fs.Hos.Os.GetSystemTick();
|
Tick start = fs.Hos.Os.GetSystemTick();
|
||||||
rc = fileSystem.OpenFile(out accessor, subPath, mode);
|
rc = fileSystem.OpenFile(ref file.Ref(), subPath, mode);
|
||||||
Tick end = fs.Hos.Os.GetSystemTick();
|
Tick end = fs.Hos.Os.GetSystemTick();
|
||||||
|
|
||||||
fs.Impl.OutputAccessLog(rc, start, end, accessor, new U8Span(logBuffer));
|
fs.Impl.OutputAccessLog(rc, start, end, file.Get, new U8Span(logBuffer));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = fileSystem.OpenFile(out accessor, subPath, mode);
|
rc = fileSystem.OpenFile(ref file.Ref(), subPath, mode);
|
||||||
}
|
}
|
||||||
fs.Impl.AbortIfNeeded(rc);
|
fs.Impl.AbortIfNeeded(rc);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
handle = new FileHandle(accessor);
|
handle = new FileHandle(file.Release());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result OpenFile(this FileSystemClient fs, out FileHandle handle, IFile file, OpenMode mode)
|
public static Result OpenFile(this FileSystemClient fs, out FileHandle handle, ref UniqueRef<IFile> file, OpenMode mode)
|
||||||
{
|
{
|
||||||
var accessor = new FileAccessor(fs.Hos, ref file, null, mode);
|
var accessor = new FileAccessor(fs.Hos, ref file, null, mode);
|
||||||
handle = new FileHandle(accessor);
|
handle = new FileHandle(accessor);
|
||||||
@ -565,23 +565,24 @@ namespace LibHac.Fs.Fsa
|
|||||||
fs.Impl.AbortIfNeeded(rc);
|
fs.Impl.AbortIfNeeded(rc);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
DirectoryAccessor accessor;
|
using var accessor = new UniqueRef<DirectoryAccessor>();
|
||||||
|
|
||||||
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
||||||
{
|
{
|
||||||
Tick start = fs.Hos.Os.GetSystemTick();
|
Tick start = fs.Hos.Os.GetSystemTick();
|
||||||
rc = fileSystem.OpenDirectory(out accessor, subPath, mode);
|
rc = fileSystem.OpenDirectory(ref accessor.Ref(), subPath, mode);
|
||||||
Tick end = fs.Hos.Os.GetSystemTick();
|
Tick end = fs.Hos.Os.GetSystemTick();
|
||||||
|
|
||||||
fs.Impl.OutputAccessLog(rc, start, end, accessor, new U8Span(logBuffer));
|
fs.Impl.OutputAccessLog(rc, start, end, accessor, new U8Span(logBuffer));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = fileSystem.OpenDirectory(out accessor, subPath, mode);
|
rc = fileSystem.OpenDirectory(ref accessor.Ref(), subPath, mode);
|
||||||
}
|
}
|
||||||
fs.Impl.AbortIfNeeded(rc);
|
fs.Impl.AbortIfNeeded(rc);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
handle = new DirectoryHandle(accessor);
|
handle = new DirectoryHandle(accessor.Release());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,25 +68,22 @@ namespace LibHac.Fs
|
|||||||
return FsTable.DeleteFile(new U8Span(path.GetString()));
|
return FsTable.DeleteFile(new U8Span(path.GetString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
Result rc = FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dirNode);
|
Result rc = FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dirNode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = new MemoryDirectory(dirNode, mode);
|
outDirectory.Reset(new MemoryDirectory(dirNode, mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
Result rc = FsTable.GetFile(new U8Span(path.GetString()), out FileNode fileNode);
|
Result rc = FsTable.GetFile(new U8Span(path.GetString()), out FileNode fileNode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new MemoryFile(mode, fileNode.File);
|
outFile.Reset(new MemoryFile(mode, fileNode.File));
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -252,10 +252,8 @@ namespace LibHac.Fs.Impl
|
|||||||
return BaseFs.Target.GetTotalSpaceSize(out totalSpace, in sfPath);
|
return BaseFs.Target.GetTotalSpaceSize(out totalSpace, in sfPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
Result rc = GetPathForServiceObject(out PathSf sfPath, path);
|
Result rc = GetPathForServiceObject(out PathSf sfPath, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -265,7 +263,7 @@ namespace LibHac.Fs.Impl
|
|||||||
rc = BaseFs.Target.OpenFile(out sfFile, in sfPath, (uint)mode);
|
rc = BaseFs.Target.OpenFile(out sfFile, in sfPath, (uint)mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new FileServiceObjectAdapter(sfFile);
|
outFile.Reset(new FileServiceObjectAdapter(sfFile));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -274,10 +272,9 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
Result rc = GetPathForServiceObject(out PathSf sfPath, path);
|
Result rc = GetPathForServiceObject(out PathSf sfPath, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -287,7 +284,7 @@ namespace LibHac.Fs.Impl
|
|||||||
rc = BaseFs.Target.OpenDirectory(out sfDir, in sfPath, (uint)mode);
|
rc = BaseFs.Target.OpenDirectory(out sfDir, in sfPath, (uint)mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = new DirectoryServiceObjectAdapter(sfDir);
|
outDirectory.Reset(new DirectoryServiceObjectAdapter(sfDir));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -33,10 +33,12 @@ namespace LibHac.FsSrv
|
|||||||
if (!programInfo.AccessControl.CanCall(OperationType.OpenAccessFailureDetectionEventNotifier))
|
if (!programInfo.AccessControl.CanCall(OperationType.OpenAccessFailureDetectionEventNotifier))
|
||||||
return ResultFs.PermissionDenied.Log();
|
return ResultFs.PermissionDenied.Log();
|
||||||
|
|
||||||
rc = _serviceImpl.CreateNotifier(out IEventNotifier tempNotifier, processId, notifyOnDeepRetry);
|
using var tempNotifier = new UniqueRef<IEventNotifier>();
|
||||||
|
|
||||||
|
rc = _serviceImpl.CreateNotifier(ref tempNotifier.Ref(), processId, notifyOnDeepRetry);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
notifier = new ReferenceCountedDisposable<IEventNotifier>(tempNotifier);
|
notifier = new ReferenceCountedDisposable<IEventNotifier>(tempNotifier.Release());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.FsSrv.Impl;
|
using LibHac.FsSrv.Impl;
|
||||||
using LibHac.FsSrv.Sf;
|
using LibHac.FsSrv.Sf;
|
||||||
using LibHac.Svc;
|
using LibHac.Svc;
|
||||||
@ -30,9 +31,9 @@ namespace LibHac.FsSrv
|
|||||||
return registry.GetProgramInfo(out programInfo, processId);
|
return registry.GetProgramInfo(out programInfo, processId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result CreateNotifier(out IEventNotifier notifier, ulong processId, bool notifyOnDeepRetry)
|
public Result CreateNotifier(ref UniqueRef<IEventNotifier> notifier, ulong processId, bool notifyOnDeepRetry)
|
||||||
{
|
{
|
||||||
return _eventManager.CreateNotifier(out notifier, processId, notifyOnDeepRetry);
|
return _eventManager.CreateNotifier(ref notifier, processId, notifyOnDeepRetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetAccessFailureDetection(ulong processId)
|
public void ResetAccessFailureDetection(ulong processId)
|
||||||
|
@ -36,9 +36,8 @@ namespace LibHac.FsSrv
|
|||||||
ReferenceCountedDisposable<IFileSystem> tempFs = null;
|
ReferenceCountedDisposable<IFileSystem> tempFs = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const int pathBufferLength = 0x40;
|
|
||||||
|
|
||||||
// Hack around error CS8350.
|
// Hack around error CS8350.
|
||||||
|
const int pathBufferLength = 0x40;
|
||||||
Span<byte> buffer = stackalloc byte[pathBufferLength];
|
Span<byte> buffer = stackalloc byte[pathBufferLength];
|
||||||
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
|
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
|
||||||
Span<byte> pathBuffer = MemoryMarshal.CreateSpan(ref bufferRef, pathBufferLength);
|
Span<byte> pathBuffer = MemoryMarshal.CreateSpan(ref bufferRef, pathBufferLength);
|
||||||
@ -49,11 +48,8 @@ namespace LibHac.FsSrv
|
|||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using var path = new Path();
|
using var path = new Path();
|
||||||
var sb = new U8StringBuilder(pathBuffer);
|
rc = PathFunctions.SetUpFixedPathSingleEntry(ref path.Ref(), pathBuffer,
|
||||||
sb.Append((byte)'/')
|
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
||||||
.Append(CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
|
||||||
|
|
||||||
rc = PathFunctions.SetUpFixedPath(ref path.Ref(), pathBuffer);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
tempFs = Shared.Move(ref fileSystem);
|
tempFs = Shared.Move(ref fileSystem);
|
||||||
@ -66,13 +62,9 @@ namespace LibHac.FsSrv
|
|||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using var path = new Path();
|
using var path = new Path();
|
||||||
var sb = new U8StringBuilder(pathBuffer);
|
rc = PathFunctions.SetUpFixedPathDoubleEntry(ref path.Ref(), pathBuffer,
|
||||||
sb.Append((byte)'/')
|
CommonPaths.SdCardNintendoRootDirectoryName,
|
||||||
.Append(CommonPaths.SdCardNintendoRootDirectoryName)
|
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
||||||
.Append((byte)'/')
|
|
||||||
.Append(CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.SdCard));
|
|
||||||
|
|
||||||
rc = PathFunctions.SetUpFixedPath(ref path.Ref(), pathBuffer);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
tempFs = Shared.Move(ref fileSystem);
|
tempFs = Shared.Move(ref fileSystem);
|
||||||
|
@ -12,10 +12,12 @@ namespace LibHac.FsSrv.FsCreator
|
|||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out subDirFileSystem);
|
UnsafeHelpers.SkipParamInit(out subDirFileSystem);
|
||||||
|
|
||||||
Result rc = baseFileSystem.Target.OpenDirectory(out IDirectory dir, in path, OpenDirectoryMode.Directory);
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
|
||||||
|
Result rc = baseFileSystem.Target.OpenDirectory(ref directory.Ref(), in path, OpenDirectoryMode.Directory);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
dir.Dispose();
|
directory.Reset();
|
||||||
|
|
||||||
ReferenceCountedDisposable<SubdirectoryFileSystem> subFs = null;
|
ReferenceCountedDisposable<SubdirectoryFileSystem> subFs = null;
|
||||||
try
|
try
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsSrv
|
namespace LibHac.FsSrv
|
||||||
{
|
{
|
||||||
public interface ISaveDataIndexerManager
|
public interface ISaveDataIndexerManager
|
||||||
{
|
{
|
||||||
Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit, SaveDataSpaceId spaceId);
|
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool neededInit, SaveDataSpaceId spaceId);
|
||||||
void ResetIndexer(SaveDataSpaceId spaceId);
|
void ResetIndexer(SaveDataSpaceId spaceId);
|
||||||
void InvalidateIndexer(SaveDataSpaceId spaceId);
|
void InvalidateIndexer(SaveDataSpaceId spaceId);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.FsSrv.Sf;
|
using LibHac.FsSrv.Sf;
|
||||||
using LibHac.Svc;
|
using LibHac.Svc;
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
{
|
{
|
||||||
public class AccessFailureDetectionEventManager
|
public class AccessFailureDetectionEventManager
|
||||||
{
|
{
|
||||||
public Result CreateNotifier(out IEventNotifier notifier, ulong processId, bool notifyOnDeepRetry)
|
public Result CreateNotifier(ref UniqueRef<IEventNotifier> notifier, ulong processId, bool notifyOnDeepRetry)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
@ -17,10 +18,10 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once RedundantOverriddenMember
|
// ReSharper disable once RedundantOverriddenMember
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
// Todo: Implement
|
// Todo: Implement
|
||||||
return base.DoOpenFile(out file, path, mode);
|
return base.DoOpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,10 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once RedundantOverriddenMember
|
// ReSharper disable once RedundantOverriddenMember
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
// Todo: Implement
|
// Todo: Implement
|
||||||
return base.DoOpenFile(out file, path, mode);
|
return base.DoOpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,20 +24,20 @@ namespace LibHac.FsSrv.Impl
|
|||||||
public class FileInterfaceAdapter : IFileSf
|
public class FileInterfaceAdapter : IFileSf
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
||||||
private IFile _baseFile;
|
private UniqueRef<IFile> _baseFile;
|
||||||
private bool _allowAllOperations;
|
private bool _allowAllOperations;
|
||||||
|
|
||||||
public FileInterfaceAdapter(IFile baseFile,
|
public FileInterfaceAdapter(ref UniqueRef<IFile> baseFile,
|
||||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
|
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
|
||||||
{
|
{
|
||||||
_baseFile = baseFile;
|
_baseFile = new UniqueRef<IFile>(ref baseFile);
|
||||||
_parentFs = Shared.Move(ref parentFileSystem);
|
_parentFs = Shared.Move(ref parentFileSystem);
|
||||||
_allowAllOperations = allowAllOperations;
|
_allowAllOperations = allowAllOperations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_baseFile?.Dispose();
|
_baseFile.Dispose();
|
||||||
_parentFs?.Dispose();
|
_parentFs?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
|
|
||||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||||
{
|
{
|
||||||
rc = _baseFile.Read(out tmpBytesRead, offset, destination.Buffer.Slice(0, (int)size), option);
|
rc = _baseFile.Get.Read(out tmpBytesRead, offset, destination.Buffer.Slice(0, (int)size), option);
|
||||||
|
|
||||||
// Retry on ResultDataCorrupted
|
// Retry on ResultDataCorrupted
|
||||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||||
@ -81,12 +81,12 @@ namespace LibHac.FsSrv.Impl
|
|||||||
using var scopedPriorityChanger =
|
using var scopedPriorityChanger =
|
||||||
new ScopedThreadPriorityChangerByAccessPriority(ScopedThreadPriorityChangerByAccessPriority.AccessMode.Write);
|
new ScopedThreadPriorityChangerByAccessPriority(ScopedThreadPriorityChangerByAccessPriority.AccessMode.Write);
|
||||||
|
|
||||||
return _baseFile.Write(offset, source.Buffer.Slice(0, (int)size), option);
|
return _baseFile.Get.Write(offset, source.Buffer.Slice(0, (int)size), option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Flush()
|
public Result Flush()
|
||||||
{
|
{
|
||||||
return _baseFile.Flush();
|
return _baseFile.Get.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result SetSize(long size)
|
public Result SetSize(long size)
|
||||||
@ -94,7 +94,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
if (size < 0)
|
if (size < 0)
|
||||||
return ResultFs.InvalidSize.Log();
|
return ResultFs.InvalidSize.Log();
|
||||||
|
|
||||||
return _baseFile.SetSize(size);
|
return _baseFile.Get.SetSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result GetSize(out long size)
|
public Result GetSize(out long size)
|
||||||
@ -107,7 +107,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
|
|
||||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||||
{
|
{
|
||||||
rc = _baseFile.GetSize(out tmpSize);
|
rc = _baseFile.Get.GetSize(out tmpSize);
|
||||||
|
|
||||||
// Retry on ResultDataCorrupted
|
// Retry on ResultDataCorrupted
|
||||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||||
@ -129,7 +129,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
{
|
{
|
||||||
Unsafe.SkipInit(out QueryRangeInfo info);
|
Unsafe.SkipInit(out QueryRangeInfo info);
|
||||||
|
|
||||||
Result rc = _baseFile.OperateRange(SpanHelpers.AsByteSpan(ref info), OperationId.QueryRange, offset,
|
Result rc = _baseFile.Get.OperateRange(SpanHelpers.AsByteSpan(ref info), OperationId.QueryRange, offset,
|
||||||
size, ReadOnlySpan<byte>.Empty);
|
size, ReadOnlySpan<byte>.Empty);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
else if (operationId == (int)OperationId.InvalidateCache)
|
else if (operationId == (int)OperationId.InvalidateCache)
|
||||||
{
|
{
|
||||||
Result rc = _baseFile.OperateRange(Span<byte>.Empty, OperationId.InvalidateCache, offset, size,
|
Result rc = _baseFile.Get.OperateRange(Span<byte>.Empty, OperationId.InvalidateCache, offset, size,
|
||||||
ReadOnlySpan<byte>.Empty);
|
ReadOnlySpan<byte>.Empty);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
Result rc = PermissionCheck((OperationId)operationId, this);
|
Result rc = PermissionCheck((OperationId)operationId, this);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFile.OperateRange(outBuffer.Buffer, (OperationId)operationId, offset, size, inBuffer.Buffer);
|
rc = _baseFile.Get.OperateRange(outBuffer.Buffer, (OperationId)operationId, offset, size, inBuffer.Buffer);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -179,18 +179,18 @@ namespace LibHac.FsSrv.Impl
|
|||||||
public class DirectoryInterfaceAdapter : IDirectorySf
|
public class DirectoryInterfaceAdapter : IDirectorySf
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
||||||
private IDirectory _baseDirectory;
|
private UniqueRef<IDirectory> _baseDirectory;
|
||||||
|
|
||||||
public DirectoryInterfaceAdapter(IDirectory baseDirectory,
|
public DirectoryInterfaceAdapter(ref UniqueRef<IDirectory> baseDirectory,
|
||||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
|
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
|
||||||
{
|
{
|
||||||
_baseDirectory = baseDirectory;
|
_baseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
|
||||||
_parentFs = Shared.Move(ref parentFileSystem);
|
_parentFs = Shared.Move(ref parentFileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_baseDirectory?.Dispose();
|
_baseDirectory.Dispose();
|
||||||
_parentFs?.Dispose();
|
_parentFs?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
|
|
||||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||||
{
|
{
|
||||||
rc = _baseDirectory.Read(out numRead, entries);
|
rc = _baseDirectory.Get.Read(out numRead, entries);
|
||||||
|
|
||||||
// Retry on ResultDataCorrupted
|
// Retry on ResultDataCorrupted
|
||||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||||
@ -223,7 +223,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||||
|
|
||||||
Result rc = _baseDirectory.GetEntryCount(out long count);
|
Result rc = _baseDirectory.Get.GetEntryCount(out long count);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
entryCount = count;
|
entryCount = count;
|
||||||
@ -496,75 +496,63 @@ namespace LibHac.FsSrv.Impl
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in PathSf path, uint mode)
|
public Result OpenFile(out ReferenceCountedDisposable<IFileSf> outFile, in PathSf path, uint mode)
|
||||||
{
|
{
|
||||||
const int maxTryCount = 2;
|
const int maxTryCount = 2;
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
UnsafeHelpers.SkipParamInit(out outFile);
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IFile fileInterface = null;
|
using var file = new UniqueRef<IFile>();
|
||||||
try
|
|
||||||
|
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||||
{
|
{
|
||||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
rc = _baseFileSystem.Target.OpenFile(ref file.Ref(), in pathNormalized, (OpenMode)mode);
|
||||||
{
|
|
||||||
rc = _baseFileSystem.Target.OpenFile(out fileInterface, in pathNormalized, (OpenMode)mode);
|
|
||||||
|
|
||||||
// Retry on ResultDataCorrupted
|
// Retry on ResultDataCorrupted
|
||||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
|
||||||
var adapter = new FileInterfaceAdapter(Shared.Move(ref fileInterface), ref selfReference, _allowAllOperations);
|
|
||||||
file = new ReferenceCountedDisposable<IFileSf>(adapter);
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
fileInterface?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
||||||
|
var adapter = new FileInterfaceAdapter(ref file.Ref(), ref selfReference, _allowAllOperations);
|
||||||
|
outFile = new ReferenceCountedDisposable<IFileSf>(adapter);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in PathSf path, uint mode)
|
public Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> outDirectory, in PathSf path, uint mode)
|
||||||
{
|
{
|
||||||
const int maxTryCount = 2;
|
const int maxTryCount = 2;
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
UnsafeHelpers.SkipParamInit(out outDirectory);
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IDirectory dirInterface = null;
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
try
|
|
||||||
|
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||||
{
|
{
|
||||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
rc = _baseFileSystem.Target.OpenDirectory(ref directory.Ref(), in pathNormalized,
|
||||||
{
|
(OpenDirectoryMode)mode);
|
||||||
rc = _baseFileSystem.Target.OpenDirectory(out dirInterface, in pathNormalized,
|
|
||||||
(OpenDirectoryMode)mode);
|
|
||||||
|
|
||||||
// Retry on ResultDataCorrupted
|
// Retry on ResultDataCorrupted
|
||||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
|
||||||
var adapter = new DirectoryInterfaceAdapter(dirInterface, ref selfReference);
|
|
||||||
directory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
dirInterface?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
||||||
|
var adapter = new DirectoryInterfaceAdapter(ref directory.Ref(), ref selfReference);
|
||||||
|
outDirectory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Commit()
|
public Result Commit()
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
namespace LibHac.FsSrv.Impl
|
namespace LibHac.FsSrv.Impl
|
||||||
{
|
{
|
||||||
public interface IEntryOpenCountSemaphoreManager : IDisposable
|
public interface IEntryOpenCountSemaphoreManager : IDisposable
|
||||||
{
|
{
|
||||||
Result TryAcquireEntryOpenCountSemaphore(out IUniqueLock semaphore);
|
Result TryAcquireEntryOpenCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphore);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,50 +8,48 @@ namespace LibHac.FsSrv.Impl
|
|||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public abstract class IResultConvertFile : IFile
|
public abstract class IResultConvertFile : IFile
|
||||||
{
|
{
|
||||||
protected IFile BaseFile;
|
protected UniqueRef<IFile> BaseFile;
|
||||||
|
|
||||||
protected IResultConvertFile(IFile baseFile)
|
protected IResultConvertFile(ref UniqueRef<IFile> baseFile)
|
||||||
{
|
{
|
||||||
BaseFile = baseFile;
|
BaseFile = new UniqueRef<IFile>(ref baseFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
BaseFile?.Dispose();
|
BaseFile.Dispose();
|
||||||
BaseFile = null;
|
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
|
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.Read(out bytesRead, offset, destination, option));
|
return ConvertResult(BaseFile.Get.Read(out bytesRead, offset, destination, option));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.Write(offset, source, option));
|
return ConvertResult(BaseFile.Get.Write(offset, source, option));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoFlush()
|
protected override Result DoFlush()
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.Flush());
|
return ConvertResult(BaseFile.Get.Flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoSetSize(long size)
|
protected override Result DoSetSize(long size)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.SetSize(size));
|
return ConvertResult(BaseFile.Get.SetSize(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetSize(out long size)
|
protected override Result DoGetSize(out long size)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.GetSize(out size));
|
return ConvertResult(BaseFile.Get.GetSize(out size));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||||
ReadOnlySpan<byte> inBuffer)
|
ReadOnlySpan<byte> inBuffer)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer));
|
return ConvertResult(BaseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Result ConvertResult(Result result);
|
protected abstract Result ConvertResult(Result result);
|
||||||
@ -60,29 +58,27 @@ namespace LibHac.FsSrv.Impl
|
|||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public abstract class IResultConvertDirectory : IDirectory
|
public abstract class IResultConvertDirectory : IDirectory
|
||||||
{
|
{
|
||||||
protected IDirectory BaseDirectory;
|
protected UniqueRef<IDirectory> BaseDirectory;
|
||||||
|
|
||||||
protected IResultConvertDirectory(IDirectory baseDirectory)
|
protected IResultConvertDirectory(ref UniqueRef<IDirectory> baseDirectory)
|
||||||
{
|
{
|
||||||
BaseDirectory = baseDirectory;
|
BaseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
BaseDirectory?.Dispose();
|
BaseDirectory.Dispose();
|
||||||
BaseDirectory = null;
|
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseDirectory.Read(out entriesRead, entryBuffer));
|
return ConvertResult(BaseDirectory.Get.Read(out entriesRead, entryBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetEntryCount(out long entryCount)
|
protected override Result DoGetEntryCount(out long entryCount)
|
||||||
{
|
{
|
||||||
return ConvertResult(BaseDirectory.GetEntryCount(out entryCount));
|
return ConvertResult(BaseDirectory.Get.GetEntryCount(out entryCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Result ConvertResult(Result result);
|
protected abstract Result ConvertResult(Result result);
|
||||||
@ -150,9 +146,9 @@ namespace LibHac.FsSrv.Impl
|
|||||||
return ConvertResult(BaseFileSystem.Target.GetEntryType(out entryType, path));
|
return ConvertResult(BaseFileSystem.Target.GetEntryType(out entryType, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract override Result DoOpenFile(out IFile file, in Path path, OpenMode mode);
|
protected abstract override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode);
|
||||||
|
|
||||||
protected abstract override Result DoOpenDirectory(out IDirectory directory, in Path path,
|
protected abstract override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
OpenDirectoryMode mode);
|
OpenDirectoryMode mode);
|
||||||
|
|
||||||
protected override Result DoCommit()
|
protected override Result DoCommit()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using LibHac.Util;
|
using LibHac.Util;
|
||||||
@ -25,6 +26,6 @@ namespace LibHac.FsSrv.Impl
|
|||||||
Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2);
|
Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2);
|
||||||
Result SetSaveDataState(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataState state);
|
Result SetSaveDataState(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataState state);
|
||||||
Result SetSaveDataRank(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataRank rank);
|
Result SetSaveDataRank(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataRank rank);
|
||||||
Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, SaveDataSpaceId spaceId);
|
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, SaveDataSpaceId spaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,92 +294,84 @@ namespace LibHac.FsSrv.Impl
|
|||||||
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IFile contextFile = null;
|
// Read the multi-commit context
|
||||||
|
using var contextFile = new UniqueRef<IFile>();
|
||||||
|
rc = contextFs.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.ReadWrite);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
Unsafe.SkipInit(out Context context);
|
||||||
|
rc = contextFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref context), ReadOption.None);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
// Note: Nintendo doesn't check if the proper amount of bytes were read, but it
|
||||||
|
// doesn't really matter since the context is validated.
|
||||||
|
if (context.Version > CurrentCommitContextVersion)
|
||||||
|
return ResultFs.InvalidMultiCommitContextVersion.Log();
|
||||||
|
|
||||||
|
// All the file systems in the multi-commit must have been at least provisionally committed
|
||||||
|
// before we can try to recover the commit.
|
||||||
|
if (context.State != CommitState.ProvisionallyCommitted)
|
||||||
|
return ResultFs.InvalidMultiCommitContextState.Log();
|
||||||
|
|
||||||
|
// Keep track of the first error that occurs during the recovery
|
||||||
|
Result recoveryResult = Result.Success;
|
||||||
|
|
||||||
|
int saveCount = 0;
|
||||||
|
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
|
||||||
|
|
||||||
|
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Read the multi-commit context
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
rc = contextFs.OpenFile(out contextFile, in contextFilePath, OpenMode.ReadWrite);
|
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
Unsafe.SkipInit(out Context context);
|
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||||
rc = contextFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref context), ReadOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
// Note: Nintendo doesn't check if the proper amount of bytes were read, but it
|
// Iterate through all the saves to find any provisionally committed save data
|
||||||
// doesn't really matter since the context is validated.
|
while (true)
|
||||||
if (context.Version > CurrentCommitContextVersion)
|
|
||||||
return ResultFs.InvalidMultiCommitContextVersion.Log();
|
|
||||||
|
|
||||||
// All the file systems in the multi-commit must have been at least provisionally committed
|
|
||||||
// before we can try to recover the commit.
|
|
||||||
if (context.State != CommitState.ProvisionallyCommitted)
|
|
||||||
return ResultFs.InvalidMultiCommitContextState.Log();
|
|
||||||
|
|
||||||
// Keep track of the first error that occurs during the recovery
|
|
||||||
Result recoveryResult = Result.Success;
|
|
||||||
|
|
||||||
int saveCount = 0;
|
|
||||||
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
|
|
||||||
|
|
||||||
SaveDataIndexerAccessor accessor = null;
|
|
||||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
rc = saveService.OpenSaveDataIndexerAccessor(out accessor, out _, SaveDataSpaceId.User);
|
Unsafe.SkipInit(out SaveDataInfo info);
|
||||||
|
|
||||||
|
rc = infoReader.Target.Read(out long readCount, OutBuffer.FromStruct(ref info));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out infoReader);
|
// Break once we're done iterating all save data
|
||||||
if (rc.IsFailure()) return rc;
|
if (readCount == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
// Iterate through all the saves to find any provisionally committed save data
|
rc = multiCommitInterface.IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted,
|
||||||
while (true)
|
in info);
|
||||||
|
|
||||||
|
// Note: Some saves could be missed if there are more than MaxFileSystemCount
|
||||||
|
// provisionally committed saves. Not sure why Nintendo doesn't catch this.
|
||||||
|
if (rc.IsSuccess() && isProvisionallyCommitted && saveCount < MaxFileSystemCount)
|
||||||
{
|
{
|
||||||
Unsafe.SkipInit(out SaveDataInfo info);
|
savesToRecover[saveCount] = info;
|
||||||
|
saveCount++;
|
||||||
rc = infoReader.Target.Read(out long readCount, OutBuffer.FromStruct(ref info));
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
// Break once we're done iterating all save data
|
|
||||||
if (readCount == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
rc = multiCommitInterface.IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted,
|
|
||||||
in info);
|
|
||||||
|
|
||||||
// Note: Some saves could be missed if there are more than MaxFileSystemCount
|
|
||||||
// provisionally committed saves. Not sure why Nintendo doesn't catch this.
|
|
||||||
if (rc.IsSuccess() && isProvisionallyCommitted && saveCount < MaxFileSystemCount)
|
|
||||||
{
|
|
||||||
savesToRecover[saveCount] = info;
|
|
||||||
saveCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
accessor?.Dispose();
|
|
||||||
infoReader?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recover the saves by finishing their commits.
|
|
||||||
// All file systems will try to be recovered, even if one fails.
|
|
||||||
// If any commits fail, the result from the first failed recovery will be returned.
|
|
||||||
for (int i = 0; i < saveCount; i++)
|
|
||||||
{
|
|
||||||
rc = multiCommitInterface.RecoverProvisionallyCommittedSaveData(in savesToRecover[i], false);
|
|
||||||
|
|
||||||
if (rc.IsFailure() && !recoveryResult.IsFailure())
|
|
||||||
{
|
|
||||||
recoveryResult = rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return recoveryResult;
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
contextFile?.Dispose();
|
infoReader?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the saves by finishing their commits.
|
||||||
|
// All file systems will try to be recovered, even if one fails.
|
||||||
|
// If any commits fail, the result from the first failed recovery will be returned.
|
||||||
|
for (int i = 0; i < saveCount; i++)
|
||||||
|
{
|
||||||
|
rc = multiCommitInterface.RecoverProvisionallyCommittedSaveData(in savesToRecover[i], false);
|
||||||
|
|
||||||
|
if (rc.IsFailure() && !recoveryResult.IsFailure())
|
||||||
|
{
|
||||||
|
recoveryResult = rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recoveryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -410,14 +402,14 @@ namespace LibHac.FsSrv.Impl
|
|||||||
int saveCount = 0;
|
int saveCount = 0;
|
||||||
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
|
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
|
||||||
|
|
||||||
SaveDataIndexerAccessor accessor = null;
|
|
||||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
|
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rc = saveService.OpenSaveDataIndexerAccessor(out accessor, out _, SaveDataSpaceId.User);
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
|
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out infoReader);
|
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
// Iterate through all the saves to find any provisionally committed save data
|
// Iterate through all the saves to find any provisionally committed save data
|
||||||
@ -446,7 +438,6 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
accessor?.Dispose();
|
|
||||||
infoReader?.Dispose();
|
infoReader?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,8 +507,8 @@ namespace LibHac.FsSrv.Impl
|
|||||||
rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = fileSystem.Target.OpenFile(out IFile file, in contextFilePath, OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
file?.Dispose();
|
rc = fileSystem.Target.OpenFile(ref file.Ref(), in contextFilePath, OpenMode.Read);
|
||||||
|
|
||||||
if (rc.IsFailure())
|
if (rc.IsFailure())
|
||||||
{
|
{
|
||||||
@ -591,12 +582,10 @@ namespace LibHac.FsSrv.Impl
|
|||||||
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IFile contextFile = null;
|
// Open context file and create if it doesn't exist
|
||||||
|
using (var contextFile = new UniqueRef<IFile>())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
// Open context file and create if it doesn't exist
|
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.Read);
|
||||||
rc = _fileSystem.OpenFile(out contextFile, in contextFilePath, OpenMode.Read);
|
|
||||||
|
|
||||||
if (rc.IsFailure())
|
if (rc.IsFailure())
|
||||||
{
|
{
|
||||||
@ -606,18 +595,14 @@ namespace LibHac.FsSrv.Impl
|
|||||||
rc = _fileSystem.CreateFile(in contextFilePath, CommitContextFileSize);
|
rc = _fileSystem.CreateFile(in contextFilePath, CommitContextFileSize);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _fileSystem.OpenFile(out contextFile, in contextFilePath, OpenMode.Read);
|
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
contextFile?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
using (var contextFile = new UniqueRef<IFile>())
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenFile(out contextFile, in contextFilePath, OpenMode.ReadWrite);
|
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.ReadWrite);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
_context.Version = CurrentCommitContextVersion;
|
_context.Version = CurrentCommitContextVersion;
|
||||||
@ -626,16 +611,12 @@ namespace LibHac.FsSrv.Impl
|
|||||||
_context.Counter = counter;
|
_context.Counter = counter;
|
||||||
|
|
||||||
// Write the initial context to the file
|
// Write the initial context to the file
|
||||||
rc = contextFile.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
rc = contextFile.Get.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = contextFile.Flush();
|
rc = contextFile.Get.Flush();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
contextFile?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = _fileSystem.Commit();
|
rc = _fileSystem.Commit();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
@ -650,29 +631,23 @@ namespace LibHac.FsSrv.Impl
|
|||||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||||
public Result CommitProvisionallyDone()
|
public Result CommitProvisionallyDone()
|
||||||
{
|
{
|
||||||
using var contextFilePath = new Fs.Path();
|
using (var contextFilePath = new Fs.Path())
|
||||||
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
IFile contextFile = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenFile(out contextFile, in contextFilePath, OpenMode.ReadWrite);
|
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
using var contextFile = new UniqueRef<IFile>();
|
||||||
|
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.ReadWrite);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
_context.State = CommitState.ProvisionallyCommitted;
|
_context.State = CommitState.ProvisionallyCommitted;
|
||||||
|
|
||||||
rc = contextFile.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
rc = contextFile.Get.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = contextFile.Flush();
|
rc = contextFile.Get.Flush();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
contextFile?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _fileSystem.Commit();
|
return _fileSystem.Commit();
|
||||||
}
|
}
|
||||||
|
@ -8,27 +8,27 @@ namespace LibHac.FsSrv.Impl
|
|||||||
internal class OpenCountFileSystem : ForwardingFileSystem
|
internal class OpenCountFileSystem : ForwardingFileSystem
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> _entryCountSemaphore;
|
private ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> _entryCountSemaphore;
|
||||||
private IUniqueLock _mountCountSemaphore;
|
private UniqueRef<IUniqueLock> _mountCountSemaphore;
|
||||||
|
|
||||||
protected OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
public OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||||
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore) : base(
|
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore) : base(
|
||||||
ref baseFileSystem)
|
ref baseFileSystem)
|
||||||
{
|
{
|
||||||
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
|
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
public OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||||
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
|
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
|
||||||
ref IUniqueLock mountCountSemaphore) : base(ref baseFileSystem)
|
ref UniqueRef<IUniqueLock> mountCountSemaphore) : base(ref baseFileSystem)
|
||||||
{
|
{
|
||||||
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
|
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
|
||||||
Shared.Move(out _mountCountSemaphore, ref mountCountSemaphore);
|
_mountCountSemaphore = new UniqueRef<IUniqueLock>(ref mountCountSemaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
|
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
|
||||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||||
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
|
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
|
||||||
ref IUniqueLock mountCountSemaphore)
|
ref UniqueRef<IUniqueLock> mountCountSemaphore)
|
||||||
{
|
{
|
||||||
var filesystem =
|
var filesystem =
|
||||||
new OpenCountFileSystem(ref baseFileSystem, ref entryCountSemaphore, ref mountCountSemaphore);
|
new OpenCountFileSystem(ref baseFileSystem, ref entryCountSemaphore, ref mountCountSemaphore);
|
||||||
@ -47,23 +47,24 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once RedundantOverriddenMember
|
// ReSharper disable once RedundantOverriddenMember
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
// Todo: Implement
|
// Todo: Implement
|
||||||
return base.DoOpenFile(out file, path, mode);
|
return base.DoOpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once RedundantOverriddenMember
|
// ReSharper disable once RedundantOverriddenMember
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
// Todo: Implement
|
// Todo: Implement
|
||||||
return base.DoOpenDirectory(out directory, path, mode);
|
return base.DoOpenDirectory(ref outDirectory, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_entryCountSemaphore?.Dispose();
|
_entryCountSemaphore?.Dispose();
|
||||||
_mountCountSemaphore?.Dispose();
|
_mountCountSemaphore.Dispose();
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SaveDataResultConvertFile : IResultConvertFile
|
public class SaveDataResultConvertFile : IResultConvertFile
|
||||||
{
|
{
|
||||||
public SaveDataResultConvertFile(IFile baseFile) : base(baseFile)
|
public SaveDataResultConvertFile(ref UniqueRef<IFile> baseFile) : base(ref baseFile)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ namespace LibHac.FsSrv.Impl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SaveDataResultConvertDirectory : IResultConvertDirectory
|
public class SaveDataResultConvertDirectory : IResultConvertDirectory
|
||||||
{
|
{
|
||||||
public SaveDataResultConvertDirectory(IDirectory baseDirectory) : base(baseDirectory)
|
public SaveDataResultConvertDirectory(ref UniqueRef<IDirectory> baseDirectory) : base(ref baseDirectory)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,25 +176,24 @@ namespace LibHac.FsSrv.Impl
|
|||||||
return new ReferenceCountedDisposable<IFileSystem>(resultConvertFileSystem);
|
return new ReferenceCountedDisposable<IFileSystem>(resultConvertFileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Result rc = ConvertResult(BaseFileSystem.Target.OpenFile(ref file.Ref(), path, mode));
|
||||||
Result rc = ConvertResult(BaseFileSystem.Target.OpenFile(out IFile tempFile, path, mode));
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new SaveDataResultConvertFile(tempFile);
|
outFile.Reset(new SaveDataResultConvertFile(ref file.Ref()));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = ConvertResult(BaseFileSystem.Target.OpenDirectory(ref directory.Ref(), path, mode));
|
||||||
Result rc = ConvertResult(BaseFileSystem.Target.OpenDirectory(out IDirectory tempDirectory, path, mode));
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = new SaveDataResultConvertDirectory(tempDirectory);
|
outDirectory.Reset(new SaveDataResultConvertDirectory(ref directory.Ref()));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,11 @@ namespace LibHac.FsSrv.Impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the directory exists
|
// Check if the directory exists
|
||||||
Result rc = baseFileSystem.Target.OpenDirectory(out IDirectory dir, rootPath, OpenDirectoryMode.Directory);
|
using var dir = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = baseFileSystem.Target.OpenDirectory(ref dir.Ref(), rootPath, OpenDirectoryMode.Directory);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
dir.Dispose();
|
dir.Reset();
|
||||||
|
|
||||||
var fs = new SubdirectoryFileSystem(ref baseFileSystem);
|
var fs = new SubdirectoryFileSystem(ref baseFileSystem);
|
||||||
using (var subDirFs = new ReferenceCountedDisposable<SubdirectoryFileSystem>(fs))
|
using (var subDirFs = new ReferenceCountedDisposable<SubdirectoryFileSystem>(fs))
|
||||||
|
@ -593,12 +593,12 @@ namespace LibHac.FsSrv
|
|||||||
ServiceImpl.IncrementRomFsRecoveredByInvalidateCacheCount();
|
ServiceImpl.IncrementRomFsRecoveredByInvalidateCacheCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result TryAcquireAddOnContentOpenCountSemaphore(out IUniqueLock semaphoreLock)
|
private Result TryAcquireAddOnContentOpenCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result TryAcquireRomMountCountSemaphore(out IUniqueLock semaphoreLock)
|
private Result TryAcquireRomMountCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -634,16 +634,14 @@ namespace LibHac.FsSrv
|
|||||||
|
|
||||||
nspPathLen += 4;
|
nspPathLen += 4;
|
||||||
|
|
||||||
if (nspPathLen > FsPath.MaxLength + 1)
|
using var pathNsp = new Path();
|
||||||
return ResultFs.TooLongPath.Log();
|
Result rc = pathNsp.InitializeWithNormalization(path, nspPathLen);
|
||||||
|
|
||||||
Result rc = FsPath.FromSpan(out FsPath nspPath, path.Slice(0, nspPathLen));
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
var storage = new FileStorageBasedFileSystem();
|
var storage = new FileStorageBasedFileSystem();
|
||||||
using var nspFileStorage = new ReferenceCountedDisposable<FileStorageBasedFileSystem>(storage);
|
using var nspFileStorage = new ReferenceCountedDisposable<FileStorageBasedFileSystem>(storage);
|
||||||
|
|
||||||
rc = nspFileStorage.Target.Initialize(ref baseFileSystem, new U8Span(nspPath.Str), OpenMode.Read);
|
rc = nspFileStorage.Target.Initialize(ref baseFileSystem, in pathNsp, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _config.PartitionFsCreator.Create(out fileSystem, nspFileStorage.AddReference<IStorage>());
|
rc = _config.PartitionFsCreator.Create(out fileSystem, nspFileStorage.AddReference<IStorage>());
|
||||||
@ -664,7 +662,11 @@ namespace LibHac.FsSrv
|
|||||||
// Todo: Create ref-counted storage
|
// Todo: Create ref-counted storage
|
||||||
var ncaFileStorage = new FileStorageBasedFileSystem();
|
var ncaFileStorage = new FileStorageBasedFileSystem();
|
||||||
|
|
||||||
Result rc = ncaFileStorage.Initialize(ref baseFileSystem, path, OpenMode.Read);
|
using var pathNca = new Path();
|
||||||
|
Result rc = pathNca.InitializeWithNormalization(path);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = ncaFileStorage.Initialize(ref baseFileSystem, in pathNca, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _config.StorageOnNcaCreator.OpenNca(out Nca ncaTemp, ncaFileStorage);
|
rc = _config.StorageOnNcaCreator.OpenNca(out Nca ncaTemp, ncaFileStorage);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -343,11 +343,9 @@ namespace LibHac.FsSrv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenSaveDataMeta(out IFile metaFile, ulong saveDataId, SaveDataSpaceId spaceId,
|
public Result OpenSaveDataMeta(ref UniqueRef<IFile> outMetaFile, ulong saveDataId, SaveDataSpaceId spaceId,
|
||||||
SaveDataMetaType metaType)
|
SaveDataMetaType metaType)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out metaFile);
|
|
||||||
|
|
||||||
ReferenceCountedDisposable<IFileSystem> metaDirFs = null;
|
ReferenceCountedDisposable<IFileSystem> metaDirFs = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -365,7 +363,7 @@ namespace LibHac.FsSrv
|
|||||||
(uint)metaType);
|
(uint)metaType);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return metaDirFs.Target.OpenFile(out metaFile, in saveDataMetaName, OpenMode.ReadWrite);
|
return metaDirFs.Target.OpenFile(ref outMetaFile, in saveDataMetaName, OpenMode.ReadWrite);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -875,25 +873,19 @@ namespace LibHac.FsSrv
|
|||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out count);
|
UnsafeHelpers.SkipParamInit(out count);
|
||||||
|
|
||||||
SaveDataIndexerAccessor accessor = null;
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
try
|
|
||||||
{
|
|
||||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, out bool _, SaveDataSpaceId.User);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
count = accessor.Indexer.GetIndexCount();
|
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), out bool _, SaveDataSpaceId.User);
|
||||||
return Result.Success;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
|
||||||
finally
|
count = accessor.Get.Indexer.GetIndexCount();
|
||||||
{
|
return Result.Success;
|
||||||
accessor?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit,
|
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool neededInit,
|
||||||
SaveDataSpaceId spaceId)
|
SaveDataSpaceId spaceId)
|
||||||
{
|
{
|
||||||
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(out accessor, out neededInit, spaceId);
|
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(ref outAccessor, out neededInit, spaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetTemporaryStorageIndexer()
|
public void ResetTemporaryStorageIndexer()
|
||||||
|
@ -49,13 +49,13 @@ namespace LibHac.FsSrv
|
|||||||
/// The returned <see cref="SaveDataIndexerAccessor"/> will have exclusive access to the requested indexer.
|
/// The returned <see cref="SaveDataIndexerAccessor"/> will have exclusive access to the requested indexer.
|
||||||
/// The accessor must be disposed after use.
|
/// The accessor must be disposed after use.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="accessor">If the method returns successfully, contains the created accessor.</param>
|
/// <param name="outAccessor">If the method returns successfully, contains the created accessor.</param>
|
||||||
/// <param name="neededInit">If the method returns successfully, contains <see langword="true"/>
|
/// <param name="neededInit">If the method returns successfully, contains <see langword="true"/>
|
||||||
/// if the indexer needed to be initialized.</param>
|
/// if the indexer needed to be initialized.</param>
|
||||||
/// <param name="spaceId">The <see cref="SaveDataSpaceId"/> of the indexer to open.</param>
|
/// <param name="spaceId">The <see cref="SaveDataSpaceId"/> of the indexer to open.</param>
|
||||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||||
public Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit,
|
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor,
|
||||||
SaveDataSpaceId spaceId)
|
out bool neededInit, SaveDataSpaceId spaceId)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out neededInit);
|
UnsafeHelpers.SkipParamInit(out neededInit);
|
||||||
|
|
||||||
@ -145,12 +145,12 @@ namespace LibHac.FsSrv
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
accessor = default;
|
outAccessor = default;
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
accessor = new SaveDataIndexerAccessor(indexer, ref indexerLock);
|
outAccessor.Reset(new SaveDataIndexerAccessor(indexer, ref indexerLock));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Diag;
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
@ -68,10 +69,10 @@ namespace LibHac.FsSrv
|
|||||||
_mutex.Initialize();
|
_mutex.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, U8Span path, OpenMode mode,
|
public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path, OpenMode mode,
|
||||||
OpenType type)
|
OpenType type)
|
||||||
{
|
{
|
||||||
Result rc = Initialize(ref baseFileSystem, path, mode);
|
Result rc = Initialize(ref baseFileSystem, in path, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return SetOpenType(type);
|
return SetOpenType(type);
|
||||||
@ -328,12 +329,17 @@ namespace LibHac.FsSrv
|
|||||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId,
|
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId,
|
||||||
OpenMode mode, Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
|
OpenMode mode, Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
|
||||||
{
|
{
|
||||||
Result rc;
|
|
||||||
UnsafeHelpers.SkipParamInit(out saveDataStorage);
|
UnsafeHelpers.SkipParamInit(out saveDataStorage);
|
||||||
|
|
||||||
Span<byte> saveImageName = stackalloc byte[0x30];
|
// Hack around error CS8350.
|
||||||
var sb = new U8StringBuilder(saveImageName);
|
const int bufferLength = 0x12;
|
||||||
sb.Append((byte)'/').AppendFormat(saveDataId, 'x', 16);
|
Span<byte> buffer = stackalloc byte[bufferLength];
|
||||||
|
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
|
||||||
|
Span<byte> saveImageNameBuffer = MemoryMarshal.CreateSpan(ref bufferRef, bufferLength);
|
||||||
|
|
||||||
|
using var saveImageName = new Path();
|
||||||
|
Result rc = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
// If an open type isn't specified, open the save without the shared file storage layer
|
// If an open type isn't specified, open the save without the shared file storage layer
|
||||||
if (!type.HasValue)
|
if (!type.HasValue)
|
||||||
@ -344,7 +350,7 @@ namespace LibHac.FsSrv
|
|||||||
fileStorage =
|
fileStorage =
|
||||||
new ReferenceCountedDisposable<FileStorageBasedFileSystem>(new FileStorageBasedFileSystem());
|
new ReferenceCountedDisposable<FileStorageBasedFileSystem>(new FileStorageBasedFileSystem());
|
||||||
|
|
||||||
rc = fileStorage.Target.Initialize(ref baseFileSystem, new U8Span(saveImageName), mode);
|
rc = fileStorage.Target.Initialize(ref baseFileSystem, in saveImageName, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
saveDataStorage = fileStorage.AddReference<IStorage>();
|
saveDataStorage = fileStorage.AddReference<IStorage>();
|
||||||
@ -375,7 +381,7 @@ namespace LibHac.FsSrv
|
|||||||
new ReferenceCountedDisposable<SaveDataOpenTypeSetFileStorage>(
|
new ReferenceCountedDisposable<SaveDataOpenTypeSetFileStorage>(
|
||||||
new SaveDataOpenTypeSetFileStorage(_fsServer, spaceId, saveDataId));
|
new SaveDataOpenTypeSetFileStorage(_fsServer, spaceId, saveDataId));
|
||||||
|
|
||||||
rc = baseFileStorage.Target.Initialize(ref baseFileSystem, new U8Span(saveImageName), mode,
|
rc = baseFileStorage.Target.Initialize(ref baseFileSystem, in saveImageName, mode,
|
||||||
type.ValueRo);
|
type.ValueRo);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ namespace LibHac.FsSrv.Sf
|
|||||||
Result RenameFile(in Path currentPath, in Path newPath);
|
Result RenameFile(in Path currentPath, in Path newPath);
|
||||||
Result RenameDirectory(in Path currentPath, in Path newPath);
|
Result RenameDirectory(in Path currentPath, in Path newPath);
|
||||||
Result GetEntryType(out uint entryType, in Path path);
|
Result GetEntryType(out uint entryType, in Path path);
|
||||||
Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in Path path, uint mode);
|
Result OpenFile(out ReferenceCountedDisposable<IFileSf> outFile, in Path path, uint mode);
|
||||||
Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in Path path, uint mode);
|
Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> outDirectory, in Path path, uint mode);
|
||||||
Result Commit();
|
Result Commit();
|
||||||
Result GetFreeSpaceSize(out long freeSpace, in Path path);
|
Result GetFreeSpaceSize(out long freeSpace, in Path path);
|
||||||
Result GetTotalSpaceSize(out long totalSpace, in Path path);
|
Result GetTotalSpaceSize(out long totalSpace, in Path path);
|
||||||
|
@ -8,23 +8,29 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
public class AesXtsDirectory : IDirectory
|
public class AesXtsDirectory : IDirectory
|
||||||
{
|
{
|
||||||
private U8String Path { get; }
|
private U8String _path;
|
||||||
private OpenDirectoryMode Mode { get; }
|
private OpenDirectoryMode _mode;
|
||||||
|
|
||||||
private IFileSystem BaseFileSystem { get; }
|
private IFileSystem _baseFileSystem;
|
||||||
private IDirectory BaseDirectory { get; }
|
private UniqueRef<IDirectory> _baseDirectory;
|
||||||
|
|
||||||
public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, U8String path, OpenDirectoryMode mode)
|
public AesXtsDirectory(IFileSystem baseFs, ref UniqueRef<IDirectory> baseDir, U8String path, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
BaseFileSystem = baseFs;
|
_baseFileSystem = baseFs;
|
||||||
BaseDirectory = baseDir;
|
_baseDirectory = new UniqueRef<IDirectory>(ref baseDir);
|
||||||
Mode = mode;
|
_mode = mode;
|
||||||
Path = path;
|
_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
_baseDirectory.Dispose();
|
||||||
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
|
||||||
{
|
{
|
||||||
Result rc = BaseDirectory.Read(out entriesRead, entryBuffer);
|
Result rc = _baseDirectory.Get.Read(out entriesRead, entryBuffer);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
for (int i = 0; i < entriesRead; i++)
|
for (int i = 0; i < entriesRead; i++)
|
||||||
@ -33,14 +39,14 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
if (entry.Type == DirectoryEntryType.File)
|
if (entry.Type == DirectoryEntryType.File)
|
||||||
{
|
{
|
||||||
if (Mode.HasFlag(OpenDirectoryMode.NoFileSize))
|
if (_mode.HasFlag(OpenDirectoryMode.NoFileSize))
|
||||||
{
|
{
|
||||||
entry.Size = 0;
|
entry.Size = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string entryName = StringUtils.NullTerminatedUtf8ToString(entry.Name);
|
string entryName = StringUtils.NullTerminatedUtf8ToString(entry.Name);
|
||||||
entry.Size = GetAesXtsFileSize(PathTools.Combine(Path.ToString(), entryName).ToU8Span());
|
entry.Size = GetAesXtsFileSize(PathTools.Combine(_path.ToString(), entryName).ToU8Span());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +56,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
protected override Result DoGetEntryCount(out long entryCount)
|
protected override Result DoGetEntryCount(out long entryCount)
|
||||||
{
|
{
|
||||||
return BaseDirectory.GetEntryCount(out entryCount);
|
return _baseDirectory.Get.GetEntryCount(out entryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,24 +72,21 @@ namespace LibHac.FsSystem
|
|||||||
// Todo: Remove try/catch when more code uses Result
|
// Todo: Remove try/catch when more code uses Result
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Result rc = BaseFileSystem.OpenFile(out IFile file, path, OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Result rc = _baseFileSystem.OpenFile(ref file.Ref(), path, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return 0;
|
if (rc.IsFailure()) return 0;
|
||||||
|
|
||||||
using (file)
|
uint magic = 0;
|
||||||
{
|
long fileSize = 0;
|
||||||
uint magic = 0;
|
long bytesRead;
|
||||||
long fileSize = 0;
|
|
||||||
long bytesRead;
|
|
||||||
|
|
||||||
file.Read(out bytesRead, magicOffset, SpanHelpers.AsByteSpan(ref magic), ReadOption.None);
|
file.Get.Read(out bytesRead, magicOffset, SpanHelpers.AsByteSpan(ref magic), ReadOption.None);
|
||||||
if (bytesRead != sizeof(uint) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0;
|
if (bytesRead != sizeof(uint) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0;
|
||||||
|
|
||||||
file.Read(out bytesRead, fileSizeOffset, SpanHelpers.AsByteSpan(ref fileSize), ReadOption.None);
|
file.Get.Read(out bytesRead, fileSizeOffset, SpanHelpers.AsByteSpan(ref fileSize), ReadOption.None);
|
||||||
if (bytesRead != sizeof(long) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0;
|
if (bytesRead != sizeof(long) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0;
|
||||||
|
|
||||||
return fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return fileSize;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
public class AesXtsFile : IFile
|
public class AesXtsFile : IFile
|
||||||
{
|
{
|
||||||
private IFile BaseFile { get; }
|
private UniqueRef<IFile> BaseFile { get; }
|
||||||
private U8String Path { get; }
|
private U8String Path { get; }
|
||||||
private byte[] KekSeed { get; }
|
private byte[] KekSeed { get; }
|
||||||
private byte[] VerificationKey { get; }
|
private byte[] VerificationKey { get; }
|
||||||
@ -20,18 +20,18 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
internal const int HeaderLength = 0x4000;
|
internal const int HeaderLength = 0x4000;
|
||||||
|
|
||||||
public AesXtsFile(OpenMode mode, IFile baseFile, U8String path, ReadOnlySpan<byte> kekSeed, ReadOnlySpan<byte> verificationKey, int blockSize)
|
public AesXtsFile(OpenMode mode, ref UniqueRef<IFile> baseFile, U8String path, ReadOnlySpan<byte> kekSeed, ReadOnlySpan<byte> verificationKey, int blockSize)
|
||||||
{
|
{
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
BaseFile = baseFile;
|
BaseFile = new UniqueRef<IFile>(ref baseFile);
|
||||||
Path = path;
|
Path = path;
|
||||||
KekSeed = kekSeed.ToArray();
|
KekSeed = kekSeed.ToArray();
|
||||||
VerificationKey = verificationKey.ToArray();
|
VerificationKey = verificationKey.ToArray();
|
||||||
BlockSize = blockSize;
|
BlockSize = blockSize;
|
||||||
|
|
||||||
Header = new AesXtsFileHeader(BaseFile);
|
Header = new AesXtsFileHeader(BaseFile.Get);
|
||||||
|
|
||||||
baseFile.GetSize(out long fileSize).ThrowIfFailure();
|
BaseFile.Get.GetSize(out long fileSize).ThrowIfFailure();
|
||||||
|
|
||||||
if (!Header.TryDecryptHeader(Path.ToString(), KekSeed, VerificationKey))
|
if (!Header.TryDecryptHeader(Path.ToString(), KekSeed, VerificationKey))
|
||||||
{
|
{
|
||||||
@ -43,7 +43,7 @@ namespace LibHac.FsSystem
|
|||||||
ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort.Value, "NAX0 key derivation failed.");
|
ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort.Value, "NAX0 key derivation failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileStorage = new FileStorage2(baseFile);
|
var fileStorage = new FileStorage2(BaseFile.Get);
|
||||||
var encStorage = new SubStorage(fileStorage, HeaderLength, fileSize - HeaderLength);
|
var encStorage = new SubStorage(fileStorage, HeaderLength, fileSize - HeaderLength);
|
||||||
encStorage.SetResizable(true);
|
encStorage.SetResizable(true);
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
Header.SetSize(size, VerificationKey);
|
Header.SetSize(size, VerificationKey);
|
||||||
|
|
||||||
Result rc = BaseFile.Write(0, Header.ToBytes(false));
|
Result rc = BaseFile.Get.Write(0, Header.ToBytes(false));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return BaseStorage.SetSize(Alignment.AlignUp(size, 0x10));
|
return BaseStorage.SetSize(Alignment.AlignUp(size, 0x10));
|
||||||
@ -126,7 +126,7 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
BaseStorage.Flush();
|
BaseStorage.Flush();
|
||||||
BaseStorage.Dispose();
|
BaseStorage.Dispose();
|
||||||
BaseFile?.Dispose();
|
BaseFile.Dispose();
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
@ -66,14 +66,12 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
var header = new AesXtsFileHeader(key, size, path.ToString(), KekSource, ValidationKey);
|
var header = new AesXtsFileHeader(key, size, path.ToString(), KekSource, ValidationKey);
|
||||||
|
|
||||||
rc = BaseFileSystem.OpenFile(out IFile baseFile, in path, OpenMode.Write);
|
using var baseFile = new UniqueRef<IFile>();
|
||||||
|
rc = BaseFileSystem.OpenFile(ref baseFile.Ref(), in path, OpenMode.Write);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (baseFile)
|
rc = baseFile.Get.Write(0, header.ToBytes(false));
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
rc = baseFile.Write(0, header.ToBytes(false));
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@ -98,28 +96,27 @@ namespace LibHac.FsSystem
|
|||||||
return BaseFileSystem.DeleteFile(path);
|
return BaseFileSystem.DeleteFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
using var baseDir = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = BaseFileSystem.OpenDirectory(ref baseDir.Ref(), path, mode);
|
||||||
Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = new AesXtsDirectory(BaseFileSystem, baseDir, new U8String(path.GetString().ToArray()), mode);
|
outDirectory.Reset(new AesXtsDirectory(BaseFileSystem, ref baseDir.Ref(), new U8String(path.GetString().ToArray()), mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
using var baseFile = new UniqueRef<IFile>();
|
||||||
|
Result rc = BaseFileSystem.OpenFile(ref baseFile.Ref(), path, mode | OpenMode.Read);
|
||||||
Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
var xtsFile = new AesXtsFile(mode, baseFile, new U8String(path.GetString().ToArray()), KekSource,
|
var xtsFile = new AesXtsFile(mode, ref baseFile.Ref(), new U8String(path.GetString().ToArray()), KekSource,
|
||||||
ValidationKey, BlockSize);
|
ValidationKey, BlockSize);
|
||||||
|
|
||||||
file = xtsFile;
|
outFile.Reset(xtsFile);
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,15 +262,13 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
header = null;
|
header = null;
|
||||||
|
|
||||||
Result rc = BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Result rc = BaseFileSystem.OpenFile(ref file.Ref(), filePath.ToU8Span(), OpenMode.Read);
|
||||||
if (rc.IsFailure()) return false;
|
if (rc.IsFailure()) return false;
|
||||||
|
|
||||||
using (file)
|
header = new AesXtsFileHeader(file.Get);
|
||||||
{
|
|
||||||
header = new AesXtsFileHeader(file);
|
|
||||||
|
|
||||||
return header.TryDecryptHeader(keyPath, KekSource, ValidationKey);
|
return header.TryDecryptHeader(keyPath, KekSource, ValidationKey);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteXtsHeader(AesXtsFileHeader header, string filePath, string keyPath)
|
private void WriteXtsHeader(AesXtsFileHeader header, string filePath, string keyPath)
|
||||||
@ -283,12 +278,10 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
header.EncryptHeader(keyPath, KekSource, ValidationKey);
|
header.EncryptHeader(keyPath, KekSource, ValidationKey);
|
||||||
|
|
||||||
BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.ReadWrite);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
BaseFileSystem.OpenFile(ref file.Ref(), filePath.ToU8Span(), OpenMode.ReadWrite);
|
||||||
|
|
||||||
using (file)
|
file.Get.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure();
|
||||||
{
|
|
||||||
file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
|
|
||||||
@ -51,12 +52,13 @@ namespace LibHac.FsSystem
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -218,10 +218,11 @@ namespace LibHac.FsSystem
|
|||||||
CreateFileOptions.None);
|
CreateFileOptions.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFileSystem.OpenFile(out IFile newInternalFile, in internalFilePath, _mode);
|
using var newInternalFile = new UniqueRef<IFile>();
|
||||||
|
rc = _baseFileSystem.OpenFile(ref newInternalFile.Ref(), in internalFilePath, _mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
_files.Add(newInternalFile);
|
_files.Add(newInternalFile.Release());
|
||||||
|
|
||||||
rc = internalFilePath.RemoveChild();
|
rc = internalFilePath.RemoveChild();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
@ -375,16 +376,16 @@ namespace LibHac.FsSystem
|
|||||||
private class ConcatenationDirectory : IDirectory
|
private class ConcatenationDirectory : IDirectory
|
||||||
{
|
{
|
||||||
private OpenDirectoryMode _mode;
|
private OpenDirectoryMode _mode;
|
||||||
private IDirectory _baseDirectory;
|
private UniqueRef<IDirectory> _baseDirectory;
|
||||||
private Path.Stored _path;
|
private Path.Stored _path;
|
||||||
private IFileSystem _baseFileSystem;
|
private IFileSystem _baseFileSystem;
|
||||||
private ConcatenationFileSystem _concatenationFileSystem;
|
private ConcatenationFileSystem _concatenationFileSystem;
|
||||||
|
|
||||||
public ConcatenationDirectory(OpenDirectoryMode mode, IDirectory baseDirectory,
|
public ConcatenationDirectory(OpenDirectoryMode mode, ref UniqueRef<IDirectory> baseDirectory,
|
||||||
ConcatenationFileSystem concatFileSystem, IFileSystem baseFileSystem)
|
ConcatenationFileSystem concatFileSystem, IFileSystem baseFileSystem)
|
||||||
{
|
{
|
||||||
_mode = mode;
|
_mode = mode;
|
||||||
_baseDirectory = baseDirectory;
|
_baseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
|
||||||
_baseFileSystem = baseFileSystem;
|
_baseFileSystem = baseFileSystem;
|
||||||
_concatenationFileSystem = concatFileSystem;
|
_concatenationFileSystem = concatFileSystem;
|
||||||
}
|
}
|
||||||
@ -414,7 +415,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
while (readCountTotal < entryBuffer.Length)
|
while (readCountTotal < entryBuffer.Length)
|
||||||
{
|
{
|
||||||
Result rc = _baseDirectory.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
Result rc = _baseDirectory.Get.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (readCount == 0)
|
if (readCount == 0)
|
||||||
@ -454,37 +455,30 @@ namespace LibHac.FsSystem
|
|||||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||||
|
|
||||||
Unsafe.SkipInit(out DirectoryEntry entry);
|
Unsafe.SkipInit(out DirectoryEntry entry);
|
||||||
IDirectory directory = null;
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
|
||||||
try
|
Path path = _path.DangerousGetPath();
|
||||||
|
|
||||||
|
Result rc = _baseFileSystem.OpenDirectory(ref directory.Ref(), in path,
|
||||||
|
OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
long entryCountTotal = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
Path path = _path.GetPath();
|
directory.Get.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
||||||
|
|
||||||
Result rc = _baseFileSystem.OpenDirectory(out directory, in path,
|
|
||||||
OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
long entryCountTotal = 0;
|
if (readCount == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
while (true)
|
if (IsReadTarget(in entry))
|
||||||
{
|
entryCountTotal++;
|
||||||
directory.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
if (readCount == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (IsReadTarget(in entry))
|
|
||||||
entryCountTotal++;
|
|
||||||
}
|
|
||||||
|
|
||||||
entryCount = entryCountTotal;
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
directory?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entryCount = entryCountTotal;
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsReadTarget(in DirectoryEntry entry)
|
private bool IsReadTarget(in DirectoryEntry entry)
|
||||||
@ -642,19 +636,16 @@ namespace LibHac.FsSystem
|
|||||||
return _baseFileSystem.Flush();
|
return _baseFileSystem.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
if (!IsConcatenationFile(in path))
|
if (!IsConcatenationFile(in path))
|
||||||
{
|
{
|
||||||
return _baseFileSystem.OpenFile(out file, in path, mode);
|
return _baseFileSystem.OpenFile(ref outFile, in path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result rc = GetInternalFileCount(out int fileCount, in path);
|
Result rc = GetInternalFileCount(out int fileCount, in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
ConcatenationFile concatFile = null;
|
|
||||||
var internalFiles = new List<IFile>(fileCount);
|
var internalFiles = new List<IFile>(fileCount);
|
||||||
|
|
||||||
using var filePath = new Path();
|
using var filePath = new Path();
|
||||||
@ -668,27 +659,27 @@ namespace LibHac.FsSystem
|
|||||||
rc = AppendInternalFilePath(ref filePath.Ref(), i);
|
rc = AppendInternalFilePath(ref filePath.Ref(), i);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFileSystem.OpenFile(out IFile internalFile, in filePath, mode);
|
using var internalFile = new UniqueRef<IFile>();
|
||||||
|
rc = _baseFileSystem.OpenFile(ref internalFile.Ref(), in filePath, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
internalFiles.Add(internalFile);
|
internalFiles.Add(internalFile.Release());
|
||||||
|
|
||||||
rc = filePath.RemoveChild();
|
rc = filePath.RemoveChild();
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
concatFile = new ConcatenationFile(mode, ref internalFiles, _InternalFileSize, _baseFileSystem);
|
using var concatFile = new UniqueRef<ConcatenationFile>(
|
||||||
|
new ConcatenationFile(mode, ref internalFiles, _InternalFileSize, _baseFileSystem));
|
||||||
|
|
||||||
rc = concatFile.Initialize(in path);
|
rc = concatFile.Get.Initialize(in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = Shared.Move(ref concatFile);
|
outFile.Set(ref concatFile.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
concatFile?.Dispose();
|
|
||||||
|
|
||||||
if (internalFiles is not null)
|
if (internalFiles is not null)
|
||||||
{
|
{
|
||||||
foreach (IFile internalFile in internalFiles)
|
foreach (IFile internalFile in internalFiles)
|
||||||
@ -699,23 +690,24 @@ namespace LibHac.FsSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
if (IsConcatenationFile(path))
|
if (IsConcatenationFile(path))
|
||||||
{
|
{
|
||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result rc = _baseFileSystem.OpenDirectory(out IDirectory baseDirectory, path, OpenDirectoryMode.All);
|
using var baseDirectory = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = _baseFileSystem.OpenDirectory(ref baseDirectory.Ref(), path, OpenDirectoryMode.All);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
var concatDirectory = new ConcatenationDirectory(mode, baseDirectory, this, _baseFileSystem);
|
using var concatDirectory = new UniqueRef<ConcatenationDirectory>(
|
||||||
rc = concatDirectory.Initialize(in path);
|
new ConcatenationDirectory(mode, ref baseDirectory.Ref(), this, _baseFileSystem));
|
||||||
|
rc = concatDirectory.Get.Initialize(in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = concatDirectory;
|
outDirectory.Set(ref concatDirectory.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +38,9 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
private FileSystemClient _fsClient;
|
private FileSystemClient _fsClient;
|
||||||
private IFileSystem _baseFs;
|
private IFileSystem _baseFs;
|
||||||
|
|
||||||
private SdkMutexType _mutex;
|
private SdkMutexType _mutex;
|
||||||
|
private UniqueRef<IFileSystem> _uniqueBaseFs;
|
||||||
|
|
||||||
// Todo: Unique file system for disposal
|
|
||||||
private int _openWritableFileCount;
|
private int _openWritableFileCount;
|
||||||
private bool _isJournalingSupported;
|
private bool _isJournalingSupported;
|
||||||
private bool _isMultiCommitSupported;
|
private bool _isMultiCommitSupported;
|
||||||
@ -57,24 +56,24 @@ namespace LibHac.FsSystem
|
|||||||
private ulong _saveDataId;
|
private ulong _saveDataId;
|
||||||
|
|
||||||
// Additions to ensure only one directory save data fs is opened at a time
|
// Additions to ensure only one directory save data fs is opened at a time
|
||||||
private IFile _lockFile;
|
private UniqueRef<IFile> _lockFile;
|
||||||
|
|
||||||
private class DirectorySaveDataFile : IFile
|
private class DirectorySaveDataFile : IFile
|
||||||
{
|
{
|
||||||
private IFile _baseFile;
|
private UniqueRef<IFile> _baseFile;
|
||||||
private DirectorySaveDataFileSystem _parentFs;
|
private DirectorySaveDataFileSystem _parentFs;
|
||||||
private OpenMode _mode;
|
private OpenMode _mode;
|
||||||
|
|
||||||
public DirectorySaveDataFile(IFile baseFile, DirectorySaveDataFileSystem parentFs, OpenMode mode)
|
public DirectorySaveDataFile(ref UniqueRef<IFile> baseFile, DirectorySaveDataFileSystem parentFs, OpenMode mode)
|
||||||
{
|
{
|
||||||
_baseFile = baseFile;
|
_baseFile = new UniqueRef<IFile>(ref baseFile);
|
||||||
_parentFs = parentFs;
|
_parentFs = parentFs;
|
||||||
_mode = mode;
|
_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_baseFile?.Dispose();
|
_baseFile.Dispose();
|
||||||
|
|
||||||
if (_mode.HasFlag(OpenMode.Write))
|
if (_mode.HasFlag(OpenMode.Write))
|
||||||
{
|
{
|
||||||
@ -88,63 +87,36 @@ namespace LibHac.FsSystem
|
|||||||
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination,
|
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination,
|
||||||
in ReadOption option)
|
in ReadOption option)
|
||||||
{
|
{
|
||||||
return _baseFile.Read(out bytesRead, offset, destination, in option);
|
return _baseFile.Get.Read(out bytesRead, offset, destination, in option);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||||
{
|
{
|
||||||
return _baseFile.Write(offset, source, in option);
|
return _baseFile.Get.Write(offset, source, in option);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoFlush()
|
protected override Result DoFlush()
|
||||||
{
|
{
|
||||||
return _baseFile.Flush();
|
return _baseFile.Get.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetSize(out long size)
|
protected override Result DoGetSize(out long size)
|
||||||
{
|
{
|
||||||
return _baseFile.GetSize(out size);
|
return _baseFile.Get.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoSetSize(long size)
|
protected override Result DoSetSize(long size)
|
||||||
{
|
{
|
||||||
return _baseFile.SetSize(size);
|
return _baseFile.Get.SetSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset,
|
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset,
|
||||||
long size, ReadOnlySpan<byte> inBuffer)
|
long size, ReadOnlySpan<byte> inBuffer)
|
||||||
{
|
{
|
||||||
return _baseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
return _baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result CreateNew(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
|
||||||
ISaveDataCommitTimeStampGetter timeStampGetter, RandomDataGenerator randomGenerator,
|
|
||||||
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled,
|
|
||||||
FileSystemClient fsClient)
|
|
||||||
{
|
|
||||||
var obj = new DirectorySaveDataFileSystem(baseFileSystem, fsClient);
|
|
||||||
Result rc = obj.Initialize(timeStampGetter, randomGenerator, isJournalingSupported, isMultiCommitSupported,
|
|
||||||
isJournalingEnabled);
|
|
||||||
|
|
||||||
if (rc.IsSuccess())
|
|
||||||
{
|
|
||||||
created = obj;
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Dispose();
|
|
||||||
UnsafeHelpers.SkipParamInit(out created);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Result CreateNew(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
|
||||||
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled)
|
|
||||||
{
|
|
||||||
return CreateNew(out created, baseFileSystem, null, null, isJournalingSupported, isMultiCommitSupported,
|
|
||||||
isJournalingEnabled, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ReferenceCountedDisposable<DirectorySaveDataFileSystem> CreateShared(IFileSystem baseFileSystem,
|
public static ReferenceCountedDisposable<DirectorySaveDataFileSystem> CreateShared(IFileSystem baseFileSystem,
|
||||||
FileSystemClient fsClient)
|
FileSystemClient fsClient)
|
||||||
{
|
{
|
||||||
@ -162,6 +134,17 @@ namespace LibHac.FsSystem
|
|||||||
_mutex.Initialize();
|
_mutex.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an uninitialized <see cref="DirectorySaveDataFileSystem"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseFileSystem">The base <see cref="IFileSystem"/> to use.</param>
|
||||||
|
public DirectorySaveDataFileSystem(ref UniqueRef<IFileSystem> baseFileSystem)
|
||||||
|
{
|
||||||
|
_baseFs = baseFileSystem.Get;
|
||||||
|
_mutex.Initialize();
|
||||||
|
_uniqueBaseFs = new UniqueRef<IFileSystem>(ref baseFileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create an uninitialized <see cref="DirectorySaveDataFileSystem"/>.
|
/// Create an uninitialized <see cref="DirectorySaveDataFileSystem"/>.
|
||||||
/// If a <see cref="FileSystemClient"/> is provided a global mutex will be used when synchronizing directories.
|
/// If a <see cref="FileSystemClient"/> is provided a global mutex will be used when synchronizing directories.
|
||||||
@ -177,13 +160,28 @@ namespace LibHac.FsSystem
|
|||||||
_fsClient = fsClient;
|
_fsClient = fsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an uninitialized <see cref="DirectorySaveDataFileSystem"/>.
|
||||||
|
/// If a <see cref="FileSystemClient"/> is provided a global mutex will be used when synchronizing directories.
|
||||||
|
/// Running outside of a Horizon context doesn't require this mutex,
|
||||||
|
/// and null can be passed to <paramref name="fsClient"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseFileSystem">The base <see cref="IFileSystem"/> to use.</param>
|
||||||
|
/// <param name="fsClient">The <see cref="FileSystemClient"/> to use. May be null.</param>
|
||||||
|
public DirectorySaveDataFileSystem(ref UniqueRef<IFileSystem> baseFileSystem, FileSystemClient fsClient)
|
||||||
|
{
|
||||||
|
_baseFs = baseFileSystem.Get;
|
||||||
|
_mutex.Initialize();
|
||||||
|
_uniqueBaseFs = new UniqueRef<IFileSystem>(ref baseFileSystem);
|
||||||
|
_fsClient = fsClient;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_lockFile?.Dispose();
|
_lockFile.Dispose();
|
||||||
_lockFile = null;
|
|
||||||
|
|
||||||
_cacheObserver?.Unregister(_spaceId, _saveDataId);
|
_cacheObserver?.Unregister(_spaceId, _saveDataId);
|
||||||
_baseFs?.Dispose();
|
_uniqueBaseFs.Dispose();
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,14 +326,14 @@ namespace LibHac.FsSystem
|
|||||||
private Result GetFileSystemLock()
|
private Result GetFileSystemLock()
|
||||||
{
|
{
|
||||||
// Having an open lock file means we already have the lock for the file system.
|
// Having an open lock file means we already have the lock for the file system.
|
||||||
if (_lockFile is not null)
|
if (_lockFile.HasValue)
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
||||||
using var pathLockFile = new Path();
|
using var pathLockFile = new Path();
|
||||||
Result rc = PathFunctions.SetUpFixedPath(ref pathLockFile.Ref(), LockFileName);
|
Result rc = PathFunctions.SetUpFixedPath(ref pathLockFile.Ref(), LockFileName);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out _lockFile, in pathLockFile, OpenMode.ReadWrite);
|
rc = _baseFs.OpenFile(ref _lockFile, in pathLockFile, OpenMode.ReadWrite);
|
||||||
|
|
||||||
if (rc.IsFailure())
|
if (rc.IsFailure())
|
||||||
{
|
{
|
||||||
@ -344,7 +342,7 @@ namespace LibHac.FsSystem
|
|||||||
rc = _baseFs.CreateFile(in pathLockFile, 0);
|
rc = _baseFs.CreateFile(in pathLockFile, 0);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out _lockFile, in pathLockFile, OpenMode.ReadWrite);
|
rc = _baseFs.OpenFile(ref _lockFile, in pathLockFile, OpenMode.ReadWrite);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -512,40 +510,39 @@ namespace LibHac.FsSystem
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
using var fullPath = new Path();
|
using var fullPath = new Path();
|
||||||
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out IFile baseFile, in fullPath, mode);
|
using var baseFile = new UniqueRef<IFile>();
|
||||||
|
rc = _baseFs.OpenFile(ref baseFile.Ref(), in fullPath, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new DirectorySaveDataFile(baseFile, this, mode);
|
using var file = new UniqueRef<IFile>(new DirectorySaveDataFile(ref baseFile.Ref(), this, mode));
|
||||||
|
|
||||||
if (mode.HasFlag(OpenMode.Write))
|
if (mode.HasFlag(OpenMode.Write))
|
||||||
{
|
{
|
||||||
_openWritableFileCount++;
|
_openWritableFileCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outFile.Set(ref file.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
using var fullPath = new Path();
|
using var fullPath = new Path();
|
||||||
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
rc = _baseFs.OpenDirectory(out directory, in fullPath, mode);
|
rc = _baseFs.OpenDirectory(ref outDirectory, in fullPath, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -704,8 +701,10 @@ namespace LibHac.FsSystem
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void DecrementWriteOpenFileCount()
|
private void DecrementWriteOpenFileCount()
|
||||||
{
|
{
|
||||||
|
// Todo?: Calling OpenFile when outFile already contains a DirectorySaveDataFile
|
||||||
|
// will try to lock this mutex a second time
|
||||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
_openWritableFileCount--;
|
_openWritableFileCount--;
|
||||||
@ -811,47 +810,40 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
private Result EnsureExtraDataSize(in Path path)
|
private Result EnsureExtraDataSize(in Path path)
|
||||||
{
|
{
|
||||||
IFile file = null;
|
using var file = new UniqueRef<IFile>();
|
||||||
try
|
Result rc = _baseFs.OpenFile(ref file.Ref(), in path, OpenMode.ReadWrite);
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
Result rc = _baseFs.OpenFile(out file, in path, OpenMode.ReadWrite);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = file.GetSize(out long fileSize);
|
rc = file.Get.GetSize(out long fileSize);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (fileSize == Unsafe.SizeOf<SaveDataExtraData>())
|
if (fileSize == Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
||||||
return file.SetSize(Unsafe.SizeOf<SaveDataExtraData>());
|
return file.Get.SetSize(Unsafe.SizeOf<SaveDataExtraData>());
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
file?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result SynchronizeExtraData(in Path destPath, in Path sourcePath)
|
private Result SynchronizeExtraData(in Path destPath, in Path sourcePath)
|
||||||
{
|
{
|
||||||
Span<byte> workBuffer = stackalloc byte[Unsafe.SizeOf<SaveDataExtraData>()];
|
Span<byte> workBuffer = stackalloc byte[Unsafe.SizeOf<SaveDataExtraData>()];
|
||||||
|
|
||||||
Result rc = _baseFs.OpenFile(out IFile sourceFile, in sourcePath, OpenMode.Read);
|
using (var sourceFile = new UniqueRef<IFile>())
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
using (sourceFile)
|
|
||||||
{
|
{
|
||||||
rc = sourceFile.Read(out long bytesRead, 0, workBuffer);
|
Result rc = _baseFs.OpenFile(ref sourceFile.Ref(), in sourcePath, OpenMode.Read);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = sourceFile.Get.Read(out long bytesRead, 0, workBuffer);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out IFile destFile, in destPath, OpenMode.Write);
|
using (var destFile = new UniqueRef<IFile>())
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
using (destFile)
|
|
||||||
{
|
{
|
||||||
rc = destFile.Write(0, workBuffer, WriteOption.Flush);
|
Result rc = _baseFs.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = destFile.Get.Write(0, workBuffer, WriteOption.Flush);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,14 +918,12 @@ namespace LibHac.FsSystem
|
|||||||
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out IFile file, in pathExtraData, OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
rc = _baseFs.OpenFile(ref file.Ref(), in pathExtraData, OpenMode.Write);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (file)
|
rc = file.Get.Write(0, SpanHelpers.AsReadOnlyByteSpan(in extraData), WriteOption.Flush);
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
rc = file.Write(0, SpanHelpers.AsReadOnlyByteSpan(in extraData), WriteOption.Flush);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@ -1002,16 +992,14 @@ namespace LibHac.FsSystem
|
|||||||
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFs.OpenFile(out IFile file, in pathExtraData, OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
rc = _baseFs.OpenFile(ref file.Ref(), in pathExtraData, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (file)
|
rc = file.Get.Read(out long bytesRead, 0, SpanHelpers.AsByteSpan(ref extraData));
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
rc = file.Read(out long bytesRead, 0, SpanHelpers.AsByteSpan(ref extraData));
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -95,42 +95,38 @@ namespace LibHac.FsSystem
|
|||||||
logger?.LogMessage(sourcePath.ToString());
|
logger?.LogMessage(sourcePath.ToString());
|
||||||
|
|
||||||
// Open source file.
|
// Open source file.
|
||||||
Result rc = sourceFileSystem.OpenFile(out IFile sourceFile, sourcePath, OpenMode.Read);
|
using var sourceFile = new UniqueRef<IFile>();
|
||||||
|
Result rc = sourceFileSystem.OpenFile(ref sourceFile.Ref(), sourcePath, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (sourceFile)
|
rc = sourceFile.Get.GetSize(out long fileSize);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = CreateOrOverwriteFile(destFileSystem, in destPath, fileSize, option);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
using var destFile = new UniqueRef<IFile>();
|
||||||
|
rc = destFileSystem.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
// Read/Write file in work buffer sized chunks.
|
||||||
|
long remaining = fileSize;
|
||||||
|
long offset = 0;
|
||||||
|
|
||||||
|
logger?.SetTotal(fileSize);
|
||||||
|
|
||||||
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
rc = sourceFile.GetSize(out long fileSize);
|
rc = sourceFile.Get.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = CreateOrOverwriteFile(destFileSystem, in destPath, fileSize, option);
|
rc = destFile.Get.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = destFileSystem.OpenFile(out IFile destFile, in destPath, OpenMode.Write);
|
remaining -= bytesRead;
|
||||||
if (rc.IsFailure()) return rc;
|
offset += bytesRead;
|
||||||
|
|
||||||
using (destFile)
|
logger?.ReportAdd(bytesRead);
|
||||||
{
|
|
||||||
// Read/Write file in work buffer sized chunks.
|
|
||||||
long remaining = fileSize;
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
logger?.SetTotal(fileSize);
|
|
||||||
|
|
||||||
while (remaining > 0)
|
|
||||||
{
|
|
||||||
rc = sourceFile.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = destFile.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
remaining -= bytesRead;
|
|
||||||
offset += bytesRead;
|
|
||||||
|
|
||||||
logger?.ReportAdd(bytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -166,13 +162,14 @@ namespace LibHac.FsSystem
|
|||||||
var pathNormalized = new Path();
|
var pathNormalized = new Path();
|
||||||
InitializeFromString(ref pathNormalized, path).ThrowIfFailure();
|
InitializeFromString(ref pathNormalized, path).ThrowIfFailure();
|
||||||
|
|
||||||
fileSystem.OpenDirectory(out IDirectory directory, in pathNormalized, OpenDirectoryMode.All).ThrowIfFailure();
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
fileSystem.OpenDirectory(ref directory.Ref(), in pathNormalized, OpenDirectoryMode.All).ThrowIfFailure();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Unsafe.SkipInit(out DirectoryEntry dirEntry);
|
Unsafe.SkipInit(out DirectoryEntry dirEntry);
|
||||||
|
|
||||||
directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry)).ThrowIfFailure();
|
directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry)).ThrowIfFailure();
|
||||||
if (entriesRead == 0) break;
|
if (entriesRead == 0) break;
|
||||||
|
|
||||||
DirectoryEntryEx entry = GetDirectoryEntryEx(ref dirEntry, path);
|
DirectoryEntryEx entry = GetDirectoryEntryEx(ref dirEntry, path);
|
||||||
|
@ -26,40 +26,41 @@ namespace LibHac.FsSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) =>
|
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) =>
|
||||||
BaseFileSystem.Target.CreateFile(path, size, option);
|
BaseFileSystem.Target.CreateFile(in path, size, option);
|
||||||
|
|
||||||
protected override Result DoDeleteFile(in Path path) => BaseFileSystem.Target.DeleteFile(path);
|
protected override Result DoDeleteFile(in Path path) => BaseFileSystem.Target.DeleteFile(in path);
|
||||||
|
|
||||||
protected override Result DoCreateDirectory(in Path path) => BaseFileSystem.Target.CreateDirectory(path);
|
protected override Result DoCreateDirectory(in Path path) => BaseFileSystem.Target.CreateDirectory(in path);
|
||||||
|
|
||||||
protected override Result DoDeleteDirectory(in Path path) => BaseFileSystem.Target.DeleteDirectory(path);
|
protected override Result DoDeleteDirectory(in Path path) => BaseFileSystem.Target.DeleteDirectory(in path);
|
||||||
|
|
||||||
protected override Result DoDeleteDirectoryRecursively(in Path path) =>
|
protected override Result DoDeleteDirectoryRecursively(in Path path) =>
|
||||||
BaseFileSystem.Target.DeleteDirectoryRecursively(path);
|
BaseFileSystem.Target.DeleteDirectoryRecursively(in path);
|
||||||
|
|
||||||
protected override Result DoCleanDirectoryRecursively(in Path path) =>
|
protected override Result DoCleanDirectoryRecursively(in Path path) =>
|
||||||
BaseFileSystem.Target.CleanDirectoryRecursively(path);
|
BaseFileSystem.Target.CleanDirectoryRecursively(in path);
|
||||||
|
|
||||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath) =>
|
protected override Result DoRenameFile(in Path currentPath, in Path newPath) =>
|
||||||
BaseFileSystem.Target.RenameFile(currentPath, newPath);
|
BaseFileSystem.Target.RenameFile(in currentPath, in newPath);
|
||||||
|
|
||||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) =>
|
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) =>
|
||||||
BaseFileSystem.Target.RenameDirectory(currentPath, newPath);
|
BaseFileSystem.Target.RenameDirectory(in currentPath, in newPath);
|
||||||
|
|
||||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) =>
|
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) =>
|
||||||
BaseFileSystem.Target.GetEntryType(out entryType, path);
|
BaseFileSystem.Target.GetEntryType(out entryType, in path);
|
||||||
|
|
||||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) =>
|
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) =>
|
||||||
BaseFileSystem.Target.GetFreeSpaceSize(out freeSpace, path);
|
BaseFileSystem.Target.GetFreeSpaceSize(out freeSpace, in path);
|
||||||
|
|
||||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) =>
|
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) =>
|
||||||
BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, path);
|
BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, in path);
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode) =>
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode) =>
|
||||||
BaseFileSystem.Target.OpenFile(out file, path, mode);
|
BaseFileSystem.Target.OpenFile(ref outFile, in path, mode);
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode) =>
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
BaseFileSystem.Target.OpenDirectory(out directory, path, mode);
|
OpenDirectoryMode mode) =>
|
||||||
|
BaseFileSystem.Target.OpenDirectory(ref outDirectory, in path, mode);
|
||||||
|
|
||||||
protected override Result DoCommit() => BaseFileSystem.Target.Commit();
|
protected override Result DoCommit() => BaseFileSystem.Target.Commit();
|
||||||
|
|
||||||
@ -71,9 +72,9 @@ namespace LibHac.FsSystem
|
|||||||
protected override Result DoFlush() => BaseFileSystem.Target.Flush();
|
protected override Result DoFlush() => BaseFileSystem.Target.Flush();
|
||||||
|
|
||||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path) =>
|
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path) =>
|
||||||
BaseFileSystem.Target.GetFileTimeStampRaw(out timeStamp, path);
|
BaseFileSystem.Target.GetFileTimeStampRaw(out timeStamp, in path);
|
||||||
|
|
||||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
|
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
|
||||||
in Path path) => BaseFileSystem.Target.QueryEntry(outBuffer, inBuffer, queryId, path);
|
in Path path) => BaseFileSystem.Target.QueryEntry(outBuffer, inBuffer, queryId, in path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
public UniqueLockWithPin(ref UniqueLock<SemaphoreAdapter> semaphore, ref ReferenceCountedDisposable<T> pinnedObject)
|
public UniqueLockWithPin(ref UniqueLock<SemaphoreAdapter> semaphore, ref ReferenceCountedDisposable<T> pinnedObject)
|
||||||
{
|
{
|
||||||
Shared.Move(out _semaphore, ref semaphore);
|
_semaphore = new UniqueLock<SemaphoreAdapter>(ref semaphore);
|
||||||
Shared.Move(out _pinnedObject, ref pinnedObject);
|
Shared.Move(out _pinnedObject, ref pinnedObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,10 +37,9 @@ namespace LibHac.FsSystem
|
|||||||
Sources.AddRange(sourceFileSystems);
|
Sources.AddRange(sourceFileSystems);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
// Open directories from all layers so they can be merged
|
// Open directories from all layers so they can be merged
|
||||||
// Only allocate the list for multiple sources if needed
|
// Only allocate the list for multiple sources if needed
|
||||||
List<IFileSystem> multipleSources = null;
|
List<IFileSystem> multipleSources = null;
|
||||||
@ -82,12 +81,12 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
if (!(multipleSources is null))
|
if (!(multipleSources is null))
|
||||||
{
|
{
|
||||||
var dir = new MergedDirectory(multipleSources, mode);
|
using var dir = new UniqueRef<MergedDirectory>(new MergedDirectory(multipleSources, mode));
|
||||||
Result rc = dir.Initialize(in path);
|
Result rc = dir.Get.Initialize(in path);
|
||||||
|
|
||||||
if (rc.IsSuccess())
|
if (rc.IsSuccess())
|
||||||
{
|
{
|
||||||
directory = dir;
|
outDirectory.Set(ref dir.Ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -95,11 +94,12 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
if (!(singleSource is null))
|
if (!(singleSource is null))
|
||||||
{
|
{
|
||||||
Result rc = singleSource.OpenDirectory(out IDirectory dir, path, mode);
|
using var dir = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = singleSource.OpenDirectory(ref dir.Ref(), in path, mode);
|
||||||
|
|
||||||
if (rc.IsSuccess())
|
if (rc.IsSuccess())
|
||||||
{
|
{
|
||||||
directory = dir;
|
outDirectory.Set(ref dir.Ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -108,10 +108,8 @@ namespace LibHac.FsSystem
|
|||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
foreach (IFileSystem fs in Sources)
|
foreach (IFileSystem fs in Sources)
|
||||||
{
|
{
|
||||||
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
|
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
|
||||||
@ -120,7 +118,7 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
if (type == DirectoryEntryType.File)
|
if (type == DirectoryEntryType.File)
|
||||||
{
|
{
|
||||||
return fs.OpenFile(out file, path, mode);
|
return fs.OpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == DirectoryEntryType.Directory)
|
if (type == DirectoryEntryType.Directory)
|
||||||
@ -225,12 +223,14 @@ namespace LibHac.FsSystem
|
|||||||
Result rc = _path.Initialize(in path);
|
Result rc = _path.Initialize(in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
using var dir = new UniqueRef<IDirectory>();
|
||||||
|
|
||||||
foreach (IFileSystem fs in SourceFileSystems)
|
foreach (IFileSystem fs in SourceFileSystems)
|
||||||
{
|
{
|
||||||
rc = fs.OpenDirectory(out IDirectory dir, in path, Mode);
|
rc = fs.OpenDirectory(ref dir.Ref(), in path, Mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
SourceDirs.Add(dir);
|
SourceDirs.Add(dir.Release());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -270,18 +270,19 @@ namespace LibHac.FsSystem
|
|||||||
// todo: Efficient way to remove duplicates
|
// todo: Efficient way to remove duplicates
|
||||||
var names = new HashSet<string>();
|
var names = new HashSet<string>();
|
||||||
|
|
||||||
Path path = _path.GetPath();
|
Path path = _path.DangerousGetPath();
|
||||||
|
using var dir = new UniqueRef<IDirectory>();
|
||||||
|
|
||||||
// Open new directories for each source because we need to remove duplicate entries
|
// Open new directories for each source because we need to remove duplicate entries
|
||||||
foreach (IFileSystem fs in SourceFileSystems)
|
foreach (IFileSystem fs in SourceFileSystems)
|
||||||
{
|
{
|
||||||
Result rc = fs.OpenDirectory(out IDirectory dir, in path, Mode);
|
Result rc = fs.OpenDirectory(ref dir.Ref(), in path, Mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
long entriesRead;
|
long entriesRead;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
rc = dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry));
|
rc = dir.Get.Read(out entriesRead, SpanHelpers.AsSpan(ref entry));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name)))
|
if (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name)))
|
||||||
|
@ -175,7 +175,7 @@ namespace LibHac.FsSystem
|
|||||||
rc = pathNormalized.Normalize(pathFlags);
|
rc = pathNormalized.Normalize(pathFlags);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
Path rootPath = _rootPath.GetPath();
|
Path rootPath = _rootPath.DangerousGetPath();
|
||||||
|
|
||||||
using var fullPath = new Path();
|
using var fullPath = new Path();
|
||||||
rc = fullPath.Combine(in rootPath, in pathNormalized);
|
rc = fullPath.Combine(in rootPath, in pathNormalized);
|
||||||
@ -379,9 +379,9 @@ namespace LibHac.FsSystem
|
|||||||
() => DeleteFileInternal(file), _fsClient);
|
() => DeleteFileInternal(file), _fsClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
Result rc = ResolveFullPath(out string fullPath, in path, true);
|
Result rc = ResolveFullPath(out string fullPath, in path, true);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -398,14 +398,12 @@ namespace LibHac.FsSystem
|
|||||||
OpenDirectoryInternal(out dirTemp, mode, dirInfo), _fsClient);
|
OpenDirectoryInternal(out dirTemp, mode, dirInfo), _fsClient);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory = dirTemp;
|
outDirectory.Reset(dirTemp);
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
Result rc = ResolveFullPath(out string fullPath, in path, true);
|
Result rc = ResolveFullPath(out string fullPath, in path, true);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -423,7 +421,7 @@ namespace LibHac.FsSystem
|
|||||||
OpenFileInternal(out fileStream, fullPath, mode), _fsClient);
|
OpenFileInternal(out fileStream, fullPath, mode), _fsClient);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new LocalFile(fileStream, mode);
|
outFile.Reset(new LocalFile(fileStream, mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,13 +34,14 @@ namespace LibHac.FsSystem
|
|||||||
BaseStorage = storage;
|
BaseStorage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
directory = new PartitionDirectory(this, path.ToString(), mode);
|
outDirectory.Reset(new PartitionDirectory(this, path.ToString(), mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
string pathNormalized = PathTools.Normalize(path.ToString()).TrimStart('/');
|
string pathNormalized = PathTools.Normalize(path.ToString()).TrimStart('/');
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ namespace LibHac.FsSystem
|
|||||||
ThrowHelper.ThrowResult(ResultFs.PathNotFound.Value);
|
ThrowHelper.ThrowResult(ResultFs.PathNotFound.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
file = OpenFile(entry, mode);
|
outFile.Reset(OpenFile(entry, mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,12 +26,14 @@ namespace LibHac.FsSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PartitionFileSystemBuilder(IFileSystem input)
|
public PartitionFileSystemBuilder(IFileSystem input)
|
||||||
{
|
{
|
||||||
|
using var file = new UniqueRef<IFile>();
|
||||||
|
|
||||||
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||||
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
||||||
{
|
{
|
||||||
input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
input.OpenFile(ref file.Ref(), entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
AddFile(entry.FullPath.TrimStart('/'), file);
|
AddFile(entry.FullPath.TrimStart('/'), file.Release());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,10 +49,9 @@ namespace LibHac.FsSystem
|
|||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
if (!IsInitialized)
|
if (!IsInitialized)
|
||||||
return ResultFs.PreconditionViolation.Log();
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
@ -61,15 +60,13 @@ namespace LibHac.FsSystem
|
|||||||
if (path == rootPath)
|
if (path == rootPath)
|
||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
|
|
||||||
directory = new PartitionDirectory(this, mode);
|
outDirectory.Reset(new PartitionDirectory(this, mode));
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
if (!IsInitialized)
|
if (!IsInitialized)
|
||||||
return ResultFs.PreconditionViolation.Log();
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
@ -81,7 +78,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
ref T entry = ref MetaData.GetEntry(entryIndex);
|
ref T entry = ref MetaData.GetEntry(entryIndex);
|
||||||
|
|
||||||
file = new PartitionFile(this, ref entry, mode);
|
outFile.Reset(new PartitionFile(this, ref entry, mode));
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
|
|
||||||
@ -6,22 +7,22 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
public class ReadOnlyFile : IFile
|
public class ReadOnlyFile : IFile
|
||||||
{
|
{
|
||||||
private IFile BaseFile { get; }
|
private UniqueRef<IFile> _baseFile;
|
||||||
|
|
||||||
public ReadOnlyFile(IFile baseFile)
|
public ReadOnlyFile(ref UniqueRef<IFile> baseFile)
|
||||||
{
|
{
|
||||||
BaseFile = baseFile;
|
_baseFile = new UniqueRef<IFile>(ref baseFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination,
|
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination,
|
||||||
in ReadOption option)
|
in ReadOption option)
|
||||||
{
|
{
|
||||||
return BaseFile.Read(out bytesRead, offset, destination, option);
|
return _baseFile.Get.Read(out bytesRead, offset, destination, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetSize(out long size)
|
protected override Result DoGetSize(out long size)
|
||||||
{
|
{
|
||||||
return BaseFile.GetSize(out size);
|
return _baseFile.Get.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoFlush()
|
protected override Result DoFlush()
|
||||||
@ -45,7 +46,7 @@ namespace LibHac.FsSystem
|
|||||||
{
|
{
|
||||||
case OperationId.InvalidateCache:
|
case OperationId.InvalidateCache:
|
||||||
case OperationId.QueryRange:
|
case OperationId.QueryRange:
|
||||||
return BaseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
return _baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||||
default:
|
default:
|
||||||
return ResultFs.UnsupportedOperateRangeForReadOnlyFile.Log();
|
return ResultFs.UnsupportedOperateRangeForReadOnlyFile.Log();
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,6 @@ namespace LibHac.FsSystem
|
|||||||
private IFileSystem BaseFs { get; }
|
private IFileSystem BaseFs { get; }
|
||||||
private ReferenceCountedDisposable<IFileSystem> BaseFsShared { get; }
|
private ReferenceCountedDisposable<IFileSystem> BaseFsShared { get; }
|
||||||
|
|
||||||
// Todo: Remove non-shared constructor
|
|
||||||
public ReadOnlyFileSystem(IFileSystem baseFileSystem)
|
|
||||||
{
|
|
||||||
BaseFs = baseFileSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyFileSystem(ReferenceCountedDisposable<IFileSystem> baseFileSystem)
|
public ReadOnlyFileSystem(ReferenceCountedDisposable<IFileSystem> baseFileSystem)
|
||||||
{
|
{
|
||||||
BaseFsShared = baseFileSystem;
|
BaseFsShared = baseFileSystem;
|
||||||
@ -28,35 +22,35 @@ namespace LibHac.FsSystem
|
|||||||
return new ReferenceCountedDisposable<IFileSystem>(fs);
|
return new ReferenceCountedDisposable<IFileSystem>(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
return BaseFs.OpenDirectory(out directory, path, mode);
|
return BaseFs.OpenDirectory(ref outDirectory, in path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
using var baseFile = new UniqueRef<IFile>();
|
||||||
|
Result rc = BaseFs.OpenFile(ref baseFile.Ref(), in path, mode);
|
||||||
Result rc = BaseFs.OpenFile(out IFile baseFile, path, mode);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
file = new ReadOnlyFile(baseFile);
|
outFile.Reset(new ReadOnlyFile(ref baseFile.Ref()));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||||
{
|
{
|
||||||
return BaseFs.GetEntryType(out entryType, path);
|
return BaseFs.GetEntryType(out entryType, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
||||||
{
|
{
|
||||||
return BaseFs.GetFreeSpaceSize(out freeSpace, path);
|
return BaseFs.GetFreeSpaceSize(out freeSpace, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
||||||
{
|
{
|
||||||
return BaseFs.GetTotalSpaceSize(out totalSpace, path);
|
return BaseFs.GetTotalSpaceSize(out totalSpace, in path);
|
||||||
|
|
||||||
// FS does:
|
// FS does:
|
||||||
// return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log();
|
// return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log();
|
||||||
@ -64,7 +58,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
|
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
|
||||||
{
|
{
|
||||||
return BaseFs.GetFileTimeStampRaw(out timeStamp, path);
|
return BaseFs.GetFileTimeStampRaw(out timeStamp, in path);
|
||||||
|
|
||||||
// FS does:
|
// FS does:
|
||||||
// return ResultFs.NotImplemented.Log();
|
// return ResultFs.NotImplemented.Log();
|
||||||
|
@ -39,9 +39,10 @@ namespace LibHac.FsSystem.RomFs
|
|||||||
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||||
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
||||||
{
|
{
|
||||||
input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using var file = new UniqueRef<IFile>();
|
||||||
|
input.OpenFile(ref file.Ref(), entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
AddFile(entry.FullPath, file);
|
AddFile(entry.FullPath, file.Release());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,23 +49,20 @@ namespace LibHac.FsSystem.RomFs
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
if (!FileTable.TryOpenDirectory(path.ToString(), out FindPosition position))
|
if (!FileTable.TryOpenDirectory(path.ToString(), out FindPosition position))
|
||||||
{
|
{
|
||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
directory = new RomFsDirectory(this, position, mode);
|
outDirectory.Reset(new RomFsDirectory(this, position, mode));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
if (!FileTable.TryOpenFile(path.ToString(), out RomFileInfo info))
|
if (!FileTable.TryOpenFile(path.ToString(), out RomFileInfo info))
|
||||||
{
|
{
|
||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
@ -77,7 +74,7 @@ namespace LibHac.FsSystem.RomFs
|
|||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
file = new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length);
|
outFile.Reset(new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length));
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Common.Keys;
|
using LibHac.Common.Keys;
|
||||||
using LibHac.Crypto;
|
using LibHac.Crypto;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
@ -148,91 +149,92 @@ namespace LibHac.FsSystem.Save
|
|||||||
|
|
||||||
protected override Result DoCreateDirectory(in Path path)
|
protected override Result DoCreateDirectory(in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.CreateDirectory(path);
|
Result result = SaveDataFileSystemCore.CreateDirectory(in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.CreateFile(path, size, option);
|
Result result = SaveDataFileSystemCore.CreateFile(in path, size, option);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoDeleteDirectory(in Path path)
|
protected override Result DoDeleteDirectory(in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.DeleteDirectory(path);
|
Result result = SaveDataFileSystemCore.DeleteDirectory(in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path);
|
Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path);
|
Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoDeleteFile(in Path path)
|
protected override Result DoDeleteFile(in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.DeleteFile(path);
|
Result result = SaveDataFileSystemCore.DeleteFile(in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode);
|
Result result = SaveDataFileSystemCore.OpenDirectory(ref outDirectory, in path, mode);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode);
|
Result result = SaveDataFileSystemCore.OpenFile(ref outFile, in path, mode);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.RenameDirectory(currentPath, newPath);
|
Result result = SaveDataFileSystemCore.RenameDirectory(in currentPath, in newPath);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.RenameFile(currentPath, newPath);
|
Result result = SaveDataFileSystemCore.RenameFile(in currentPath, in newPath);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path);
|
Result result = SaveDataFileSystemCore.GetEntryType(out entryType, in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path);
|
Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
||||||
{
|
{
|
||||||
Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path);
|
Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, in path);
|
||||||
|
|
||||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||||
}
|
}
|
||||||
|
@ -134,10 +134,9 @@ namespace LibHac.FsSystem.Save
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
Result rc = CheckIfNormalized(in path);
|
Result rc = CheckIfNormalized(in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -146,15 +145,13 @@ namespace LibHac.FsSystem.Save
|
|||||||
return ResultFs.PathNotFound.Log();
|
return ResultFs.PathNotFound.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
directory = new SaveDataDirectory(this, position, mode);
|
outDirectory.Reset(new SaveDataDirectory(this, position, mode));
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
Result rc = CheckIfNormalized(in path);
|
Result rc = CheckIfNormalized(in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
@ -165,7 +162,7 @@ namespace LibHac.FsSystem.Save
|
|||||||
|
|
||||||
AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock);
|
AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock);
|
||||||
|
|
||||||
file = new SaveDataFile(storage, new U8Span(path.GetString()), FileTable, fileInfo.Length, mode);
|
outFile.Reset(new SaveDataFile(storage, new U8Span(path.GetString()), FileTable, fileInfo.Length, mode));
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -95,14 +95,15 @@ namespace LibHac.FsSystem
|
|||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
return _baseFileSystem.Target.OpenFile(out file, path, mode);
|
return _baseFileSystem.Target.OpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
return _baseFileSystem.Target.OpenDirectory(out directory, path, mode);
|
return _baseFileSystem.Target.OpenDirectory(ref outDirectory, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||||
|
@ -111,16 +111,17 @@ namespace LibHac.FsSystem
|
|||||||
return BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, path);
|
return BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageFlag);
|
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageFlag);
|
||||||
return BaseFileSystem.Target.OpenFile(out file, path, mode);
|
return BaseFileSystem.Target.OpenFile(ref outFile, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageFlag);
|
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageFlag);
|
||||||
return BaseFileSystem.Target.OpenDirectory(out directory, path, mode);
|
return BaseFileSystem.Target.OpenDirectory(ref outDirectory, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoCommit()
|
protected override Result DoCommit()
|
||||||
|
@ -40,7 +40,7 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
private Result ResolveFullPath(ref Path outPath, in Path relativePath)
|
private Result ResolveFullPath(ref Path outPath, in Path relativePath)
|
||||||
{
|
{
|
||||||
Path rootPath = _rootPath.GetPath();
|
Path rootPath = _rootPath.DangerousGetPath();
|
||||||
return outPath.Combine(in rootPath, in relativePath);
|
return outPath.Combine(in rootPath, in relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,29 +100,26 @@ namespace LibHac.FsSystem
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
using var fullPath = new Path();
|
using var fullPath = new Path();
|
||||||
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFileSystem.OpenFile(out file, in fullPath, mode);
|
rc = _baseFileSystem.OpenFile(ref outFile, in fullPath, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||||
|
OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
using var fullPath = new Path();
|
using var fullPath = new Path();
|
||||||
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = _baseFileSystem.OpenDirectory(out directory, in fullPath, mode);
|
rc = _baseFileSystem.OpenDirectory(ref outDirectory, in fullPath, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -39,105 +39,92 @@ namespace LibHac.FsSystem
|
|||||||
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
||||||
ref FsIterationTaskClosure closure)
|
ref FsIterationTaskClosure closure)
|
||||||
{
|
{
|
||||||
IDirectory directory = null;
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
try
|
|
||||||
|
Result rc = fs.OpenDirectory(ref directory.Ref(), in workPath, OpenDirectoryMode.All);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
Result rc = fs.OpenDirectory(out directory, in workPath, OpenDirectoryMode.All);
|
rc = directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
while (true)
|
if (entriesRead == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
workPath.AppendChild(dirEntry.Name);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (dirEntry.Type == DirectoryEntryType.Directory)
|
||||||
{
|
{
|
||||||
rc = directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
rc = onEnterDir(in workPath, in dirEntry, ref closure);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (entriesRead == 0)
|
rc = IterateDirectoryRecursivelyInternal(fs, ref workPath, ref dirEntry, onEnterDir, onExitDir,
|
||||||
break;
|
onFile, ref closure);
|
||||||
|
|
||||||
workPath.AppendChild(dirEntry.Name);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (dirEntry.Type == DirectoryEntryType.Directory)
|
rc = onExitDir(in workPath, in dirEntry, ref closure);
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
rc = onEnterDir(in workPath, in dirEntry, ref closure);
|
}
|
||||||
if (rc.IsFailure()) return rc;
|
else
|
||||||
|
{
|
||||||
rc = IterateDirectoryRecursivelyInternal(fs, ref workPath, ref dirEntry, onEnterDir, onExitDir,
|
rc = onFile(in workPath, in dirEntry, ref closure);
|
||||||
onFile, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = onExitDir(in workPath, in dirEntry, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = onFile(in workPath, in dirEntry, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = workPath.RemoveChild();
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
rc = workPath.RemoveChild();
|
||||||
}
|
if (rc.IsFailure()) return rc;
|
||||||
finally
|
|
||||||
{
|
|
||||||
directory?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Result CleanupDirectoryRecursivelyInternal(IFileSystem fs, ref Path workPath,
|
private static Result CleanupDirectoryRecursivelyInternal(IFileSystem fs, ref Path workPath,
|
||||||
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
||||||
ref FsIterationTaskClosure closure)
|
ref FsIterationTaskClosure closure)
|
||||||
{
|
{
|
||||||
IDirectory directory = null;
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
try
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
while (true)
|
Result rc = fs.OpenDirectory(ref directory.Ref(), in workPath, OpenDirectoryMode.All);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
directory.Reset(null);
|
||||||
|
|
||||||
|
if (entriesRead == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rc = workPath.AppendChild(dirEntry.Name);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (dirEntry.Type == DirectoryEntryType.Directory)
|
||||||
{
|
{
|
||||||
Result rc = fs.OpenDirectory(out directory, in workPath, OpenDirectoryMode.All);
|
rc = onEnterDir(in workPath, in dirEntry, ref closure);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
rc = CleanupDirectoryRecursivelyInternal(fs, ref workPath, ref dirEntry, onEnterDir, onExitDir,
|
||||||
|
onFile, ref closure);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
directory.Dispose();
|
rc = onExitDir(in workPath, in dirEntry, ref closure);
|
||||||
directory = null;
|
|
||||||
|
|
||||||
if (entriesRead == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
rc = workPath.AppendChild(dirEntry.Name);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
if (dirEntry.Type == DirectoryEntryType.Directory)
|
else
|
||||||
{
|
{
|
||||||
rc = onEnterDir(in workPath, in dirEntry, ref closure);
|
rc = onFile(in workPath, in dirEntry, ref closure);
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = CleanupDirectoryRecursivelyInternal(fs, ref workPath, ref dirEntry, onEnterDir, onExitDir,
|
|
||||||
onFile, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = onExitDir(in workPath, in dirEntry, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = onFile(in workPath, in dirEntry, ref closure);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = workPath.RemoveChild();
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
rc = workPath.RemoveChild();
|
||||||
}
|
if (rc.IsFailure()) return rc;
|
||||||
finally
|
|
||||||
{
|
|
||||||
directory?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result IterateDirectoryRecursively(IFileSystem fs, in Path rootPath, ref DirectoryEntry dirEntry,
|
public static Result IterateDirectoryRecursively(IFileSystem fs, in Path rootPath, ref DirectoryEntry dirEntry,
|
||||||
@ -171,38 +158,34 @@ namespace LibHac.FsSystem
|
|||||||
in Path sourcePath, Span<byte> workBuffer)
|
in Path sourcePath, Span<byte> workBuffer)
|
||||||
{
|
{
|
||||||
// Open source file.
|
// Open source file.
|
||||||
Result rc = sourceFileSystem.OpenFile(out IFile sourceFile, sourcePath, OpenMode.Read);
|
using var sourceFile = new UniqueRef<IFile>();
|
||||||
|
Result rc = sourceFileSystem.OpenFile(ref sourceFile.Ref(), sourcePath, OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (sourceFile)
|
rc = sourceFile.Get.GetSize(out long fileSize);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
using var destFile = new UniqueRef<IFile>();
|
||||||
|
rc = destFileSystem.CreateFile(in destPath, fileSize);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = destFileSystem.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
// Read/Write file in work buffer sized chunks.
|
||||||
|
long remaining = fileSize;
|
||||||
|
long offset = 0;
|
||||||
|
|
||||||
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
rc = sourceFile.GetSize(out long fileSize);
|
rc = sourceFile.Get.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = destFileSystem.CreateFile(in destPath, fileSize);
|
rc = destFile.Get.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = destFileSystem.OpenFile(out IFile destFile, in destPath, OpenMode.Write);
|
remaining -= bytesRead;
|
||||||
if (rc.IsFailure()) return rc;
|
offset += bytesRead;
|
||||||
|
|
||||||
using (destFile)
|
|
||||||
{
|
|
||||||
// Read/Write file in work buffer sized chunks.
|
|
||||||
long remaining = fileSize;
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
while (remaining > 0)
|
|
||||||
{
|
|
||||||
rc = sourceFile.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = destFile.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
remaining -= bytesRead;
|
|
||||||
offset += bytesRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -300,31 +283,25 @@ namespace LibHac.FsSystem
|
|||||||
|
|
||||||
static Result OnFile(in Path path, in DirectoryEntry entry, ref FsIterationTaskClosure closure)
|
static Result OnFile(in Path path, in DirectoryEntry entry, ref FsIterationTaskClosure closure)
|
||||||
{
|
{
|
||||||
IFile file = null;
|
using var file = new UniqueRef<IFile>();
|
||||||
try
|
|
||||||
|
Result rc = closure.SourceFileSystem.OpenFile(ref file.Ref(), in path, OpenMode.Read);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
long offset = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
Result rc = closure.SourceFileSystem.OpenFile(out file, in path, OpenMode.Read);
|
rc = file.Get.Read(out long bytesRead, offset, closure.Buffer, ReadOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
long offset = 0;
|
if (bytesRead < closure.Buffer.Length)
|
||||||
|
break;
|
||||||
|
|
||||||
while (true)
|
offset += bytesRead;
|
||||||
{
|
|
||||||
rc = file.Read(out long bytesRead, offset, closure.Buffer, ReadOption.None);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
if (bytesRead < closure.Buffer.Length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
offset += bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
file?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var rootPath = new Path();
|
using var rootPath = new Path();
|
||||||
@ -420,46 +397,30 @@ namespace LibHac.FsSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result TryAcquireCountSemaphore(out UniqueLock<SemaphoreAdapter> uniqueLock, SemaphoreAdapter semaphore)
|
public static Result TryAcquireCountSemaphore(ref UniqueLock<SemaphoreAdapter> outUniqueLock,
|
||||||
|
SemaphoreAdapter semaphore)
|
||||||
{
|
{
|
||||||
UniqueLock<SemaphoreAdapter> tempUniqueLock = default;
|
using var uniqueLock = new UniqueLock<SemaphoreAdapter>(semaphore, new DeferLock());
|
||||||
try
|
|
||||||
{
|
|
||||||
tempUniqueLock = new UniqueLock<SemaphoreAdapter>(semaphore, new DeferLock());
|
|
||||||
|
|
||||||
if (!tempUniqueLock.TryLock())
|
if (!uniqueLock.TryLock())
|
||||||
{
|
return ResultFs.OpenCountLimit.Log();
|
||||||
uniqueLock = default;
|
|
||||||
return ResultFs.OpenCountLimit.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
uniqueLock = Shared.Move(ref tempUniqueLock);
|
outUniqueLock.Set(ref uniqueLock.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
tempUniqueLock.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result MakeUniqueLockWithPin<T>(out IUniqueLock uniqueLock, SemaphoreAdapter semaphore,
|
public static Result MakeUniqueLockWithPin<T>(ref UniqueRef<IUniqueLock> outUniqueLock,
|
||||||
ref ReferenceCountedDisposable<T> objectToPin) where T : class, IDisposable
|
SemaphoreAdapter semaphore, ref ReferenceCountedDisposable<T> objectToPin) where T : class, IDisposable
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out uniqueLock);
|
using var semaphoreAdapter = new UniqueLock<SemaphoreAdapter>();
|
||||||
|
Result rc = TryAcquireCountSemaphore(ref semaphoreAdapter.Ref(), semaphore);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
UniqueLock<SemaphoreAdapter> tempUniqueLock = default;
|
var lockWithPin = new UniqueLockWithPin<T>(ref semaphoreAdapter.Ref(), ref objectToPin);
|
||||||
try
|
using var uniqueLock = new UniqueRef<IUniqueLock>(lockWithPin);
|
||||||
{
|
|
||||||
Result rc = TryAcquireCountSemaphore(out tempUniqueLock, semaphore);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
uniqueLock = new UniqueLockWithPin<T>(ref tempUniqueLock, ref objectToPin);
|
outUniqueLock.Set(ref uniqueLock.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
tempUniqueLock.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
|
using static InlineIL.IL.Emit;
|
||||||
|
|
||||||
namespace LibHac.Os
|
namespace LibHac.Os
|
||||||
{
|
{
|
||||||
@ -24,6 +25,22 @@ namespace LibHac.Os
|
|||||||
{
|
{
|
||||||
return new UniqueLock<TMutex>(lockable);
|
return new UniqueLock<TMutex>(lockable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once EntityNameCapturedOnly.Global
|
||||||
|
public static ref UniqueLockRef<T> Ref<T>(this in UniqueLockRef<T> value) where T : struct, ILockable
|
||||||
|
{
|
||||||
|
Ldarg(nameof(value));
|
||||||
|
Ret();
|
||||||
|
throw InlineIL.IL.Unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once EntityNameCapturedOnly.Global
|
||||||
|
public static ref UniqueLock<T> Ref<T>(this in UniqueLock<T> value) where T : class, ILockable
|
||||||
|
{
|
||||||
|
Ldarg(nameof(value));
|
||||||
|
Ret();
|
||||||
|
throw InlineIL.IL.Unreachable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
|
public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
|
||||||
|
@ -107,9 +107,10 @@ namespace LibHac
|
|||||||
SwitchFsNca nca = null;
|
SwitchFsNca nca = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
|
ContentFs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
nca = new SwitchFsNca(new Nca(KeySet, ncaFile.AsStorage()));
|
nca = new SwitchFsNca(new Nca(KeySet, ncaFile.Release().AsStorage()));
|
||||||
|
|
||||||
nca.NcaId = GetNcaFilename(fileEntry.Name, nca);
|
nca.NcaId = GetNcaFilename(fileEntry.Name, nca);
|
||||||
string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca";
|
string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca";
|
||||||
@ -145,9 +146,10 @@ namespace LibHac
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SaveFs.OpenFile(out IFile file, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using var file = new UniqueRef<IFile>();
|
||||||
|
SaveFs.OpenFile(ref file.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
save = new SaveDataFileSystem(KeySet, file.AsStorage(), IntegrityCheckLevel.None, true);
|
save = new SaveDataFileSystem(KeySet, file.Release().AsStorage(), IntegrityCheckLevel.None, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -172,9 +174,10 @@ namespace LibHac
|
|||||||
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
|
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, cnmtPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using var file = new UniqueRef<IFile>();
|
||||||
|
fs.OpenFile(ref file.Ref(), cnmtPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
var metadata = new Cnmt(file.AsStream());
|
var metadata = new Cnmt(file.Release().AsStream());
|
||||||
title.Id = metadata.TitleId;
|
title.Id = metadata.TitleId;
|
||||||
title.Version = metadata.TitleVersion;
|
title.Version = metadata.TitleVersion;
|
||||||
title.Metadata = metadata;
|
title.Metadata = metadata;
|
||||||
@ -216,11 +219,12 @@ namespace LibHac
|
|||||||
foreach (Title title in Titles.Values.Where(x => x.ControlNca != null))
|
foreach (Title title in Titles.Values.Where(x => x.ControlNca != null))
|
||||||
{
|
{
|
||||||
IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
romfs.OpenFile(out IFile control, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
|
||||||
|
|
||||||
using (control)
|
using (var control = new UniqueRef<IFile>())
|
||||||
{
|
{
|
||||||
control.Read(out _, 0, title.Control.ByteSpan).ThrowIfFailure();
|
romfs.OpenFile(ref control.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
|
control.Get.Read(out _, 0, title.Control.ByteSpan).ThrowIfFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ref ApplicationControlTitle desc in title.Control.Value.Titles)
|
foreach (ref ApplicationControlTitle desc in title.Control.Value.Titles)
|
||||||
|
@ -32,8 +32,9 @@ namespace LibHac
|
|||||||
XciPartition root = GetRootPartition();
|
XciPartition root = GetRootPartition();
|
||||||
if (type == XciPartitionType.Root) return root;
|
if (type == XciPartitionType.Root) return root;
|
||||||
|
|
||||||
root.OpenFile(out IFile partitionFile, type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using var partitionFile = new UniqueRef<IFile>();
|
||||||
return new XciPartition(partitionFile.AsStorage());
|
root.OpenFile(ref partitionFile.Ref(), type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
return new XciPartition(partitionFile.Release().AsStorage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private XciPartition GetRootPartition()
|
private XciPartition GetRootPartition()
|
||||||
|
@ -36,9 +36,10 @@ namespace hactoolnet
|
|||||||
throw new FileNotFoundException("Specified NCA does not contain a delta fragment");
|
throw new FileNotFoundException("Specified NCA does not contain a delta fragment");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName.ToU8String(), OpenMode.Read).ThrowIfFailure();
|
using var deltaFragmentFile = new UniqueRef<IFile>();
|
||||||
|
fs.OpenFile(ref deltaFragmentFile.Ref(), FragmentFileName.ToU8String(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
deltaStorage = deltaFragmentFile.AsStorage();
|
deltaStorage = deltaFragmentFile.Release().AsStorage();
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { } // Ignore non-NCA3 files
|
catch (InvalidDataException) { } // Ignore non-NCA3 files
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using LibHac;
|
|||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Crypto;
|
using LibHac.Crypto;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Fsa;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
using LibHac.Util;
|
using LibHac.Util;
|
||||||
using static hactoolnet.Print;
|
using static hactoolnet.Print;
|
||||||
@ -23,7 +24,7 @@ namespace hactoolnet
|
|||||||
|
|
||||||
Span<AesXtsKey> keys = ctx.KeySet.SdCardEncryptionKeys;
|
Span<AesXtsKey> keys = ctx.KeySet.SdCardEncryptionKeys;
|
||||||
|
|
||||||
using var baseFile = new LocalFile(ctx.Options.InFile, OpenMode.Read);
|
using var baseFile = new UniqueRef<IFile>(new LocalFile(ctx.Options.InFile, OpenMode.Read));
|
||||||
|
|
||||||
AesXtsFile xtsFile = null;
|
AesXtsFile xtsFile = null;
|
||||||
int contentType = 0;
|
int contentType = 0;
|
||||||
@ -35,7 +36,7 @@ namespace hactoolnet
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath.ToU8String(), kekSource, validationKey, 0x4000);
|
xtsFile = new AesXtsFile(OpenMode.Read, ref baseFile.Ref(), ctx.Options.SdPath.ToU8String(), kekSource, validationKey, 0x4000);
|
||||||
contentType = i;
|
contentType = i;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -227,8 +227,9 @@ namespace hactoolnet
|
|||||||
IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid);
|
IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
if (!pfs.FileExists("main.npdm")) return Validity.Unchecked;
|
if (!pfs.FileExists("main.npdm")) return Validity.Unchecked;
|
||||||
|
|
||||||
pfs.OpenFile(out IFile npdmFile, "main.npdm".ToU8String(), OpenMode.Read).ThrowIfFailure();
|
using var npdmFile = new UniqueRef<IFile>();
|
||||||
var npdm = new NpdmBinary(npdmFile.AsStream());
|
pfs.OpenFile(ref npdmFile.Ref(), "main.npdm".ToU8String(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
var npdm = new NpdmBinary(npdmFile.Release().AsStream());
|
||||||
|
|
||||||
return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus);
|
return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus);
|
||||||
}
|
}
|
||||||
@ -258,10 +259,12 @@ namespace hactoolnet
|
|||||||
if (nca.CanOpenSection(NcaSectionType.Code))
|
if (nca.CanOpenSection(NcaSectionType.Code))
|
||||||
{
|
{
|
||||||
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None);
|
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None);
|
||||||
Result r = fs.OpenFile(out IFile file, "/main.npdm".ToU8String(), OpenMode.Read);
|
|
||||||
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Result r = fs.OpenFile(ref file.Ref(), "/main.npdm".ToU8String(), OpenMode.Read);
|
||||||
if (r.IsSuccess())
|
if (r.IsSuccess())
|
||||||
{
|
{
|
||||||
var npdm = new NpdmBinary(file.AsStream(), null);
|
var npdm = new NpdmBinary(file.Release().AsStream(), null);
|
||||||
PrintItem(sb, colLen, "Title Name:", npdm.TitleName);
|
PrintItem(sb, colLen, "Title Name:", npdm.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,26 +67,23 @@ namespace hactoolnet
|
|||||||
string destFilename = ctx.Options.ReplaceFileDest;
|
string destFilename = ctx.Options.ReplaceFileDest;
|
||||||
if (!destFilename.StartsWith("/")) destFilename = '/' + destFilename;
|
if (!destFilename.StartsWith("/")) destFilename = '/' + destFilename;
|
||||||
|
|
||||||
using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read))
|
using var inFile = new UniqueRef<IFile>(new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read));
|
||||||
|
|
||||||
|
using var outFile = new UniqueRef<IFile>();
|
||||||
|
save.OpenFile(ref outFile.Ref(), destFilename.ToU8String(), OpenMode.ReadWrite).ThrowIfFailure();
|
||||||
|
|
||||||
|
inFile.Get.GetSize(out long inFileSize).ThrowIfFailure();
|
||||||
|
outFile.Get.GetSize(out long outFileSize).ThrowIfFailure();
|
||||||
|
|
||||||
|
if (inFileSize != outFileSize)
|
||||||
{
|
{
|
||||||
save.OpenFile(out IFile outFile, destFilename.ToU8String(), OpenMode.ReadWrite).ThrowIfFailure();
|
outFile.Get.SetSize(inFileSize).ThrowIfFailure();
|
||||||
|
|
||||||
using (outFile)
|
|
||||||
{
|
|
||||||
inFile.GetSize(out long inFileSize).ThrowIfFailure();
|
|
||||||
outFile.GetSize(out long outFileSize).ThrowIfFailure();
|
|
||||||
|
|
||||||
if (inFileSize != outFileSize)
|
|
||||||
{
|
|
||||||
outFile.SetSize(inFileSize).ThrowIfFailure();
|
|
||||||
}
|
|
||||||
|
|
||||||
inFile.CopyTo(outFile, ctx.Logger);
|
|
||||||
|
|
||||||
ctx.Logger.LogMessage($"Replaced file {destFilename}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inFile.Get.CopyTo(outFile.Get, ctx.Logger);
|
||||||
|
|
||||||
|
ctx.Logger.LogMessage($"Replaced file {destFilename}");
|
||||||
|
|
||||||
signNeeded = true;
|
signNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,20 +34,45 @@ namespace LibHac.Tests.Fs
|
|||||||
|
|
||||||
public IFileSystem Create()
|
public IFileSystem Create()
|
||||||
{
|
{
|
||||||
DirectorySaveDataFileSystem
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, BaseFileSystem, true, true, true)
|
||||||
.CreateNew(out DirectorySaveDataFileSystem saveFs, BaseFileSystem, true, true, true)
|
|
||||||
.ThrowIfFailure();
|
.ThrowIfFailure();
|
||||||
|
|
||||||
return saveFs;
|
return saveFs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Result CreateDirSaveFs(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
||||||
|
ISaveDataCommitTimeStampGetter timeStampGetter, RandomDataGenerator randomGenerator,
|
||||||
|
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled,
|
||||||
|
FileSystemClient fsClient)
|
||||||
|
{
|
||||||
|
var obj = new DirectorySaveDataFileSystem(baseFileSystem, fsClient);
|
||||||
|
Result rc = obj.Initialize(timeStampGetter, randomGenerator, isJournalingSupported, isMultiCommitSupported,
|
||||||
|
isJournalingEnabled);
|
||||||
|
|
||||||
|
if (rc.IsSuccess())
|
||||||
|
{
|
||||||
|
created = obj;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Dispose();
|
||||||
|
UnsafeHelpers.SkipParamInit(out created);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result CreateDirSaveFs(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
||||||
|
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled)
|
||||||
|
{
|
||||||
|
return CreateDirSaveFs(out created, baseFileSystem, null, null, isJournalingSupported, isMultiCommitSupported,
|
||||||
|
isJournalingEnabled, null);
|
||||||
|
}
|
||||||
|
|
||||||
private (IFileSystem baseFs, DirectorySaveDataFileSystem saveFs) CreateFileSystemInternal()
|
private (IFileSystem baseFs, DirectorySaveDataFileSystem saveFs) CreateFileSystemInternal()
|
||||||
{
|
{
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
return (baseFs, saveFs);
|
return (baseFs, saveFs);
|
||||||
}
|
}
|
||||||
@ -132,8 +157,7 @@ namespace LibHac.Tests.Fs
|
|||||||
baseFs.CreateFile("/0/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
baseFs.CreateFile("/0/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||||
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
Assert.Success(saveFs.GetEntryType(out _, "/file1"));
|
Assert.Success(saveFs.GetEntryType(out _, "/file1"));
|
||||||
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file2"));
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file2"));
|
||||||
@ -151,8 +175,7 @@ namespace LibHac.Tests.Fs
|
|||||||
baseFs.CreateFile("/_/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
baseFs.CreateFile("/_/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||||
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
||||||
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
||||||
@ -168,8 +191,7 @@ namespace LibHac.Tests.Fs
|
|||||||
// Set the existing files before initializing the save FS
|
// Set the existing files before initializing the save FS
|
||||||
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
||||||
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
||||||
@ -202,8 +224,7 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
var originalExtraData = new SaveDataExtraData();
|
var originalExtraData = new SaveDataExtraData();
|
||||||
originalExtraData.DataSize = 0x12345;
|
originalExtraData.DataSize = 0x12345;
|
||||||
@ -212,7 +233,7 @@ namespace LibHac.Tests.Fs
|
|||||||
Assert.Success(saveFs.CommitExtraData(false));
|
Assert.Success(saveFs.CommitExtraData(false));
|
||||||
|
|
||||||
saveFs.Dispose();
|
saveFs.Dispose();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
|
|
||||||
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
||||||
Assert.Equal(originalExtraData, extraData);
|
Assert.Equal(originalExtraData, extraData);
|
||||||
@ -223,8 +244,7 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
var originalExtraData = new SaveDataExtraData();
|
var originalExtraData = new SaveDataExtraData();
|
||||||
originalExtraData.DataSize = 0x12345;
|
originalExtraData.DataSize = 0x12345;
|
||||||
@ -233,7 +253,7 @@ namespace LibHac.Tests.Fs
|
|||||||
saveFs.CommitExtraData(false).ThrowIfFailure();
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
||||||
|
|
||||||
saveFs.Dispose();
|
saveFs.Dispose();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
|
|
||||||
var newExtraData = new SaveDataExtraData();
|
var newExtraData = new SaveDataExtraData();
|
||||||
newExtraData.DataSize = 0x67890;
|
newExtraData.DataSize = 0x67890;
|
||||||
@ -251,8 +271,7 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
// Write extra data and close with committing
|
// Write extra data and close with committing
|
||||||
var originalExtraData = new SaveDataExtraData();
|
var originalExtraData = new SaveDataExtraData();
|
||||||
@ -262,7 +281,7 @@ namespace LibHac.Tests.Fs
|
|||||||
saveFs.CommitExtraData(false).ThrowIfFailure();
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
||||||
|
|
||||||
saveFs.Dispose();
|
saveFs.Dispose();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
|
|
||||||
// Write a new extra data and close without committing
|
// Write a new extra data and close without committing
|
||||||
var newExtraData = new SaveDataExtraData();
|
var newExtraData = new SaveDataExtraData();
|
||||||
@ -272,7 +291,7 @@ namespace LibHac.Tests.Fs
|
|||||||
saveFs.Dispose();
|
saveFs.Dispose();
|
||||||
|
|
||||||
// Read extra data should match the first one
|
// Read extra data should match the first one
|
||||||
DirectorySaveDataFileSystem.CreateNew(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
||||||
|
|
||||||
Assert.Equal(originalExtraData, extraData);
|
Assert.Equal(originalExtraData, extraData);
|
||||||
@ -286,8 +305,7 @@ namespace LibHac.Tests.Fs
|
|||||||
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
||||||
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
||||||
|
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
||||||
|
|
||||||
@ -302,8 +320,8 @@ namespace LibHac.Tests.Fs
|
|||||||
var timeStampGetter = new TimeStampGetter();
|
var timeStampGetter = new TimeStampGetter();
|
||||||
|
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||||
|
|
||||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||||
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
||||||
@ -330,8 +348,8 @@ namespace LibHac.Tests.Fs
|
|||||||
var timeStampGetter = new TimeStampGetter();
|
var timeStampGetter = new TimeStampGetter();
|
||||||
|
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||||
|
|
||||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||||
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
||||||
@ -358,8 +376,8 @@ namespace LibHac.Tests.Fs
|
|||||||
var timeStampGetter = new TimeStampGetter();
|
var timeStampGetter = new TimeStampGetter();
|
||||||
|
|
||||||
var baseFs = new InMemoryFileSystem();
|
var baseFs = new InMemoryFileSystem();
|
||||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||||
|
|
||||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||||
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
||||||
@ -421,12 +439,13 @@ namespace LibHac.Tests.Fs
|
|||||||
var extraData = new SaveDataExtraData();
|
var extraData = new SaveDataExtraData();
|
||||||
extraData.DataSize = saveDataSize;
|
extraData.DataSize = saveDataSize;
|
||||||
|
|
||||||
rc = fileSystem.OpenFile(out IFile file, path, OpenMode.ReadWrite);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
rc = fileSystem.OpenFile(ref file.Ref(), path, OpenMode.ReadWrite);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (file)
|
using (file)
|
||||||
{
|
{
|
||||||
rc = file.Write(0, SpanHelpers.AsByteSpan(ref extraData), WriteOption.Flush);
|
rc = file.Get.Write(0, SpanHelpers.AsByteSpan(ref extraData), WriteOption.Flush);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,26 +140,22 @@ namespace LibHac.Tests.Fs
|
|||||||
return fs.GetTotalSpaceSize(out totalSpace, in pathNormalized);
|
return fs.GetTotalSpaceSize(out totalSpace, in pathNormalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result OpenFile(this IFileSystem fs, out IFile file, string path, OpenMode mode)
|
public static Result OpenFile(this IFileSystem fs, ref UniqueRef<IFile> file, string path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return fs.OpenFile(out file, in pathNormalized, mode);
|
return fs.OpenFile(ref file, in pathNormalized, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result OpenDirectory(this IFileSystem fs, out IDirectory directory, string path, OpenDirectoryMode mode)
|
public static Result OpenDirectory(this IFileSystem fs, ref UniqueRef<IDirectory> directory, string path, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
|
||||||
|
|
||||||
using var pathNormalized = new Path();
|
using var pathNormalized = new Path();
|
||||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return fs.OpenDirectory(out directory, in pathNormalized, mode);
|
return fs.OpenDirectory(ref directory, in pathNormalized, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result GetFileTimeStampRaw(this IFileSystem fs, out FileTimeStampRaw timeStamp, string path)
|
public static Result GetFileTimeStampRaw(this IFileSystem fs, out FileTimeStampRaw timeStamp, string path)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -23,14 +24,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/dir1/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
fs.CreateFile("/dir1/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||||
fs.CreateFile("/dir2/file", data2.Length, CreateFileOptions.None).ThrowIfFailure();
|
fs.CreateFile("/dir2/file", data2.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||||
|
|
||||||
fs.OpenFile(out IFile file1, "/dir1/file", OpenMode.Write).ThrowIfFailure();
|
using var file1 = new UniqueRef<IFile>();
|
||||||
fs.OpenFile(out IFile file2, "/dir2/file", OpenMode.Write).ThrowIfFailure();
|
using var file2 = new UniqueRef<IFile>();
|
||||||
|
|
||||||
file1.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
fs.OpenFile(ref file1.Ref(), "/dir1/file", OpenMode.Write).ThrowIfFailure();
|
||||||
file2.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
fs.OpenFile(ref file2.Ref(), "/dir2/file", OpenMode.Write).ThrowIfFailure();
|
||||||
|
|
||||||
file1.Dispose();
|
file1.Get.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||||
file2.Dispose();
|
file2.Get.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||||
|
|
||||||
|
file1.Reset();
|
||||||
|
file2.Reset();
|
||||||
|
|
||||||
fs.Commit().ThrowIfFailure();
|
fs.Commit().ThrowIfFailure();
|
||||||
fs.Dispose();
|
fs.Dispose();
|
||||||
@ -41,23 +45,18 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
byte[] readData1 = new byte[data1.Length];
|
byte[] readData1 = new byte[data1.Length];
|
||||||
byte[] readData2 = new byte[data2.Length];
|
byte[] readData2 = new byte[data2.Length];
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out file1, "/dir1/file", OpenMode.Read));
|
Assert.Success(fs.OpenFile(ref file1.Ref(), "/dir1/file", OpenMode.Read));
|
||||||
|
|
||||||
using (file1)
|
Assert.Success(file1.Get.Read(out long bytesReadFile1, 0, readData1, ReadOption.None));
|
||||||
{
|
file1.Reset();
|
||||||
Assert.Success(file1.Read(out long bytesRead, 0, readData1, ReadOption.None));
|
Assert.Equal(data1.Length, bytesReadFile1);
|
||||||
Assert.Equal(data1.Length, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(data1, readData1);
|
Assert.Equal(data1, readData1);
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out file2, "/dir2/file", OpenMode.Read));
|
Assert.Success(fs.OpenFile(ref file2.Ref(), "/dir2/file", OpenMode.Read));
|
||||||
|
|
||||||
using (file2)
|
Assert.Success(file2.Get.Read(out long bytesReadFile2, 0, readData2, ReadOption.None));
|
||||||
{
|
Assert.Equal(data2.Length, bytesReadFile2);
|
||||||
Assert.Success(file2.Read(out long bytesRead, 0, readData2, ReadOption.None));
|
|
||||||
Assert.Equal(data2.Length, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(data2, readData2);
|
Assert.Equal(data2, readData2);
|
||||||
}
|
}
|
||||||
@ -109,9 +108,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateDirectory("/dir").ThrowIfFailure();
|
fs.CreateDirectory("/dir").ThrowIfFailure();
|
||||||
fs.CreateFile("/dir/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
fs.CreateFile("/dir/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/dir/file", OpenMode.Write).ThrowIfFailure();
|
using var file = new UniqueRef<IFile>();
|
||||||
file.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
fs.OpenFile(ref file.Ref(), "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||||
file.Dispose();
|
file.Get.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||||
|
file.Reset();
|
||||||
|
|
||||||
// Commit and reopen the file system
|
// Commit and reopen the file system
|
||||||
fs.Commit().ThrowIfFailure();
|
fs.Commit().ThrowIfFailure();
|
||||||
@ -120,22 +120,19 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs = fsCreator.Create();
|
fs = fsCreator.Create();
|
||||||
|
|
||||||
// Make changes to the file
|
// Make changes to the file
|
||||||
fs.OpenFile(out file, "/dir/file", OpenMode.Write).ThrowIfFailure();
|
fs.OpenFile(ref file.Ref(), "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||||
file.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
file.Get.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||||
file.Dispose();
|
file.Reset();
|
||||||
|
|
||||||
Assert.Success(fs.Rollback());
|
Assert.Success(fs.Rollback());
|
||||||
|
|
||||||
// The file should contain the original data after the rollback
|
// The file should contain the original data after the rollback
|
||||||
byte[] readData = new byte[data1.Length];
|
byte[] readData = new byte[data1.Length];
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out file, "/dir/file", OpenMode.Read));
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir/file", OpenMode.Read));
|
||||||
|
|
||||||
using (file)
|
Assert.Success(file.Get.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||||
{
|
Assert.Equal(data1.Length, bytesRead);
|
||||||
Assert.Success(file.Read(out long bytesRead, 0, readData, ReadOption.None));
|
|
||||||
Assert.Equal(data1.Length, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(data1, readData);
|
Assert.Equal(data1, readData);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -72,9 +73,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.CreateFile("/file", expectedSize, CreateFileOptions.None);
|
fs.CreateFile("/file", expectedSize, CreateFileOptions.None);
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
|
|
||||||
Assert.Success(file.GetSize(out long fileSize));
|
Assert.Success(file.Get.GetSize(out long fileSize));
|
||||||
Assert.Equal(expectedSize, fileSize);
|
Assert.Equal(expectedSize, fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,9 +15,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[1];
|
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[1];
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.Read(out long entriesRead, entries));
|
Assert.Success(directory.Get.Read(out long entriesRead, entries));
|
||||||
Assert.Equal(0, entriesRead);
|
Assert.Equal(0, entriesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,9 +27,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.GetEntryCount(out long entryCount));
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
||||||
Assert.Equal(0, entryCount);
|
Assert.Equal(0, entryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,17 +44,18 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
|
fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
|
||||||
fs.CreateFile("/dir/file2", 0, CreateFileOptions.None);
|
fs.CreateFile("/dir/file2", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All));
|
using var dir = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref dir.Ref(), "/dir", OpenDirectoryMode.All));
|
||||||
|
|
||||||
var entry1 = new DirectoryEntry();
|
var entry1 = new DirectoryEntry();
|
||||||
var entry2 = new DirectoryEntry();
|
var entry2 = new DirectoryEntry();
|
||||||
var entry3 = new DirectoryEntry();
|
var entry3 = new DirectoryEntry();
|
||||||
var entry4 = new DirectoryEntry();
|
var entry4 = new DirectoryEntry();
|
||||||
|
|
||||||
Assert.Success(dir.Read(out long entriesRead1, SpanHelpers.AsSpan(ref entry1)));
|
Assert.Success(dir.Get.Read(out long entriesRead1, SpanHelpers.AsSpan(ref entry1)));
|
||||||
Assert.Success(dir.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)));
|
Assert.Success(dir.Get.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)));
|
||||||
Assert.Success(dir.Read(out long entriesRead3, SpanHelpers.AsSpan(ref entry3)));
|
Assert.Success(dir.Get.Read(out long entriesRead3, SpanHelpers.AsSpan(ref entry3)));
|
||||||
Assert.Success(dir.Read(out long entriesRead4, SpanHelpers.AsSpan(ref entry4)));
|
Assert.Success(dir.Get.Read(out long entriesRead4, SpanHelpers.AsSpan(ref entry4)));
|
||||||
|
|
||||||
Assert.Equal(1, entriesRead1);
|
Assert.Equal(1, entriesRead1);
|
||||||
Assert.Equal(1, entriesRead2);
|
Assert.Equal(1, entriesRead2);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -15,12 +16,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[20];
|
byte[] buffer = new byte[20];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Assert.Success(file.Read(out long bytesRead, 50, buffer, ReadOption.None));
|
Assert.Success(file.Get.Read(out long bytesRead, 50, buffer, ReadOption.None));
|
||||||
Assert.Equal(20, bytesRead);
|
Assert.Equal(20, bytesRead);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -31,12 +31,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Result rc = file.Read(out _, 1, buffer, ReadOption.None);
|
Result rc = file.Get.Read(out _, 1, buffer, ReadOption.None);
|
||||||
Assert.Result(ResultFs.OutOfRange, rc);
|
Assert.Result(ResultFs.OutOfRange, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -47,12 +46,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
{
|
|
||||||
Result rc = file.Read(out _, 0, buffer, ReadOption.None);
|
Result rc = file.Get.Read(out _, 0, buffer, ReadOption.None);
|
||||||
Assert.Result(ResultFs.ReadUnpermitted, rc);
|
Assert.Result(ResultFs.ReadUnpermitted, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -63,12 +61,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
{
|
|
||||||
Result rc = file.Read(out _, -5, buffer, ReadOption.None);
|
Result rc = file.Get.Read(out _, -5, buffer, ReadOption.None);
|
||||||
Assert.Result(ResultFs.OutOfRange, rc);
|
Assert.Result(ResultFs.OutOfRange, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -79,12 +76,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
{
|
|
||||||
Result rc = file.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
|
Result rc = file.Get.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
|
||||||
Assert.Result(ResultFs.OutOfRange, rc);
|
Assert.Result(ResultFs.OutOfRange, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -95,12 +91,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[200];
|
byte[] buffer = new byte[200];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Assert.Success(file.Read(out long bytesRead, 90, buffer, ReadOption.None));
|
Assert.Success(file.Get.Read(out long bytesRead, 90, buffer, ReadOption.None));
|
||||||
Assert.Equal(10, bytesRead);
|
Assert.Equal(10, bytesRead);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -111,11 +106,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||||
|
|
||||||
// The contents of a created file are undefined, so zero the file
|
// The contents of a created file are undefined, so zero the file
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
{
|
file.Get.Write(0, new byte[100], WriteOption.None);
|
||||||
file.Write(0, new byte[100], WriteOption.None);
|
file.Reset();
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bufferExpected = new byte[200];
|
byte[] bufferExpected = new byte[200];
|
||||||
bufferExpected.AsSpan(10).Fill(0xCC);
|
bufferExpected.AsSpan(10).Fill(0xCC);
|
||||||
@ -123,12 +117,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
byte[] buffer = new byte[200];
|
byte[] buffer = new byte[200];
|
||||||
buffer.AsSpan().Fill(0xCC);
|
buffer.AsSpan().Fill(0xCC);
|
||||||
|
|
||||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
using (file)
|
|
||||||
{
|
Assert.Success(file.Get.Read(out _, 90, buffer, ReadOption.None));
|
||||||
Assert.Success(file.Read(out _, 90, buffer, ReadOption.None));
|
Assert.Equal(bufferExpected, buffer);
|
||||||
Assert.Equal(bufferExpected, buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -12,13 +13,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
using var file = new UniqueRef<IFile>();
|
||||||
Result rc = file.SetSize(54321);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||||
file.Dispose();
|
Result rc = file.Get.SetSize(54321);
|
||||||
|
file.Reset();
|
||||||
|
|
||||||
fs.OpenFile(out file, "/file", OpenMode.All);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||||
file.GetSize(out long fileSize);
|
file.Get.GetSize(out long fileSize);
|
||||||
file.Dispose();
|
|
||||||
|
|
||||||
Assert.Success(rc);
|
Assert.Success(rc);
|
||||||
Assert.Equal(54321, fileSize);
|
Assert.Equal(54321, fileSize);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -16,18 +17,16 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
file.Write(0, data, WriteOption.None);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
file.Dispose();
|
file.Get.Write(0, data, WriteOption.None);
|
||||||
|
file.Reset();
|
||||||
|
|
||||||
byte[] readData = new byte[data.Length];
|
byte[] readData = new byte[data.Length];
|
||||||
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
|
|
||||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
Assert.Success(file.Get.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||||
using (file)
|
Assert.Equal(data.Length, bytesRead);
|
||||||
{
|
|
||||||
Assert.Success(file.Read(out long bytesRead, 0, readData, ReadOption.None));
|
|
||||||
Assert.Equal(data.Length, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(data, readData);
|
Assert.Equal(data, readData);
|
||||||
}
|
}
|
||||||
@ -40,12 +39,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
{
|
|
||||||
Result rc = file.Write(5, buffer, WriteOption.None);
|
Result rc = file.Get.Write(5, buffer, WriteOption.None);
|
||||||
Assert.Result(ResultFs.FileExtensionWithoutOpenModeAllowAppend, rc);
|
Assert.Result(ResultFs.FileExtensionWithoutOpenModeAllowAppend, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -56,12 +54,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Result rc = file.Write(5, buffer, WriteOption.None);
|
Result rc = file.Get.Write(5, buffer, WriteOption.None);
|
||||||
Assert.Result(ResultFs.WriteUnpermitted, rc);
|
Assert.Result(ResultFs.WriteUnpermitted, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -72,12 +69,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Result rc = file.Write(-5, buffer, WriteOption.None);
|
Result rc = file.Get.Write(-5, buffer, WriteOption.None);
|
||||||
Assert.Result(ResultFs.OutOfRange, rc);
|
Assert.Result(ResultFs.OutOfRange, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -88,12 +84,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
{
|
|
||||||
Result rc = file.Write(long.MaxValue - 5, buffer, WriteOption.None);
|
Result rc = file.Get.Write(long.MaxValue - 5, buffer, WriteOption.None);
|
||||||
Assert.Result(ResultFs.OutOfRange, rc);
|
Assert.Result(ResultFs.OutOfRange, rc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -104,14 +99,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||||
{
|
|
||||||
Assert.Success(file.Write(5, buffer, WriteOption.None));
|
|
||||||
|
|
||||||
file.GetSize(out long newSize);
|
Assert.Success(file.Get.Write(5, buffer, WriteOption.None));
|
||||||
Assert.Equal(15, newSize);
|
|
||||||
}
|
file.Get.GetSize(out long newSize);
|
||||||
|
Assert.Equal(15, newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -122,14 +116,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||||
|
|
||||||
byte[] buffer = new byte[10];
|
byte[] buffer = new byte[10];
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||||
{
|
|
||||||
Assert.Success(file.Write(15, buffer, WriteOption.None));
|
|
||||||
|
|
||||||
file.GetSize(out long newSize);
|
Assert.Success(file.Get.Write(15, buffer, WriteOption.None));
|
||||||
Assert.Equal(25, newSize);
|
|
||||||
}
|
file.Get.GetSize(out long newSize);
|
||||||
|
Assert.Equal(25, newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -145,23 +138,21 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
byte[] writeBuffer = new byte[10];
|
byte[] writeBuffer = new byte[10];
|
||||||
writeBuffer.AsSpan().Fill(0xCC);
|
writeBuffer.AsSpan().Fill(0xCC);
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
using var file = new UniqueRef<IFile>();
|
||||||
using (file)
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||||
{
|
|
||||||
Assert.Success(file.Write(15, writeBuffer, WriteOption.None));
|
|
||||||
|
|
||||||
// Unwritten portions of new files are undefined, so write to the other portions
|
Assert.Success(file.Get.Write(15, writeBuffer, WriteOption.None));
|
||||||
file.Write(0, new byte[15], WriteOption.None);
|
|
||||||
}
|
// Unwritten portions of new files are undefined, so write to the other portions
|
||||||
|
file.Get.Write(0, new byte[15], WriteOption.None);
|
||||||
|
file.Reset();
|
||||||
|
|
||||||
byte[] readBuffer = new byte[25];
|
byte[] readBuffer = new byte[25];
|
||||||
|
|
||||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||||
using (file)
|
|
||||||
{
|
file.Get.Read(out _, 0, readBuffer, ReadOption.None);
|
||||||
file.Read(out _, 0, readBuffer, ReadOption.None);
|
Assert.Equal(bufferExpected, readBuffer);
|
||||||
Assert.Equal(bufferExpected, readBuffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -13,7 +14,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||||
|
|
||||||
Result rc = fs.OpenDirectory(out _, "/file", OpenDirectoryMode.All);
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Result rc = fs.OpenDirectory(ref directory.Ref(), "/file", OpenDirectoryMode.All);
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, rc);
|
Assert.Result(ResultFs.PathNotFound, rc);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -13,7 +14,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.CreateDirectory("/dir");
|
fs.CreateDirectory("/dir");
|
||||||
|
|
||||||
Result rc = fs.OpenFile(out _, "/dir", OpenMode.All);
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Result rc = fs.OpenFile(ref file.Ref(), "/dir", OpenMode.All);
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, rc);
|
Assert.Result(ResultFs.PathNotFound, rc);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using LibHac.Fs;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -74,18 +75,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.RenameFile("/file1", "/file2");
|
fs.RenameFile("/file1", "/file2");
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out IFile file1, "/file1", OpenMode.Read));
|
using var file1 = new UniqueRef<IFile>();
|
||||||
Assert.Success(fs.OpenFile(out IFile file2, "/file2", OpenMode.Read));
|
using var file2 = new UniqueRef<IFile>();
|
||||||
|
|
||||||
using (file1)
|
Assert.Success(fs.OpenFile(ref file1.Ref(), "/file1", OpenMode.Read));
|
||||||
using (file2)
|
Assert.Success(fs.OpenFile(ref file2.Ref(), "/file2", OpenMode.Read));
|
||||||
{
|
|
||||||
Assert.Success(file1.GetSize(out long file1Size));
|
|
||||||
Assert.Success(file2.GetSize(out long file2Size));
|
|
||||||
|
|
||||||
Assert.Equal(54321, file1Size);
|
Assert.Success(file1.Get.GetSize(out long file1Size));
|
||||||
Assert.Equal(12345, file2Size);
|
Assert.Success(file2.Get.GetSize(out long file2Size));
|
||||||
}
|
|
||||||
|
Assert.Equal(54321, file1Size);
|
||||||
|
Assert.Equal(12345, file2Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -97,17 +97,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|||||||
|
|
||||||
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
||||||
|
|
||||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
using var file = new UniqueRef<IFile>();
|
||||||
file.Write(0, data, WriteOption.None);
|
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||||
file.Dispose();
|
file.Get.Write(0, data, WriteOption.None);
|
||||||
|
file.Reset();
|
||||||
|
|
||||||
fs.RenameFile("/file", "/renamed");
|
fs.RenameFile("/file", "/renamed");
|
||||||
|
|
||||||
byte[] readData = new byte[data.Length];
|
byte[] readData = new byte[data.Length];
|
||||||
|
|
||||||
fs.OpenFile(out file, "/renamed", OpenMode.Read);
|
fs.OpenFile(ref file.Ref(), "/renamed", OpenMode.Read);
|
||||||
Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
|
Result rc = file.Get.Read(out long bytesRead, 0, readData, ReadOption.None);
|
||||||
file.Dispose();
|
|
||||||
|
|
||||||
Assert.Success(rc);
|
Assert.Success(rc);
|
||||||
Assert.Equal(data.Length, bytesRead);
|
Assert.Equal(data.Length, bytesRead);
|
||||||
|
@ -58,7 +58,8 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, fs.OpenFile(out _, "/fakefile", OpenMode.All));
|
using var file = new UniqueRef<IFile>();
|
||||||
|
Assert.Result(ResultFs.PathNotFound, fs.OpenFile(ref file.Ref(), "/fakefile", OpenMode.All));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -66,8 +67,9 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile", OpenMode.All));
|
using var file = new UniqueRef<IFile>();
|
||||||
Assert.Success(file.GetSize(out long fileSize));
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir/replacedFile", OpenMode.All));
|
||||||
|
Assert.Success(file.Get.GetSize(out long fileSize));
|
||||||
|
|
||||||
Assert.Equal(2, fileSize);
|
Assert.Equal(2, fileSize);
|
||||||
}
|
}
|
||||||
@ -77,8 +79,9 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile", OpenMode.All));
|
using var file = new UniqueRef<IFile>();
|
||||||
Assert.Success(fs.OpenFile(out _, "/dir2/upperFile", OpenMode.All));
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/lowerFile", OpenMode.All));
|
||||||
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/upperFile", OpenMode.All));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -86,7 +89,8 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(out _, "/fakedir", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(ref directory.Ref(), "/fakedir", OpenDirectoryMode.All));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -94,8 +98,9 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
Assert.Equal(typeof(InMemoryFileSystem), dir.GetType().DeclaringType);
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/lowerDir", OpenDirectoryMode.All));
|
||||||
|
Assert.Equal(typeof(InMemoryFileSystem), directory.Get.GetType().DeclaringType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -103,8 +108,9 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
Assert.Equal(typeof(LayeredFileSystem), dir.GetType().DeclaringType);
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir", OpenDirectoryMode.All));
|
||||||
|
Assert.Equal(typeof(LayeredFileSystem), directory.Get.GetType().DeclaringType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -122,9 +128,10 @@ namespace LibHac.Tests.Fs
|
|||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[4];
|
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[4];
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.Read(out long entriesRead, entries));
|
Assert.Success(directory.Get.Read(out long entriesRead, entries));
|
||||||
Assert.Equal(3, entriesRead);
|
Assert.Equal(3, entriesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,9 +141,10 @@ namespace LibHac.Tests.Fs
|
|||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
var entry = new DirectoryEntry();
|
var entry = new DirectoryEntry();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.Read(out _, SpanHelpers.AsSpan(ref entry)));
|
Assert.Success(directory.Get.Read(out _, SpanHelpers.AsSpan(ref entry)));
|
||||||
Assert.Equal("replacedFile", StringUtils.Utf8ZToString(entry.Name));
|
Assert.Equal("replacedFile", StringUtils.Utf8ZToString(entry.Name));
|
||||||
Assert.Equal(2, entry.Size);
|
Assert.Equal(2, entry.Size);
|
||||||
}
|
}
|
||||||
@ -147,9 +155,10 @@ namespace LibHac.Tests.Fs
|
|||||||
IFileSystem fs = CreateEmptyFileSystem();
|
IFileSystem fs = CreateEmptyFileSystem();
|
||||||
var entry = new DirectoryEntry();
|
var entry = new DirectoryEntry();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref entry)));
|
Assert.Success(directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref entry)));
|
||||||
Assert.Equal(0, entriesRead);
|
Assert.Equal(0, entriesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,9 +167,10 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.GetEntryCount(out long entryCount));
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
||||||
Assert.Equal(3, entryCount);
|
Assert.Equal(3, entryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,16 +180,17 @@ namespace LibHac.Tests.Fs
|
|||||||
IFileSystem fs = CreateFileSystem();
|
IFileSystem fs = CreateFileSystem();
|
||||||
var entry = new DirectoryEntry();
|
var entry = new DirectoryEntry();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
||||||
|
|
||||||
// Read all entries
|
// Read all entries
|
||||||
long entriesRead;
|
long entriesRead;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Assert.Success(directory.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)));
|
Assert.Success(directory.Get.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)));
|
||||||
} while (entriesRead != 0);
|
} while (entriesRead != 0);
|
||||||
|
|
||||||
Assert.Success(directory.GetEntryCount(out long entryCount));
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
||||||
Assert.Equal(3, entryCount);
|
Assert.Equal(3, entryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,9 +199,10 @@ namespace LibHac.Tests.Fs
|
|||||||
{
|
{
|
||||||
IFileSystem fs = CreateEmptyFileSystem();
|
IFileSystem fs = CreateEmptyFileSystem();
|
||||||
|
|
||||||
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
|
using var directory = new UniqueRef<IDirectory>();
|
||||||
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
||||||
|
|
||||||
Assert.Success(directory.GetEntryCount(out long entryCount));
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
||||||
Assert.Equal(0, entryCount);
|
Assert.Equal(0, entryCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user