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"/>.
|
||||
/// </summary>
|
||||
/// <returns>The created <see cref="Path"/>.</returns>
|
||||
public readonly Path GetPath()
|
||||
public readonly Path DangerousGetPath()
|
||||
{
|
||||
return new Path
|
||||
{
|
||||
@ -1113,6 +1113,20 @@ namespace LibHac.Fs
|
||||
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
|
||||
internal static Result SetUpFixedPathSaveId(ref Path path, Span<byte> pathBuffer, ulong saveDataId)
|
||||
{
|
||||
|
@ -5,22 +5,24 @@ namespace LibHac.Fs
|
||||
{
|
||||
public class FileStorageBasedFileSystem : FileStorage2
|
||||
{
|
||||
private ReferenceCountedDisposable<IFileSystem> BaseFileSystem { get; set; }
|
||||
private IFile BaseFile { get; set; }
|
||||
private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
|
||||
private UniqueRef<IFile> _baseFile;
|
||||
|
||||
public FileStorageBasedFileSystem()
|
||||
{
|
||||
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;
|
||||
|
||||
SetFile(file);
|
||||
BaseFile = file;
|
||||
BaseFileSystem = Shared.Move(ref baseFileSystem);
|
||||
SetFile(baseFile.Get);
|
||||
_baseFileSystem = Shared.Move(ref baseFileSystem);
|
||||
_baseFile.Set(ref _baseFile.Ref());
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -29,8 +31,8 @@ namespace LibHac.Fs
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
BaseFile?.Dispose();
|
||||
BaseFileSystem?.Dispose();
|
||||
_baseFile.Dispose();
|
||||
_baseFileSystem?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
@ -7,33 +7,33 @@ namespace LibHac.Fs.Impl
|
||||
{
|
||||
internal class DirectoryAccessor : IDisposable
|
||||
{
|
||||
private IDirectory _directory;
|
||||
private UniqueRef<IDirectory> _directory;
|
||||
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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IDirectory directory = Shared.Move(ref _directory);
|
||||
directory?.Dispose();
|
||||
|
||||
_directory.Reset();
|
||||
_parentFileSystem.NotifyCloseDirectory(this);
|
||||
|
||||
_directory.Dispose();
|
||||
}
|
||||
|
||||
public FileSystemAccessor GetParent() => _parentFileSystem;
|
||||
|
||||
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)
|
||||
{
|
||||
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 IFile _file;
|
||||
private UniqueRef<IFile> _file;
|
||||
private FileSystemAccessor _parentFileSystem;
|
||||
private WriteState _writeState;
|
||||
private Result _lastResult;
|
||||
@ -30,12 +30,12 @@ namespace LibHac.Fs.Impl
|
||||
|
||||
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)
|
||||
{
|
||||
Hos = hosClient;
|
||||
|
||||
_file = Shared.Move(ref file);
|
||||
_file = new UniqueRef<IFile>(ref file);
|
||||
_parentFileSystem = parentFileSystem;
|
||||
_writeState = WriteState.None;
|
||||
_lastResult = Result.Success;
|
||||
@ -52,8 +52,7 @@ namespace LibHac.Fs.Impl
|
||||
|
||||
_parentFileSystem?.NotifyCloseFile(this);
|
||||
|
||||
IFile file = Shared.Move(ref _file);
|
||||
file?.Dispose();
|
||||
_file.Dispose();
|
||||
}
|
||||
|
||||
public OpenMode GetOpenMode() => _openMode;
|
||||
@ -77,7 +76,7 @@ namespace LibHac.Fs.Impl
|
||||
public Result ReadWithoutCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||
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,
|
||||
@ -166,7 +165,7 @@ namespace LibHac.Fs.Impl
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -182,7 +181,7 @@ namespace LibHac.Fs.Impl
|
||||
using ScopedSetter<WriteState> setter =
|
||||
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
||||
|
||||
Result rc = UpdateLastResult(_file.Flush());
|
||||
Result rc = UpdateLastResult(_file.Get.Flush());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
setter.Set(WriteState.None);
|
||||
@ -198,7 +197,7 @@ namespace LibHac.Fs.Impl
|
||||
using ScopedSetter<WriteState> setter =
|
||||
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 (_filePathHash.Data != 0)
|
||||
@ -217,13 +216,13 @@ namespace LibHac.Fs.Impl
|
||||
if (_lastResult.IsFailure())
|
||||
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,
|
||||
ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
return _file.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||
return _file.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,25 +331,21 @@ namespace LibHac.Fs.Impl
|
||||
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();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFile iFile = null;
|
||||
try
|
||||
{
|
||||
rc = _fileSystem.OpenFile(out iFile, in pathNormalized, mode);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
rc = _fileSystem.OpenFile(ref file.Ref(), in pathNormalized, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var fileAccessor = new FileAccessor(Hos, ref iFile, this, mode);
|
||||
var accessor = new FileAccessor(Hos, ref file.Ref(), this, mode);
|
||||
|
||||
using (ScopedLock.Lock(ref _openListLock))
|
||||
{
|
||||
_openFiles.AddLast(fileAccessor);
|
||||
_openFiles.AddLast(accessor);
|
||||
}
|
||||
|
||||
if (_isPathCacheAttached)
|
||||
@ -364,44 +360,30 @@ namespace LibHac.Fs.Impl
|
||||
}
|
||||
}
|
||||
|
||||
file = Shared.Move(ref fileAccessor);
|
||||
outFile.Reset(accessor);
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
iFile?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IDirectory iDirectory = null;
|
||||
try
|
||||
{
|
||||
rc = _fileSystem.OpenDirectory(out iDirectory, in pathNormalized, mode);
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
rc = _fileSystem.OpenDirectory(ref directory.Ref(), in pathNormalized, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var directoryAccessor = new DirectoryAccessor(ref iDirectory, this);
|
||||
var accessor = new DirectoryAccessor(ref directory.Ref(), this);
|
||||
|
||||
using (ScopedLock.Lock(ref _openListLock))
|
||||
{
|
||||
_openDirectories.AddLast(directoryAccessor);
|
||||
_openDirectories.AddLast(accessor);
|
||||
}
|
||||
|
||||
directory = Shared.Move(ref directoryAccessor);
|
||||
outDirectory.Reset(accessor);
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
iDirectory?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
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.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
||||
/// 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())
|
||||
return ResultFs.NullptrArgument.Log();
|
||||
|
||||
@ -214,7 +212,7 @@ namespace LibHac.Fs.Fsa
|
||||
Result rs = pathNormalized.InitializeWithNormalization(path);
|
||||
if (rs.IsFailure()) return rs;
|
||||
|
||||
return DoOpenFile(out file, in pathNormalized, mode);
|
||||
return DoOpenFile(ref file, in pathNormalized, mode);
|
||||
}
|
||||
|
||||
/// <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.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
||||
/// 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)
|
||||
{
|
||||
@ -236,28 +234,24 @@ namespace LibHac.Fs.Fsa
|
||||
return ResultFs.InvalidOpenMode.Log();
|
||||
}
|
||||
|
||||
return DoOpenFile(out file, in path, mode);
|
||||
return DoOpenFile(ref file, in path, mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IDirectory"/> instance for enumerating the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">If the operation returns successfully,
|
||||
/// An <see cref="IDirectory"/> instance for the specified directory.</param>
|
||||
/// <param name="outDirectory"></param>
|
||||
/// <param name="path">The directory's full path.</param>
|
||||
/// <param name="mode">Specifies which sub-entries should be enumerated.</param>
|
||||
/// <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>
|
||||
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 ||
|
||||
(mode & ~(OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize)) != 0)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
return ResultFs.InvalidOpenMode.Log();
|
||||
}
|
||||
|
||||
return DoOpenDirectory(out directory, in path, mode);
|
||||
return DoOpenDirectory(ref outDirectory, in path, mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -325,8 +319,9 @@ namespace LibHac.Fs.Fsa
|
||||
return ResultFs.NotImplemented.Log();
|
||||
}
|
||||
|
||||
protected abstract Result DoOpenFile(out IFile file, in Path path, OpenMode mode);
|
||||
protected abstract Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode);
|
||||
protected abstract Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode);
|
||||
protected abstract Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||
OpenDirectoryMode mode);
|
||||
protected abstract Result DoCommit();
|
||||
|
||||
protected virtual Result DoCommitProvisionally(long counter) => ResultFs.NotImplemented.Log();
|
||||
|
@ -508,27 +508,27 @@ namespace LibHac.Fs.Fsa
|
||||
fs.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
FileAccessor accessor;
|
||||
using var file = new UniqueRef<FileAccessor>();
|
||||
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
||||
{
|
||||
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();
|
||||
|
||||
fs.Impl.OutputAccessLog(rc, start, end, accessor, new U8Span(logBuffer));
|
||||
fs.Impl.OutputAccessLog(rc, start, end, file.Get, new U8Span(logBuffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = fileSystem.OpenFile(out accessor, subPath, mode);
|
||||
rc = fileSystem.OpenFile(ref file.Ref(), subPath, mode);
|
||||
}
|
||||
fs.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
handle = new FileHandle(accessor);
|
||||
handle = new FileHandle(file.Release());
|
||||
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);
|
||||
handle = new FileHandle(accessor);
|
||||
@ -565,23 +565,24 @@ namespace LibHac.Fs.Fsa
|
||||
fs.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
DirectoryAccessor accessor;
|
||||
using var accessor = new UniqueRef<DirectoryAccessor>();
|
||||
|
||||
if (fs.Impl.IsEnabledAccessLog() && fileSystem.IsEnabledAccessLog())
|
||||
{
|
||||
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();
|
||||
|
||||
fs.Impl.OutputAccessLog(rc, start, end, accessor, new U8Span(logBuffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = fileSystem.OpenDirectory(out accessor, subPath, mode);
|
||||
rc = fileSystem.OpenDirectory(ref accessor.Ref(), subPath, mode);
|
||||
}
|
||||
fs.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
handle = new DirectoryHandle(accessor);
|
||||
handle = new DirectoryHandle(accessor.Release());
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -68,25 +68,22 @@ namespace LibHac.Fs
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = new MemoryDirectory(dirNode, mode);
|
||||
outDirectory.Reset(new MemoryDirectory(dirNode, mode));
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new MemoryFile(mode, fileNode.File);
|
||||
outFile.Reset(new MemoryFile(mode, fileNode.File));
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -252,10 +252,8 @@ namespace LibHac.Fs.Impl
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -265,7 +263,7 @@ namespace LibHac.Fs.Impl
|
||||
rc = BaseFs.Target.OpenFile(out sfFile, in sfPath, (uint)mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new FileServiceObjectAdapter(sfFile);
|
||||
outFile.Reset(new FileServiceObjectAdapter(sfFile));
|
||||
return Result.Success;
|
||||
}
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -287,7 +284,7 @@ namespace LibHac.Fs.Impl
|
||||
rc = BaseFs.Target.OpenDirectory(out sfDir, in sfPath, (uint)mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = new DirectoryServiceObjectAdapter(sfDir);
|
||||
outDirectory.Reset(new DirectoryServiceObjectAdapter(sfDir));
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
|
@ -33,10 +33,12 @@ namespace LibHac.FsSrv
|
||||
if (!programInfo.AccessControl.CanCall(OperationType.OpenAccessFailureDetectionEventNotifier))
|
||||
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;
|
||||
|
||||
notifier = new ReferenceCountedDisposable<IEventNotifier>(tempNotifier);
|
||||
notifier = new ReferenceCountedDisposable<IEventNotifier>(tempNotifier.Release());
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Svc;
|
||||
@ -30,9 +31,9 @@ namespace LibHac.FsSrv
|
||||
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)
|
||||
|
@ -36,9 +36,8 @@ namespace LibHac.FsSrv
|
||||
ReferenceCountedDisposable<IFileSystem> tempFs = null;
|
||||
try
|
||||
{
|
||||
const int pathBufferLength = 0x40;
|
||||
|
||||
// Hack around error CS8350.
|
||||
const int pathBufferLength = 0x40;
|
||||
Span<byte> buffer = stackalloc byte[pathBufferLength];
|
||||
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
|
||||
Span<byte> pathBuffer = MemoryMarshal.CreateSpan(ref bufferRef, pathBufferLength);
|
||||
@ -49,11 +48,8 @@ namespace LibHac.FsSrv
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using var path = new Path();
|
||||
var sb = new U8StringBuilder(pathBuffer);
|
||||
sb.Append((byte)'/')
|
||||
.Append(CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
||||
|
||||
rc = PathFunctions.SetUpFixedPath(ref path.Ref(), pathBuffer);
|
||||
rc = PathFunctions.SetUpFixedPathSingleEntry(ref path.Ref(), pathBuffer,
|
||||
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
tempFs = Shared.Move(ref fileSystem);
|
||||
@ -66,13 +62,9 @@ namespace LibHac.FsSrv
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using var path = new Path();
|
||||
var sb = new U8StringBuilder(pathBuffer);
|
||||
sb.Append((byte)'/')
|
||||
.Append(CommonPaths.SdCardNintendoRootDirectoryName)
|
||||
.Append((byte)'/')
|
||||
.Append(CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.SdCard));
|
||||
|
||||
rc = PathFunctions.SetUpFixedPath(ref path.Ref(), pathBuffer);
|
||||
rc = PathFunctions.SetUpFixedPathDoubleEntry(ref path.Ref(), pathBuffer,
|
||||
CommonPaths.SdCardNintendoRootDirectoryName,
|
||||
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
tempFs = Shared.Move(ref fileSystem);
|
||||
|
@ -12,10 +12,12 @@ namespace LibHac.FsSrv.FsCreator
|
||||
{
|
||||
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;
|
||||
|
||||
dir.Dispose();
|
||||
directory.Reset();
|
||||
|
||||
ReferenceCountedDisposable<SubdirectoryFileSystem> subFs = null;
|
||||
try
|
||||
|
@ -1,10 +1,11 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv
|
||||
{
|
||||
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 InvalidateIndexer(SaveDataSpaceId spaceId);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Svc;
|
||||
|
||||
@ -6,7 +7,7 @@ namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
@ -17,10 +18,10 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
{
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
||||
private IFile _baseFile;
|
||||
private UniqueRef<IFile> _baseFile;
|
||||
private bool _allowAllOperations;
|
||||
|
||||
public FileInterfaceAdapter(IFile baseFile,
|
||||
public FileInterfaceAdapter(ref UniqueRef<IFile> baseFile,
|
||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
|
||||
{
|
||||
_baseFile = baseFile;
|
||||
_baseFile = new UniqueRef<IFile>(ref baseFile);
|
||||
_parentFs = Shared.Move(ref parentFileSystem);
|
||||
_allowAllOperations = allowAllOperations;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseFile?.Dispose();
|
||||
_baseFile.Dispose();
|
||||
_parentFs?.Dispose();
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace LibHac.FsSrv.Impl
|
||||
|
||||
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
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
@ -81,12 +81,12 @@ namespace LibHac.FsSrv.Impl
|
||||
using var scopedPriorityChanger =
|
||||
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()
|
||||
{
|
||||
return _baseFile.Flush();
|
||||
return _baseFile.Get.Flush();
|
||||
}
|
||||
|
||||
public Result SetSize(long size)
|
||||
@ -94,7 +94,7 @@ namespace LibHac.FsSrv.Impl
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
return _baseFile.SetSize(size);
|
||||
return _baseFile.Get.SetSize(size);
|
||||
}
|
||||
|
||||
public Result GetSize(out long size)
|
||||
@ -107,7 +107,7 @@ namespace LibHac.FsSrv.Impl
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFile.GetSize(out tmpSize);
|
||||
rc = _baseFile.Get.GetSize(out tmpSize);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
@ -129,7 +129,7 @@ namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -137,7 +137,7 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
@ -165,7 +165,7 @@ namespace LibHac.FsSrv.Impl
|
||||
Result rc = PermissionCheck((OperationId)operationId, this);
|
||||
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;
|
||||
|
||||
return Result.Success;
|
||||
@ -179,18 +179,18 @@ namespace LibHac.FsSrv.Impl
|
||||
public class DirectoryInterfaceAdapter : IDirectorySf
|
||||
{
|
||||
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)
|
||||
{
|
||||
_baseDirectory = baseDirectory;
|
||||
_baseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
|
||||
_parentFs = Shared.Move(ref parentFileSystem);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseDirectory?.Dispose();
|
||||
_baseDirectory.Dispose();
|
||||
_parentFs?.Dispose();
|
||||
}
|
||||
|
||||
@ -206,7 +206,7 @@ namespace LibHac.FsSrv.Impl
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseDirectory.Read(out numRead, entries);
|
||||
rc = _baseDirectory.Get.Read(out numRead, entries);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
@ -223,7 +223,7 @@ namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||
|
||||
Result rc = _baseDirectory.GetEntryCount(out long count);
|
||||
Result rc = _baseDirectory.Get.GetEntryCount(out long count);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entryCount = count;
|
||||
@ -496,21 +496,20 @@ namespace LibHac.FsSrv.Impl
|
||||
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;
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
UnsafeHelpers.SkipParamInit(out outFile);
|
||||
|
||||
using var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFile fileInterface = null;
|
||||
try
|
||||
{
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFileSystem.Target.OpenFile(out fileInterface, in pathNormalized, (OpenMode)mode);
|
||||
rc = _baseFileSystem.Target.OpenFile(ref file.Ref(), in pathNormalized, (OpenMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
@ -520,32 +519,26 @@ namespace LibHac.FsSrv.Impl
|
||||
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);
|
||||
var adapter = new FileInterfaceAdapter(ref file.Ref(), ref selfReference, _allowAllOperations);
|
||||
outFile = new ReferenceCountedDisposable<IFileSf>(adapter);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fileInterface?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
UnsafeHelpers.SkipParamInit(out outDirectory);
|
||||
|
||||
using var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IDirectory dirInterface = null;
|
||||
try
|
||||
{
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFileSystem.Target.OpenDirectory(out dirInterface, in pathNormalized,
|
||||
rc = _baseFileSystem.Target.OpenDirectory(ref directory.Ref(), in pathNormalized,
|
||||
(OpenDirectoryMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
@ -556,16 +549,11 @@ namespace LibHac.FsSrv.Impl
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
||||
var adapter = new DirectoryInterfaceAdapter(dirInterface, ref selfReference);
|
||||
directory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
||||
var adapter = new DirectoryInterfaceAdapter(ref directory.Ref(), ref selfReference);
|
||||
outDirectory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
dirInterface?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result Commit()
|
||||
{
|
||||
|
@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
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
|
||||
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()
|
||||
{
|
||||
BaseFile?.Dispose();
|
||||
BaseFile = null;
|
||||
|
||||
BaseFile.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return ConvertResult(BaseFile.Write(offset, source, option));
|
||||
return ConvertResult(BaseFile.Get.Write(offset, source, option));
|
||||
}
|
||||
|
||||
protected override Result DoFlush()
|
||||
{
|
||||
return ConvertResult(BaseFile.Flush());
|
||||
return ConvertResult(BaseFile.Get.Flush());
|
||||
}
|
||||
|
||||
protected override Result DoSetSize(long size)
|
||||
{
|
||||
return ConvertResult(BaseFile.SetSize(size));
|
||||
return ConvertResult(BaseFile.Get.SetSize(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,
|
||||
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);
|
||||
@ -60,29 +58,27 @@ namespace LibHac.FsSrv.Impl
|
||||
// ReSharper disable once InconsistentNaming
|
||||
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()
|
||||
{
|
||||
BaseDirectory?.Dispose();
|
||||
BaseDirectory = null;
|
||||
|
||||
BaseDirectory.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return ConvertResult(BaseDirectory.GetEntryCount(out entryCount));
|
||||
return ConvertResult(BaseDirectory.Get.GetEntryCount(out entryCount));
|
||||
}
|
||||
|
||||
protected abstract Result ConvertResult(Result result);
|
||||
@ -150,9 +146,9 @@ namespace LibHac.FsSrv.Impl
|
||||
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);
|
||||
|
||||
protected override Result DoCommit()
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Util;
|
||||
@ -25,6 +26,6 @@ namespace LibHac.FsSrv.Impl
|
||||
Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2);
|
||||
Result SetSaveDataState(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataState state);
|
||||
Result SetSaveDataRank(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataRank rank);
|
||||
Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, SaveDataSpaceId spaceId);
|
||||
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, SaveDataSpaceId spaceId);
|
||||
}
|
||||
}
|
||||
|
@ -294,15 +294,13 @@ namespace LibHac.FsSrv.Impl
|
||||
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFile contextFile = null;
|
||||
try
|
||||
{
|
||||
// Read the multi-commit context
|
||||
rc = contextFs.OpenFile(out contextFile, in contextFilePath, OpenMode.ReadWrite);
|
||||
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.Read(out _, 0, SpanHelpers.AsByteSpan(ref context), ReadOption.None);
|
||||
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
|
||||
@ -321,14 +319,14 @@ namespace LibHac.FsSrv.Impl
|
||||
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);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Iterate through all the saves to find any provisionally committed save data
|
||||
@ -357,7 +355,6 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
infoReader?.Dispose();
|
||||
}
|
||||
|
||||
@ -376,11 +373,6 @@ namespace LibHac.FsSrv.Impl
|
||||
|
||||
return recoveryResult;
|
||||
}
|
||||
finally
|
||||
{
|
||||
contextFile?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to recover a multi-commit using the context in the provided file system.
|
||||
@ -410,14 +402,14 @@ namespace LibHac.FsSrv.Impl
|
||||
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);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Iterate through all the saves to find any provisionally committed save data
|
||||
@ -446,7 +438,6 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
infoReader?.Dispose();
|
||||
}
|
||||
|
||||
@ -516,8 +507,8 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = fileSystem.Target.OpenFile(out IFile file, in contextFilePath, OpenMode.Read);
|
||||
file?.Dispose();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
rc = fileSystem.Target.OpenFile(ref file.Ref(), in contextFilePath, OpenMode.Read);
|
||||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
@ -591,12 +582,10 @@ namespace LibHac.FsSrv.Impl
|
||||
Result rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFile contextFile = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Open context file and create if it doesn't exist
|
||||
rc = _fileSystem.OpenFile(out contextFile, in contextFilePath, OpenMode.Read);
|
||||
using (var contextFile = new UniqueRef<IFile>())
|
||||
{
|
||||
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.Read);
|
||||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
@ -606,18 +595,14 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = _fileSystem.CreateFile(in contextFilePath, CommitContextFileSize);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
_context.Version = CurrentCommitContextVersion;
|
||||
@ -626,16 +611,12 @@ namespace LibHac.FsSrv.Impl
|
||||
_context.Counter = counter;
|
||||
|
||||
// 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;
|
||||
|
||||
rc = contextFile.Flush();
|
||||
rc = contextFile.Get.Flush();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
finally
|
||||
{
|
||||
contextFile?.Dispose();
|
||||
}
|
||||
|
||||
rc = _fileSystem.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
@ -650,29 +631,23 @@ namespace LibHac.FsSrv.Impl
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
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);
|
||||
using var contextFile = new UniqueRef<IFile>();
|
||||
rc = _fileSystem.OpenFile(ref contextFile.Ref(), in contextFilePath, OpenMode.ReadWrite);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
_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;
|
||||
|
||||
rc = contextFile.Flush();
|
||||
rc = contextFile.Get.Flush();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
finally
|
||||
{
|
||||
contextFile?.Dispose();
|
||||
}
|
||||
|
||||
return _fileSystem.Commit();
|
||||
}
|
||||
|
@ -8,27 +8,27 @@ namespace LibHac.FsSrv.Impl
|
||||
internal class OpenCountFileSystem : ForwardingFileSystem
|
||||
{
|
||||
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 baseFileSystem)
|
||||
{
|
||||
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
|
||||
}
|
||||
|
||||
protected OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||
public OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||
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 _mountCountSemaphore, ref mountCountSemaphore);
|
||||
_mountCountSemaphore = new UniqueRef<IUniqueLock>(ref mountCountSemaphore);
|
||||
}
|
||||
|
||||
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
|
||||
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
|
||||
ref IUniqueLock mountCountSemaphore)
|
||||
ref UniqueRef<IUniqueLock> mountCountSemaphore)
|
||||
{
|
||||
var filesystem =
|
||||
new OpenCountFileSystem(ref baseFileSystem, ref entryCountSemaphore, ref mountCountSemaphore);
|
||||
@ -47,23 +47,24 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
|
||||
// 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
|
||||
return base.DoOpenFile(out file, path, mode);
|
||||
return base.DoOpenFile(ref outFile, path, mode);
|
||||
}
|
||||
|
||||
// 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
|
||||
return base.DoOpenDirectory(out directory, path, mode);
|
||||
return base.DoOpenDirectory(ref outDirectory, path, mode);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_entryCountSemaphore?.Dispose();
|
||||
_mountCountSemaphore?.Dispose();
|
||||
_mountCountSemaphore.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ namespace LibHac.FsSrv.Impl
|
||||
/// </summary>
|
||||
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>
|
||||
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);
|
||||
}
|
||||
|
||||
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 = ConvertResult(BaseFileSystem.Target.OpenFile(out IFile tempFile, path, mode));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
Result rc = ConvertResult(BaseFileSystem.Target.OpenFile(ref file.Ref(), path, mode));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new SaveDataResultConvertFile(tempFile);
|
||||
outFile.Reset(new SaveDataResultConvertFile(ref file.Ref()));
|
||||
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 = ConvertResult(BaseFileSystem.Target.OpenDirectory(out IDirectory tempDirectory, path, mode));
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
Result rc = ConvertResult(BaseFileSystem.Target.OpenDirectory(ref directory.Ref(), path, mode));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = new SaveDataResultConvertDirectory(tempDirectory);
|
||||
outDirectory.Reset(new SaveDataResultConvertDirectory(ref directory.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -27,10 +27,11 @@ namespace LibHac.FsSrv.Impl
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
dir.Dispose();
|
||||
dir.Reset();
|
||||
|
||||
var fs = new SubdirectoryFileSystem(ref baseFileSystem);
|
||||
using (var subDirFs = new ReferenceCountedDisposable<SubdirectoryFileSystem>(fs))
|
||||
|
@ -593,12 +593,12 @@ namespace LibHac.FsSrv
|
||||
ServiceImpl.IncrementRomFsRecoveredByInvalidateCacheCount();
|
||||
}
|
||||
|
||||
private Result TryAcquireAddOnContentOpenCountSemaphore(out IUniqueLock semaphoreLock)
|
||||
private Result TryAcquireAddOnContentOpenCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Result TryAcquireRomMountCountSemaphore(out IUniqueLock semaphoreLock)
|
||||
private Result TryAcquireRomMountCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -634,16 +634,14 @@ namespace LibHac.FsSrv
|
||||
|
||||
nspPathLen += 4;
|
||||
|
||||
if (nspPathLen > FsPath.MaxLength + 1)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
Result rc = FsPath.FromSpan(out FsPath nspPath, path.Slice(0, nspPathLen));
|
||||
using var pathNsp = new Path();
|
||||
Result rc = pathNsp.InitializeWithNormalization(path, nspPathLen);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var storage = new FileStorageBasedFileSystem();
|
||||
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;
|
||||
|
||||
rc = _config.PartitionFsCreator.Create(out fileSystem, nspFileStorage.AddReference<IStorage>());
|
||||
@ -664,7 +662,11 @@ namespace LibHac.FsSrv
|
||||
// Todo: Create ref-counted storage
|
||||
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;
|
||||
|
||||
rc = _config.StorageOnNcaCreator.OpenNca(out Nca ncaTemp, ncaFileStorage);
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv.Impl;
|
||||
@ -78,9 +77,9 @@ namespace LibHac.FsSrv
|
||||
return new ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager>(adapter);
|
||||
}
|
||||
|
||||
public Result TryAcquireEntryOpenCountSemaphore(out IUniqueLock semaphore)
|
||||
public Result TryAcquireEntryOpenCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphore)
|
||||
{
|
||||
return _saveService.Target.TryAcquireSaveDataEntryOpenCountSemaphore(out semaphore);
|
||||
return _saveService.Target.TryAcquireSaveDataEntryOpenCountSemaphore(ref outSemaphore);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@ -462,7 +461,7 @@ namespace LibHac.FsSrv
|
||||
return rc;
|
||||
|
||||
// Delete the actual save data.
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
rc = _serviceImpl.DeleteSaveDataFileSystem(spaceId, saveDataId, wipeSaveFile, in saveDataRootPath);
|
||||
if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc))
|
||||
return rc;
|
||||
@ -481,23 +480,16 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
if (saveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (value.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return DeleteSaveDataFileSystemCommon(spaceId, saveDataId);
|
||||
}
|
||||
@ -518,10 +510,8 @@ namespace LibHac.FsSrv
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
try
|
||||
{
|
||||
SaveDataSpaceId actualSpaceId;
|
||||
|
||||
// Only the FS process may delete the save indexer's save data.
|
||||
@ -534,7 +524,7 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Get the actual space ID of this save.
|
||||
@ -544,28 +534,28 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
actualSpaceId = value.SpaceId;
|
||||
}
|
||||
|
||||
// Check if the caller has permission to delete this save.
|
||||
rc = accessor.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Result GetExtraData(out SaveDataExtraData data) =>
|
||||
_serviceImpl.ReadSaveDataFileSystemExtraData(out data, actualSpaceId, saveDataId, key.Type,
|
||||
_saveDataRootPath.GetPath());
|
||||
_saveDataRootPath.DangerousGetPath());
|
||||
|
||||
rc = SaveDataAccessibilityChecker.CheckDelete(in key, programInfo, GetExtraData);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Pre-delete checks successful. Put the save in the Processing state until deletion is finished.
|
||||
rc = accessor.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.Commit();
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
@ -577,21 +567,15 @@ namespace LibHac.FsSrv
|
||||
// The indexer doesn't track itself, so skip if deleting its save data.
|
||||
if (saveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
// accessor will never be null at this point
|
||||
rc = accessor!.Indexer.Delete(saveDataId);
|
||||
rc = accessor.Get.Indexer.Delete(saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.Commit();
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2)
|
||||
{
|
||||
@ -702,13 +686,14 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
ulong saveDataId = 0;
|
||||
bool creating = false;
|
||||
bool accessorInitialized = false;
|
||||
Result rc;
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
|
||||
StorageType storageFlag = DecidePossibleStorageFlag(attribute.Type, creationInfo.SpaceId);
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
|
||||
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
try
|
||||
{
|
||||
// Add the new save data to the save indexer
|
||||
@ -727,9 +712,11 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, creationInfo.SpaceId);
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), creationInfo.SpaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
accessorInitialized = true;
|
||||
|
||||
SaveDataAttribute indexerKey = attribute;
|
||||
|
||||
// Add the new value to the indexer
|
||||
@ -738,7 +725,7 @@ namespace LibHac.FsSrv
|
||||
// If a static save data ID is specified that ID is always used
|
||||
saveDataId = attribute.StaticSaveDataId;
|
||||
|
||||
rc = accessor.Indexer.PutStaticSaveDataIdIndex(in indexerKey);
|
||||
rc = accessor.Get.Indexer.PutStaticSaveDataIdIndex(in indexerKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -747,14 +734,14 @@ namespace LibHac.FsSrv
|
||||
// end up in a situation where it can't create a required system save.
|
||||
if (!SaveDataProperties.CanUseIndexerReservedArea(attribute.Type))
|
||||
{
|
||||
if (accessor.Indexer.IsRemainedReservedOnly())
|
||||
if (accessor.Get.Indexer.IsRemainedReservedOnly())
|
||||
{
|
||||
return ResultKvdb.OutOfKeyResource.Log();
|
||||
}
|
||||
}
|
||||
|
||||
// If a static save data ID is no specified we're assigned a new save ID
|
||||
rc = accessor.Indexer.Publish(out saveDataId, in indexerKey);
|
||||
rc = accessor.Get.Indexer.Publish(out saveDataId, in indexerKey);
|
||||
}
|
||||
|
||||
if (rc.IsFailure())
|
||||
@ -770,24 +757,24 @@ namespace LibHac.FsSrv
|
||||
creating = true;
|
||||
|
||||
// Set the state, space ID and size on the new save indexer entry.
|
||||
rc = accessor.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.SetSpaceId(saveDataId, ConvertToRealSpaceId(creationInfo.SpaceId));
|
||||
rc = accessor.Get.Indexer.SetSpaceId(saveDataId, ConvertToRealSpaceId(creationInfo.SpaceId));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = QuerySaveDataTotalSize(out long saveDataSize, creationInfo.Size, creationInfo.JournalSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.SetSize(saveDataId, saveDataSize);
|
||||
rc = accessor.Get.Indexer.SetSize(saveDataId, saveDataSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.Commit();
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
// After the new save was added to the save indexer, create the save data file or directory.
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
rc = _serviceImpl.CreateSaveDataFileSystem(saveDataId, in attribute, in creationInfo,
|
||||
in saveDataRootPath, in hashSalt, false);
|
||||
|
||||
@ -814,22 +801,20 @@ namespace LibHac.FsSrv
|
||||
|
||||
if (metaInfo.Type == SaveDataMetaType.Thumbnail)
|
||||
{
|
||||
rc = _serviceImpl.OpenSaveDataMeta(out IFile metaFile, saveDataId, creationInfo.SpaceId,
|
||||
using var metaFile = new UniqueRef<IFile>();
|
||||
rc = _serviceImpl.OpenSaveDataMeta(ref metaFile.Ref(), saveDataId, creationInfo.SpaceId,
|
||||
metaInfo.Type);
|
||||
|
||||
using (metaFile)
|
||||
{
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// The first 0x20 bytes of thumbnail meta files is an SHA-256 hash.
|
||||
// Zero the hash to indicate that it's currently unused.
|
||||
ReadOnlySpan<byte> metaFileHash = stackalloc byte[0x20];
|
||||
|
||||
rc = metaFile.Write(0, metaFileHash, WriteOption.Flush);
|
||||
rc = metaFile.Get.Write(0, metaFileHash, WriteOption.Flush);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (leaveUnfinalized)
|
||||
{
|
||||
@ -840,14 +825,11 @@ namespace LibHac.FsSrv
|
||||
// The indexer's save data isn't tracked, so we don't need to update its state.
|
||||
if (attribute.StaticSaveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
// accessor shouldn't ever be null, but checking makes the analyzers happy
|
||||
Abort.DoAbortUnless(accessor != null);
|
||||
|
||||
// Mark the save data as being successfully created
|
||||
rc = accessor.Indexer.SetState(saveDataId, SaveDataState.Normal);
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Normal);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.Commit();
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
@ -861,19 +843,17 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
DeleteSaveDataFileSystemCore(creationInfo.SpaceId, saveDataId, false).IgnoreResult();
|
||||
|
||||
if (accessor != null && saveDataId != SaveData.SaveIndexerId)
|
||||
if (accessorInitialized && saveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
|
||||
if (rc.IsSuccess() && value.SpaceId == creationInfo.SpaceId)
|
||||
{
|
||||
accessor.Indexer.Delete(saveDataId).IgnoreResult();
|
||||
accessor.Indexer.Commit().IgnoreResult();
|
||||
accessor.Get.Indexer.Delete(saveDataId).IgnoreResult();
|
||||
accessor.Get.Indexer.Commit().IgnoreResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,18 +863,16 @@ namespace LibHac.FsSrv
|
||||
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageType.NonGameCard);
|
||||
|
||||
Result rc = OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (accessor)
|
||||
{
|
||||
rc = accessor.Indexer.Get(out SaveDataIndexerValue value, in attribute);
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue value, in attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexer.GenerateSaveDataInfo(out info, in attribute, in value);
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize)
|
||||
{
|
||||
@ -1014,10 +992,8 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out fileSystem, out saveDataId);
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
try
|
||||
{
|
||||
ulong tempSaveDataId;
|
||||
bool isStaticSaveDataId = attribute.StaticSaveDataId != 0 && attribute.UserId == UserId.InvalidId;
|
||||
|
||||
@ -1028,10 +1004,10 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
else
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.Get(out SaveDataIndexerValue indexerValue, in attribute);
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue indexerValue, in attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (indexerValue.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
@ -1044,7 +1020,7 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
|
||||
// Open the save data using its ID
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
Result saveFsResult = _serviceImpl.OpenSaveDataFileSystem(out fileSystem, spaceId, tempSaveDataId,
|
||||
in saveDataRootPath, openReadOnly, attribute.Type, cacheExtraData);
|
||||
|
||||
@ -1082,11 +1058,11 @@ namespace LibHac.FsSrv
|
||||
if (isStaticSaveDataId)
|
||||
{
|
||||
// The accessor won't be open yet if the save has a static ID
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Check the space ID of the save data
|
||||
rc = accessor.Indexer.Get(out SaveDataIndexerValue value, in key);
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue value, in key);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (value.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
@ -1094,24 +1070,17 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
|
||||
// Remove the indexer entry. Nintendo ignores these results
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
accessor.Indexer.Delete(tempSaveDataId).IgnoreResult();
|
||||
accessor.Indexer.Commit().IgnoreResult();
|
||||
accessor.Get.Indexer.Delete(tempSaveDataId).IgnoreResult();
|
||||
accessor.Get.Indexer.Commit().IgnoreResult();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Result OpenUserSaveDataFileSystemCore(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
SaveDataSpaceId spaceId, in SaveDataAttribute attribute, ProgramInfo programInfo, bool openReadOnly)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out fileSystem);
|
||||
IUniqueLock mountCountSemaphore = null;
|
||||
ReferenceCountedDisposable<IFileSystem> tempFileSystem = null;
|
||||
ReferenceCountedDisposable<SaveDataFileSystemService> saveService = null;
|
||||
ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> openEntryCountAdapter = null;
|
||||
@ -1122,10 +1091,11 @@ namespace LibHac.FsSrv
|
||||
try
|
||||
{
|
||||
// Try grabbing the mount count semaphore
|
||||
Result rc = TryAcquireSaveDataMountCountSemaphore(out mountCountSemaphore);
|
||||
using var mountCountSemaphore = new UniqueRef<IUniqueLock>();
|
||||
Result rc = TryAcquireSaveDataMountCountSemaphore(ref mountCountSemaphore.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
bool useAsyncFileSystem = !_serviceImpl.IsAllowedDirectorySaveData(spaceId, in saveDataRootPath);
|
||||
|
||||
// Open the file system
|
||||
@ -1138,7 +1108,7 @@ namespace LibHac.FsSrv
|
||||
|
||||
Result ReadExtraData(out SaveDataExtraData data)
|
||||
{
|
||||
Path savePath = _saveDataRootPath.GetPath();
|
||||
Path savePath = _saveDataRootPath.DangerousGetPath();
|
||||
return _serviceImpl.ReadSaveDataFileSystemExtraData(out data, spaceId, saveDataId, type,
|
||||
in savePath);
|
||||
}
|
||||
@ -1159,7 +1129,7 @@ namespace LibHac.FsSrv
|
||||
openEntryCountAdapter = SaveDataOpenCountAdapter.CreateShared(ref saveService);
|
||||
|
||||
tempFileSystem = OpenCountFileSystem.CreateShared(ref tempFileSystem, ref openEntryCountAdapter,
|
||||
ref mountCountSemaphore);
|
||||
ref mountCountSemaphore.Ref());
|
||||
|
||||
var pathFlags = new PathFlags();
|
||||
pathFlags.AllowBackslash();
|
||||
@ -1168,7 +1138,6 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
finally
|
||||
{
|
||||
mountCountSemaphore?.Dispose();
|
||||
tempFileSystem?.Dispose();
|
||||
saveService?.Dispose();
|
||||
openEntryCountAdapter?.Dispose();
|
||||
@ -1238,7 +1207,7 @@ namespace LibHac.FsSrv
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
bool useAsyncFileSystem = !_serviceImpl.IsAllowedDirectorySaveData(spaceId, in saveDataRootPath);
|
||||
|
||||
ReferenceCountedDisposable<IFileSystem> tempFileSystem = null;
|
||||
@ -1257,7 +1226,7 @@ namespace LibHac.FsSrv
|
||||
|
||||
Result ReadExtraData(out SaveDataExtraData data) =>
|
||||
_serviceImpl.ReadSaveDataFileSystemExtraData(out data, spaceId, saveDataId, type,
|
||||
_saveDataRootPath.GetPath());
|
||||
_saveDataRootPath.DangerousGetPath());
|
||||
|
||||
// Check if we have permissions to open this save data
|
||||
rc = SaveDataAccessibilityChecker.CheckOpen(in attribute, programInfo, ReadExtraData);
|
||||
@ -1290,32 +1259,25 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
// Nintendo used this parameter in older FS versions, but never removed it.
|
||||
// Nintendo used isTemporarySaveData in older FS versions, but never removed the parameter.
|
||||
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId, bool isTemporarySaveData)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out extraData);
|
||||
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageType.NonGameCard);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
return _serviceImpl.ReadSaveDataFileSystemExtraData(out extraData, spaceId, saveDataId, key.Type,
|
||||
in saveDataRootPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId, in SaveDataExtraData extraDataMask)
|
||||
@ -1332,63 +1294,51 @@ namespace LibHac.FsSrv
|
||||
|
||||
if (spaceId == SaveDataSpaceId.BisAuto)
|
||||
{
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
if (IsStaticSaveDataIdValueRange(saveDataId))
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.System);
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.User);
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
resolvedSpaceId = value.SpaceId;
|
||||
|
||||
rc = accessor.Indexer.GetKey(out key, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetKey(out key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
resolvedSpaceId = value.SpaceId;
|
||||
|
||||
rc = accessor.Indexer.GetKey(out key, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetKey(out key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Result ReadExtraData(out SaveDataExtraData data) => _serviceImpl.ReadSaveDataFileSystemExtraData(out data,
|
||||
resolvedSpaceId, saveDataId, key.Type, _saveDataRootPath.GetPath());
|
||||
resolvedSpaceId, saveDataId, key.Type, _saveDataRootPath.DangerousGetPath());
|
||||
|
||||
rc = SaveDataAccessibilityChecker.CheckReadExtraData(in key, in extraDataMask, programInfo,
|
||||
ReadExtraData);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
rc = _serviceImpl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData tempExtraData, resolvedSpaceId,
|
||||
saveDataId, key.Type, in saveDataRootPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
@ -1490,7 +1440,7 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageType.NonGameCard);
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
return _serviceImpl.WriteSaveDataFileSystemExtraData(spaceId, saveDataId, in extraData, in saveDataRootPath,
|
||||
saveType, updateTimeStamp);
|
||||
}
|
||||
@ -1503,23 +1453,22 @@ namespace LibHac.FsSrv
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Result ReadExtraData(out SaveDataExtraData data) => _serviceImpl.ReadSaveDataFileSystemExtraData(out data,
|
||||
spaceId, saveDataId, key.Type, _saveDataRootPath.GetPath());
|
||||
spaceId, saveDataId, key.Type, _saveDataRootPath.DangerousGetPath());
|
||||
|
||||
rc = SaveDataAccessibilityChecker.CheckWriteExtraData(in key, in extraDataMask, programInfo,
|
||||
ReadExtraData);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
rc = _serviceImpl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraDataModify, spaceId,
|
||||
saveDataId, key.Type, in saveDataRootPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
@ -1529,11 +1478,6 @@ namespace LibHac.FsSrv
|
||||
return _serviceImpl.WriteSaveDataFileSystemExtraData(spaceId, saveDataId, in extraDataModify,
|
||||
in saveDataRootPath, key.Type, false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, InBuffer extraData)
|
||||
{
|
||||
@ -1601,15 +1545,16 @@ namespace LibHac.FsSrv
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
}
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.System);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
infoReader = reader.AddReference<ISaveDataInfoReader>();
|
||||
@ -1617,7 +1562,6 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
reader?.Dispose();
|
||||
}
|
||||
}
|
||||
@ -1635,15 +1579,16 @@ namespace LibHac.FsSrv
|
||||
rc = CheckOpenSaveDataInfoReaderAccessControl(programInfo, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var infoFilter = new SaveDataInfoFilter(ConvertToRealSpaceId(spaceId), default, default, default,
|
||||
@ -1656,7 +1601,6 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
reader?.Dispose();
|
||||
}
|
||||
}
|
||||
@ -1677,15 +1621,16 @@ namespace LibHac.FsSrv
|
||||
rc = CheckOpenSaveDataInfoReaderAccessControl(programInfo, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.System);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var infoFilter = new SaveDataInfoFilter(spaceId, in filter);
|
||||
@ -1697,7 +1642,6 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
reader?.Dispose();
|
||||
}
|
||||
}
|
||||
@ -1707,15 +1651,16 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out count, out info);
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (var filterReader = new SaveDataInfoFilterReader(reader, in infoFilter))
|
||||
@ -1725,7 +1670,6 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
reader?.Dispose();
|
||||
}
|
||||
}
|
||||
@ -1836,15 +1780,16 @@ namespace LibHac.FsSrv
|
||||
if (spaceId != SaveDataSpaceId.SdCache && spaceId != SaveDataSpaceId.User)
|
||||
return ResultFs.InvalidSaveDataSpaceId.Log();
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
ReferenceCountedDisposable<SaveDataInfoReaderImpl> reader = null;
|
||||
SaveDataInfoFilterReader filterReader = null;
|
||||
try
|
||||
{
|
||||
rc = OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
||||
|
||||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out reader);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ProgramId resolvedProgramId = ResolveDefaultSaveDataReferenceProgramId(programInfo.ProgramId);
|
||||
@ -1853,16 +1798,14 @@ namespace LibHac.FsSrv
|
||||
SaveDataType.Cache, userId: default, saveDataId: default, index: default,
|
||||
(int)SaveDataRank.Primary);
|
||||
|
||||
filterReader = new SaveDataInfoFilterReader(reader, in filter);
|
||||
filterReader.Reset(new SaveDataInfoFilterReader(reader, in filter));
|
||||
|
||||
infoReader = new ReferenceCountedDisposable<ISaveDataInfoReader>(Shared.Move(ref filterReader));
|
||||
infoReader = new ReferenceCountedDisposable<ISaveDataInfoReader>(filterReader.Release());
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
reader?.Dispose();
|
||||
filterReader?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1980,7 +1923,7 @@ namespace LibHac.FsSrv
|
||||
Result rc = FindCacheStorage(out SaveDataInfo saveInfo, out SaveDataSpaceId spaceId, index);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path saveDataRootPath = _saveDataRootPath.GetPath();
|
||||
Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
rc = _serviceImpl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, spaceId,
|
||||
saveInfo.SaveDataId, saveInfo.Type, in saveDataRootPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
@ -2057,19 +2000,12 @@ namespace LibHac.FsSrv
|
||||
public Result CleanUpSaveData()
|
||||
{
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageType.Bis);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.System);
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return CleanUpSaveData(accessor);
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
return CleanUpSaveData(accessor.Get);
|
||||
}
|
||||
|
||||
private Result CleanUpSaveData(SaveDataIndexerAccessor accessor)
|
||||
@ -2081,19 +2017,12 @@ namespace LibHac.FsSrv
|
||||
public Result CompleteSaveDataExtension()
|
||||
{
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(StorageType.Bis);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, SaveDataSpaceId.System);
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return CompleteSaveDataExtension(accessor);
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
return CompleteSaveDataExtension(accessor.Get);
|
||||
}
|
||||
|
||||
private Result CompleteSaveDataExtension(SaveDataIndexerAccessor accessor)
|
||||
@ -2215,51 +2144,41 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
}
|
||||
|
||||
private Result TryAcquireSaveDataEntryOpenCountSemaphore(out IUniqueLock semaphoreLock)
|
||||
private Result TryAcquireSaveDataEntryOpenCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out semaphoreLock);
|
||||
|
||||
ReferenceCountedDisposable<SaveDataFileSystemService> saveService = null;
|
||||
IUniqueLock uniqueLock = null;
|
||||
try
|
||||
{
|
||||
saveService = _selfReference.AddReference();
|
||||
|
||||
Result rc = Utility12.MakeUniqueLockWithPin(out uniqueLock, _openEntryCountSemaphore,
|
||||
Result rc = Utility12.MakeUniqueLockWithPin(ref outSemaphoreLock, _openEntryCountSemaphore,
|
||||
ref saveService);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Shared.Move(out semaphoreLock, ref uniqueLock);
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
saveService?.Dispose();
|
||||
uniqueLock?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Result TryAcquireSaveDataMountCountSemaphore(out IUniqueLock semaphoreLock)
|
||||
private Result TryAcquireSaveDataMountCountSemaphore(ref UniqueRef<IUniqueLock> outSemaphoreLock)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out semaphoreLock);
|
||||
|
||||
ReferenceCountedDisposable<SaveDataFileSystemService> saveService = null;
|
||||
IUniqueLock uniqueLock = null;
|
||||
try
|
||||
{
|
||||
saveService = _selfReference.AddReference();
|
||||
|
||||
Result rc = Utility12.MakeUniqueLockWithPin(out uniqueLock, _saveDataMountCountSemaphore,
|
||||
Result rc = Utility12.MakeUniqueLockWithPin(ref outSemaphoreLock, _saveDataMountCountSemaphore,
|
||||
ref saveService);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Shared.Move(out semaphoreLock, ref uniqueLock);
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
saveService?.Dispose();
|
||||
uniqueLock?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2286,14 +2205,11 @@ namespace LibHac.FsSrv
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, SaveDataSpaceId spaceId)
|
||||
private Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor,
|
||||
SaveDataSpaceId spaceId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out accessor);
|
||||
|
||||
SaveDataIndexerAccessor accessorTemp = null;
|
||||
try
|
||||
{
|
||||
Result rc = _serviceImpl.OpenSaveDataIndexerAccessor(out accessorTemp, out bool neededInit, spaceId);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
Result rc = _serviceImpl.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out bool neededInit, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (neededInit)
|
||||
@ -2302,14 +2218,9 @@ namespace LibHac.FsSrv
|
||||
// nn::fssrv::SaveDataFileSystemService::CompleteSaveDataExtensionCore
|
||||
}
|
||||
|
||||
Shared.Move(out accessor, ref accessorTemp);
|
||||
outAccessor.Set(ref accessor.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessorTemp?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Result GetProgramInfo(out ProgramInfo programInfo)
|
||||
{
|
||||
@ -2405,10 +2316,10 @@ namespace LibHac.FsSrv
|
||||
return OpenSaveDataInternalStorageFileSystemCore(out fileSystem, spaceId, saveDataId, useSecondMacKey);
|
||||
}
|
||||
|
||||
Result ISaveDataTransferCoreInterface.OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor,
|
||||
SaveDataSpaceId spaceId)
|
||||
Result ISaveDataTransferCoreInterface.OpenSaveDataIndexerAccessor(
|
||||
ref UniqueRef<SaveDataIndexerAccessor> outAccessor, SaveDataSpaceId spaceId)
|
||||
{
|
||||
return OpenSaveDataIndexerAccessor(out accessor, spaceId);
|
||||
return OpenSaveDataIndexerAccessor(ref outAccessor, spaceId);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -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)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out metaFile);
|
||||
|
||||
ReferenceCountedDisposable<IFileSystem> metaDirFs = null;
|
||||
try
|
||||
{
|
||||
@ -365,7 +363,7 @@ namespace LibHac.FsSrv
|
||||
(uint)metaType);
|
||||
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
|
||||
{
|
||||
@ -875,25 +873,19 @@ namespace LibHac.FsSrv
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out count);
|
||||
|
||||
SaveDataIndexerAccessor accessor = null;
|
||||
try
|
||||
{
|
||||
Result rc = OpenSaveDataIndexerAccessor(out accessor, out bool _, SaveDataSpaceId.User);
|
||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||
|
||||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), out bool _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
count = accessor.Indexer.GetIndexCount();
|
||||
count = accessor.Get.Indexer.GetIndexCount();
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
accessor?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit,
|
||||
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool neededInit,
|
||||
SaveDataSpaceId spaceId)
|
||||
{
|
||||
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(out accessor, out neededInit, spaceId);
|
||||
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(ref outAccessor, out neededInit, spaceId);
|
||||
}
|
||||
|
||||
public void ResetTemporaryStorageIndexer()
|
||||
|
@ -49,13 +49,13 @@ namespace LibHac.FsSrv
|
||||
/// The returned <see cref="SaveDataIndexerAccessor"/> will have exclusive access to the requested indexer.
|
||||
/// The accessor must be disposed after use.
|
||||
/// </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"/>
|
||||
/// if the indexer needed to be initialized.</param>
|
||||
/// <param name="spaceId">The <see cref="SaveDataSpaceId"/> of the indexer to open.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit,
|
||||
SaveDataSpaceId spaceId)
|
||||
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor,
|
||||
out bool neededInit, SaveDataSpaceId spaceId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out neededInit);
|
||||
|
||||
@ -145,12 +145,12 @@ namespace LibHac.FsSrv
|
||||
break;
|
||||
|
||||
default:
|
||||
accessor = default;
|
||||
outAccessor = default;
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
|
||||
|
||||
accessor = new SaveDataIndexerAccessor(indexer, ref indexerLock);
|
||||
outAccessor.Reset(new SaveDataIndexerAccessor(indexer, ref indexerLock));
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
@ -68,10 +69,10 @@ namespace LibHac.FsSrv
|
||||
_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)
|
||||
{
|
||||
Result rc = Initialize(ref baseFileSystem, path, mode);
|
||||
Result rc = Initialize(ref baseFileSystem, in path, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return SetOpenType(type);
|
||||
@ -328,12 +329,17 @@ namespace LibHac.FsSrv
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId,
|
||||
OpenMode mode, Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
|
||||
{
|
||||
Result rc;
|
||||
UnsafeHelpers.SkipParamInit(out saveDataStorage);
|
||||
|
||||
Span<byte> saveImageName = stackalloc byte[0x30];
|
||||
var sb = new U8StringBuilder(saveImageName);
|
||||
sb.Append((byte)'/').AppendFormat(saveDataId, 'x', 16);
|
||||
// Hack around error CS8350.
|
||||
const int bufferLength = 0x12;
|
||||
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 (!type.HasValue)
|
||||
@ -344,7 +350,7 @@ namespace LibHac.FsSrv
|
||||
fileStorage =
|
||||
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;
|
||||
|
||||
saveDataStorage = fileStorage.AddReference<IStorage>();
|
||||
@ -375,7 +381,7 @@ namespace LibHac.FsSrv
|
||||
new ReferenceCountedDisposable<SaveDataOpenTypeSetFileStorage>(
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
|
@ -17,8 +17,8 @@ namespace LibHac.FsSrv.Sf
|
||||
Result RenameFile(in Path currentPath, in Path newPath);
|
||||
Result RenameDirectory(in Path currentPath, in Path newPath);
|
||||
Result GetEntryType(out uint entryType, in Path path);
|
||||
Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in Path path, uint mode);
|
||||
Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in Path path, uint mode);
|
||||
Result OpenFile(out ReferenceCountedDisposable<IFileSf> outFile, in Path path, uint mode);
|
||||
Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> outDirectory, in Path path, uint mode);
|
||||
Result Commit();
|
||||
Result GetFreeSpaceSize(out long freeSpace, in Path path);
|
||||
Result GetTotalSpaceSize(out long totalSpace, in Path path);
|
||||
|
@ -8,23 +8,29 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
public class AesXtsDirectory : IDirectory
|
||||
{
|
||||
private U8String Path { get; }
|
||||
private OpenDirectoryMode Mode { get; }
|
||||
private U8String _path;
|
||||
private OpenDirectoryMode _mode;
|
||||
|
||||
private IFileSystem BaseFileSystem { get; }
|
||||
private IDirectory BaseDirectory { get; }
|
||||
private IFileSystem _baseFileSystem;
|
||||
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;
|
||||
BaseDirectory = baseDir;
|
||||
Mode = mode;
|
||||
Path = path;
|
||||
_baseFileSystem = baseFs;
|
||||
_baseDirectory = new UniqueRef<IDirectory>(ref baseDir);
|
||||
_mode = mode;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_baseDirectory.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < entriesRead; i++)
|
||||
@ -33,14 +39,14 @@ namespace LibHac.FsSystem
|
||||
|
||||
if (entry.Type == DirectoryEntryType.File)
|
||||
{
|
||||
if (Mode.HasFlag(OpenDirectoryMode.NoFileSize))
|
||||
if (_mode.HasFlag(OpenDirectoryMode.NoFileSize))
|
||||
{
|
||||
entry.Size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
return BaseDirectory.GetEntryCount(out entryCount);
|
||||
return _baseDirectory.Get.GetEntryCount(out entryCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -66,25 +72,22 @@ namespace LibHac.FsSystem
|
||||
// Todo: Remove try/catch when more code uses Result
|
||||
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;
|
||||
|
||||
using (file)
|
||||
{
|
||||
uint magic = 0;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 0;
|
||||
|
@ -8,7 +8,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
public class AesXtsFile : IFile
|
||||
{
|
||||
private IFile BaseFile { get; }
|
||||
private UniqueRef<IFile> BaseFile { get; }
|
||||
private U8String Path { get; }
|
||||
private byte[] KekSeed { get; }
|
||||
private byte[] VerificationKey { get; }
|
||||
@ -20,18 +20,18 @@ namespace LibHac.FsSystem
|
||||
|
||||
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;
|
||||
BaseFile = baseFile;
|
||||
BaseFile = new UniqueRef<IFile>(ref baseFile);
|
||||
Path = path;
|
||||
KekSeed = kekSeed.ToArray();
|
||||
VerificationKey = verificationKey.ToArray();
|
||||
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))
|
||||
{
|
||||
@ -43,7 +43,7 @@ namespace LibHac.FsSystem
|
||||
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);
|
||||
encStorage.SetResizable(true);
|
||||
|
||||
@ -116,7 +116,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
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;
|
||||
|
||||
return BaseStorage.SetSize(Alignment.AlignUp(size, 0x10));
|
||||
@ -126,7 +126,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
BaseStorage.Flush();
|
||||
BaseStorage.Dispose();
|
||||
BaseFile?.Dispose();
|
||||
BaseFile.Dispose();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
@ -66,14 +66,12 @@ namespace LibHac.FsSystem
|
||||
|
||||
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;
|
||||
|
||||
using (baseFile)
|
||||
{
|
||||
rc = baseFile.Write(0, header.ToBytes(false));
|
||||
rc = baseFile.Get.Write(0, header.ToBytes(false));
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -98,28 +96,27 @@ namespace LibHac.FsSystem
|
||||
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);
|
||||
|
||||
Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode);
|
||||
using var baseDir = new UniqueRef<IDirectory>();
|
||||
Result rc = BaseFileSystem.OpenDirectory(ref baseDir.Ref(), path, mode);
|
||||
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;
|
||||
}
|
||||
|
||||
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 = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read);
|
||||
using var baseFile = new UniqueRef<IFile>();
|
||||
Result rc = BaseFileSystem.OpenFile(ref baseFile.Ref(), path, mode | OpenMode.Read);
|
||||
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);
|
||||
|
||||
file = xtsFile;
|
||||
outFile.Reset(xtsFile);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
@ -265,16 +262,14 @@ namespace LibHac.FsSystem
|
||||
|
||||
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;
|
||||
|
||||
using (file)
|
||||
{
|
||||
header = new AesXtsFileHeader(file);
|
||||
header = new AesXtsFileHeader(file.Get);
|
||||
|
||||
return header.TryDecryptHeader(keyPath, KekSource, ValidationKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteXtsHeader(AesXtsFileHeader header, string filePath, string keyPath)
|
||||
{
|
||||
@ -283,12 +278,10 @@ namespace LibHac.FsSystem
|
||||
|
||||
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.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure();
|
||||
}
|
||||
file.Get.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
|
||||
@ -51,12 +52,13 @@ namespace LibHac.FsSystem
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -218,10 +218,11 @@ namespace LibHac.FsSystem
|
||||
CreateFileOptions.None);
|
||||
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;
|
||||
|
||||
_files.Add(newInternalFile);
|
||||
_files.Add(newInternalFile.Release());
|
||||
|
||||
rc = internalFilePath.RemoveChild();
|
||||
if (rc.IsFailure()) return rc;
|
||||
@ -375,16 +376,16 @@ namespace LibHac.FsSystem
|
||||
private class ConcatenationDirectory : IDirectory
|
||||
{
|
||||
private OpenDirectoryMode _mode;
|
||||
private IDirectory _baseDirectory;
|
||||
private UniqueRef<IDirectory> _baseDirectory;
|
||||
private Path.Stored _path;
|
||||
private IFileSystem _baseFileSystem;
|
||||
private ConcatenationFileSystem _concatenationFileSystem;
|
||||
|
||||
public ConcatenationDirectory(OpenDirectoryMode mode, IDirectory baseDirectory,
|
||||
public ConcatenationDirectory(OpenDirectoryMode mode, ref UniqueRef<IDirectory> baseDirectory,
|
||||
ConcatenationFileSystem concatFileSystem, IFileSystem baseFileSystem)
|
||||
{
|
||||
_mode = mode;
|
||||
_baseDirectory = baseDirectory;
|
||||
_baseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
|
||||
_baseFileSystem = baseFileSystem;
|
||||
_concatenationFileSystem = concatFileSystem;
|
||||
}
|
||||
@ -414,7 +415,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
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 (readCount == 0)
|
||||
@ -454,13 +455,11 @@ namespace LibHac.FsSystem
|
||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||
|
||||
Unsafe.SkipInit(out DirectoryEntry entry);
|
||||
IDirectory directory = null;
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
|
||||
try
|
||||
{
|
||||
Path path = _path.GetPath();
|
||||
Path path = _path.DangerousGetPath();
|
||||
|
||||
Result rc = _baseFileSystem.OpenDirectory(out directory, in path,
|
||||
Result rc = _baseFileSystem.OpenDirectory(ref directory.Ref(), in path,
|
||||
OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -468,7 +467,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
while (true)
|
||||
{
|
||||
directory.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
||||
directory.Get.Read(out long readCount, SpanHelpers.AsSpan(ref entry));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (readCount == 0)
|
||||
@ -481,11 +480,6 @@ namespace LibHac.FsSystem
|
||||
entryCount = entryCountTotal;
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
directory?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsReadTarget(in DirectoryEntry entry)
|
||||
{
|
||||
@ -642,19 +636,16 @@ namespace LibHac.FsSystem
|
||||
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))
|
||||
{
|
||||
return _baseFileSystem.OpenFile(out file, in path, mode);
|
||||
return _baseFileSystem.OpenFile(ref outFile, in path, mode);
|
||||
}
|
||||
|
||||
Result rc = GetInternalFileCount(out int fileCount, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ConcatenationFile concatFile = null;
|
||||
var internalFiles = new List<IFile>(fileCount);
|
||||
|
||||
using var filePath = new Path();
|
||||
@ -668,27 +659,27 @@ namespace LibHac.FsSystem
|
||||
rc = AppendInternalFilePath(ref filePath.Ref(), i);
|
||||
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;
|
||||
|
||||
internalFiles.Add(internalFile);
|
||||
internalFiles.Add(internalFile.Release());
|
||||
|
||||
rc = filePath.RemoveChild();
|
||||
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;
|
||||
|
||||
file = Shared.Move(ref concatFile);
|
||||
outFile.Set(ref concatFile.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
concatFile?.Dispose();
|
||||
|
||||
if (internalFiles is not null)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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;
|
||||
|
||||
var concatDirectory = new ConcatenationDirectory(mode, baseDirectory, this, _baseFileSystem);
|
||||
rc = concatDirectory.Initialize(in path);
|
||||
using var concatDirectory = new UniqueRef<ConcatenationDirectory>(
|
||||
new ConcatenationDirectory(mode, ref baseDirectory.Ref(), this, _baseFileSystem));
|
||||
rc = concatDirectory.Get.Initialize(in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = concatDirectory;
|
||||
outDirectory.Set(ref concatDirectory.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,9 @@ namespace LibHac.FsSystem
|
||||
|
||||
private FileSystemClient _fsClient;
|
||||
private IFileSystem _baseFs;
|
||||
|
||||
private SdkMutexType _mutex;
|
||||
private UniqueRef<IFileSystem> _uniqueBaseFs;
|
||||
|
||||
// Todo: Unique file system for disposal
|
||||
private int _openWritableFileCount;
|
||||
private bool _isJournalingSupported;
|
||||
private bool _isMultiCommitSupported;
|
||||
@ -57,24 +56,24 @@ namespace LibHac.FsSystem
|
||||
private ulong _saveDataId;
|
||||
|
||||
// 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 IFile _baseFile;
|
||||
private UniqueRef<IFile> _baseFile;
|
||||
private DirectorySaveDataFileSystem _parentFs;
|
||||
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;
|
||||
_mode = mode;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_baseFile?.Dispose();
|
||||
_baseFile.Dispose();
|
||||
|
||||
if (_mode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
@ -88,63 +87,36 @@ namespace LibHac.FsSystem
|
||||
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination,
|
||||
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)
|
||||
{
|
||||
return _baseFile.Write(offset, source, in option);
|
||||
return _baseFile.Get.Write(offset, source, in option);
|
||||
}
|
||||
|
||||
protected override Result DoFlush()
|
||||
{
|
||||
return _baseFile.Flush();
|
||||
return _baseFile.Get.Flush();
|
||||
}
|
||||
|
||||
protected override Result DoGetSize(out long size)
|
||||
{
|
||||
return _baseFile.GetSize(out size);
|
||||
return _baseFile.Get.GetSize(out 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,
|
||||
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,
|
||||
FileSystemClient fsClient)
|
||||
{
|
||||
@ -162,6 +134,17 @@ namespace LibHac.FsSystem
|
||||
_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>
|
||||
/// Create an uninitialized <see cref="DirectorySaveDataFileSystem"/>.
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
_lockFile?.Dispose();
|
||||
_lockFile = null;
|
||||
_lockFile.Dispose();
|
||||
|
||||
_cacheObserver?.Unregister(_spaceId, _saveDataId);
|
||||
_baseFs?.Dispose();
|
||||
_uniqueBaseFs.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
@ -328,14 +326,14 @@ namespace LibHac.FsSystem
|
||||
private Result GetFileSystemLock()
|
||||
{
|
||||
// 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;
|
||||
|
||||
using var pathLockFile = new Path();
|
||||
Result rc = PathFunctions.SetUpFixedPath(ref pathLockFile.Ref(), LockFileName);
|
||||
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())
|
||||
{
|
||||
@ -344,7 +342,7 @@ namespace LibHac.FsSystem
|
||||
rc = _baseFs.CreateFile(in pathLockFile, 0);
|
||||
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;
|
||||
}
|
||||
else
|
||||
@ -512,40 +510,39 @@ namespace LibHac.FsSystem
|
||||
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();
|
||||
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
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;
|
||||
|
||||
file = new DirectorySaveDataFile(baseFile, this, mode);
|
||||
using var file = new UniqueRef<IFile>(new DirectorySaveDataFile(ref baseFile.Ref(), this, mode));
|
||||
|
||||
if (mode.HasFlag(OpenMode.Write))
|
||||
{
|
||||
_openWritableFileCount++;
|
||||
}
|
||||
|
||||
outFile.Set(ref file.Ref());
|
||||
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();
|
||||
Result rc = ResolvePath(ref fullPath.Ref(), in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
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;
|
||||
|
||||
return Result.Success;
|
||||
@ -704,8 +701,10 @@ namespace LibHac.FsSystem
|
||||
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);
|
||||
|
||||
_openWritableFileCount--;
|
||||
@ -811,47 +810,40 @@ namespace LibHac.FsSystem
|
||||
|
||||
private Result EnsureExtraDataSize(in Path path)
|
||||
{
|
||||
IFile file = null;
|
||||
try
|
||||
{
|
||||
Result rc = _baseFs.OpenFile(out file, in path, OpenMode.ReadWrite);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
Result rc = _baseFs.OpenFile(ref file.Ref(), 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 (fileSize == Unsafe.SizeOf<SaveDataExtraData>())
|
||||
return Result.Success;
|
||||
|
||||
return file.SetSize(Unsafe.SizeOf<SaveDataExtraData>());
|
||||
}
|
||||
finally
|
||||
{
|
||||
file?.Dispose();
|
||||
}
|
||||
return file.Get.SetSize(Unsafe.SizeOf<SaveDataExtraData>());
|
||||
}
|
||||
|
||||
private Result SynchronizeExtraData(in Path destPath, in Path sourcePath)
|
||||
{
|
||||
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>())
|
||||
{
|
||||
Result rc = _baseFs.OpenFile(ref sourceFile.Ref(), in sourcePath, OpenMode.Read);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (sourceFile)
|
||||
{
|
||||
rc = sourceFile.Read(out long bytesRead, 0, workBuffer);
|
||||
rc = sourceFile.Get.Read(out long bytesRead, 0, workBuffer);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
||||
}
|
||||
|
||||
rc = _baseFs.OpenFile(out IFile destFile, in destPath, OpenMode.Write);
|
||||
using (var destFile = new UniqueRef<IFile>())
|
||||
{
|
||||
Result rc = _baseFs.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (destFile)
|
||||
{
|
||||
rc = destFile.Write(0, workBuffer, WriteOption.Flush);
|
||||
rc = destFile.Get.Write(0, workBuffer, WriteOption.Flush);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
@ -926,14 +918,12 @@ namespace LibHac.FsSystem
|
||||
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
||||
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;
|
||||
|
||||
using (file)
|
||||
{
|
||||
rc = file.Write(0, SpanHelpers.AsReadOnlyByteSpan(in extraData), WriteOption.Flush);
|
||||
rc = file.Get.Write(0, SpanHelpers.AsReadOnlyByteSpan(in extraData), WriteOption.Flush);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -1002,16 +992,14 @@ namespace LibHac.FsSystem
|
||||
Result rc = GetExtraDataPath(ref pathExtraData.Ref());
|
||||
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;
|
||||
|
||||
using (file)
|
||||
{
|
||||
rc = file.Read(out long bytesRead, 0, SpanHelpers.AsByteSpan(ref extraData));
|
||||
rc = file.Get.Read(out long bytesRead, 0, SpanHelpers.AsByteSpan(ref extraData));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Assert.SdkEqual(bytesRead, Unsafe.SizeOf<SaveDataExtraData>());
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -95,22 +95,20 @@ namespace LibHac.FsSystem
|
||||
logger?.LogMessage(sourcePath.ToString());
|
||||
|
||||
// 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;
|
||||
|
||||
using (sourceFile)
|
||||
{
|
||||
rc = sourceFile.GetSize(out long fileSize);
|
||||
rc = sourceFile.Get.GetSize(out long fileSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = CreateOrOverwriteFile(destFileSystem, in destPath, fileSize, option);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = destFileSystem.OpenFile(out IFile destFile, in destPath, OpenMode.Write);
|
||||
using var destFile = new UniqueRef<IFile>();
|
||||
rc = destFileSystem.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (destFile)
|
||||
{
|
||||
// Read/Write file in work buffer sized chunks.
|
||||
long remaining = fileSize;
|
||||
long offset = 0;
|
||||
@ -119,10 +117,10 @@ namespace LibHac.FsSystem
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
rc = sourceFile.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
||||
rc = sourceFile.Get.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = destFile.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||
rc = destFile.Get.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
remaining -= bytesRead;
|
||||
@ -130,8 +128,6 @@ namespace LibHac.FsSystem
|
||||
|
||||
logger?.ReportAdd(bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -166,13 +162,14 @@ namespace LibHac.FsSystem
|
||||
var pathNormalized = new Path();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
DirectoryEntryEx entry = GetDirectoryEntryEx(ref dirEntry, path);
|
||||
|
@ -26,40 +26,41 @@ namespace LibHac.FsSystem
|
||||
}
|
||||
|
||||
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) =>
|
||||
BaseFileSystem.Target.DeleteDirectoryRecursively(path);
|
||||
BaseFileSystem.Target.DeleteDirectoryRecursively(in 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) =>
|
||||
BaseFileSystem.Target.RenameFile(currentPath, newPath);
|
||||
BaseFileSystem.Target.RenameFile(in currentPath, in 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) =>
|
||||
BaseFileSystem.Target.GetEntryType(out entryType, path);
|
||||
BaseFileSystem.Target.GetEntryType(out entryType, in 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) =>
|
||||
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) =>
|
||||
BaseFileSystem.Target.OpenFile(out file, path, mode);
|
||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode) =>
|
||||
BaseFileSystem.Target.OpenFile(ref outFile, in path, mode);
|
||||
|
||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode) =>
|
||||
BaseFileSystem.Target.OpenDirectory(out directory, path, mode);
|
||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||
OpenDirectoryMode mode) =>
|
||||
BaseFileSystem.Target.OpenDirectory(ref outDirectory, in path, mode);
|
||||
|
||||
protected override Result DoCommit() => BaseFileSystem.Target.Commit();
|
||||
|
||||
@ -71,9 +72,9 @@ namespace LibHac.FsSystem
|
||||
protected override Result DoFlush() => BaseFileSystem.Target.Flush();
|
||||
|
||||
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,
|
||||
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)
|
||||
{
|
||||
Shared.Move(out _semaphore, ref semaphore);
|
||||
_semaphore = new UniqueLock<SemaphoreAdapter>(ref semaphore);
|
||||
Shared.Move(out _pinnedObject, ref pinnedObject);
|
||||
}
|
||||
|
||||
|
@ -37,10 +37,9 @@ namespace LibHac.FsSystem
|
||||
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
|
||||
// Only allocate the list for multiple sources if needed
|
||||
List<IFileSystem> multipleSources = null;
|
||||
@ -82,12 +81,12 @@ namespace LibHac.FsSystem
|
||||
|
||||
if (!(multipleSources is null))
|
||||
{
|
||||
var dir = new MergedDirectory(multipleSources, mode);
|
||||
Result rc = dir.Initialize(in path);
|
||||
using var dir = new UniqueRef<MergedDirectory>(new MergedDirectory(multipleSources, mode));
|
||||
Result rc = dir.Get.Initialize(in path);
|
||||
|
||||
if (rc.IsSuccess())
|
||||
{
|
||||
directory = dir;
|
||||
outDirectory.Set(ref dir.Ref());
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -95,11 +94,12 @@ namespace LibHac.FsSystem
|
||||
|
||||
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())
|
||||
{
|
||||
directory = dir;
|
||||
outDirectory.Set(ref dir.Ref());
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -108,10 +108,8 @@ namespace LibHac.FsSystem
|
||||
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)
|
||||
{
|
||||
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
|
||||
@ -120,7 +118,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
if (type == DirectoryEntryType.File)
|
||||
{
|
||||
return fs.OpenFile(out file, path, mode);
|
||||
return fs.OpenFile(ref outFile, path, mode);
|
||||
}
|
||||
|
||||
if (type == DirectoryEntryType.Directory)
|
||||
@ -225,12 +223,14 @@ namespace LibHac.FsSystem
|
||||
Result rc = _path.Initialize(in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using var dir = new UniqueRef<IDirectory>();
|
||||
|
||||
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;
|
||||
|
||||
SourceDirs.Add(dir);
|
||||
SourceDirs.Add(dir.Release());
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
@ -270,18 +270,19 @@ namespace LibHac.FsSystem
|
||||
// todo: Efficient way to remove duplicates
|
||||
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
|
||||
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;
|
||||
|
||||
long entriesRead;
|
||||
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 (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name)))
|
||||
|
@ -175,7 +175,7 @@ namespace LibHac.FsSystem
|
||||
rc = pathNormalized.Normalize(pathFlags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Path rootPath = _rootPath.GetPath();
|
||||
Path rootPath = _rootPath.DangerousGetPath();
|
||||
|
||||
using var fullPath = new Path();
|
||||
rc = fullPath.Combine(in rootPath, in pathNormalized);
|
||||
@ -379,9 +379,9 @@ namespace LibHac.FsSystem
|
||||
() => 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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -398,14 +398,12 @@ namespace LibHac.FsSystem
|
||||
OpenDirectoryInternal(out dirTemp, mode, dirInfo), _fsClient);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = dirTemp;
|
||||
outDirectory.Reset(dirTemp);
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -423,7 +421,7 @@ namespace LibHac.FsSystem
|
||||
OpenFileInternal(out fileStream, fullPath, mode), _fsClient);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new LocalFile(fileStream, mode);
|
||||
outFile.Reset(new LocalFile(fileStream, mode));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -34,13 +34,14 @@ namespace LibHac.FsSystem
|
||||
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;
|
||||
}
|
||||
|
||||
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('/');
|
||||
|
||||
@ -49,7 +50,7 @@ namespace LibHac.FsSystem
|
||||
ThrowHelper.ThrowResult(ResultFs.PathNotFound.Value);
|
||||
}
|
||||
|
||||
file = OpenFile(entry, mode);
|
||||
outFile.Reset(OpenFile(entry, mode));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -26,12 +26,14 @@ namespace LibHac.FsSystem
|
||||
/// </summary>
|
||||
public PartitionFileSystemBuilder(IFileSystem input)
|
||||
{
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||
.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();
|
||||
}
|
||||
|
||||
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)
|
||||
return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
@ -61,15 +60,13 @@ namespace LibHac.FsSystem
|
||||
if (path == rootPath)
|
||||
return ResultFs.PathNotFound.Log();
|
||||
|
||||
directory = new PartitionDirectory(this, mode);
|
||||
outDirectory.Reset(new PartitionDirectory(this, mode));
|
||||
|
||||
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)
|
||||
return ResultFs.PreconditionViolation.Log();
|
||||
|
||||
@ -81,7 +78,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
|
||||
@ -6,22 +7,22 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
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,
|
||||
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)
|
||||
{
|
||||
return BaseFile.GetSize(out size);
|
||||
return _baseFile.Get.GetSize(out size);
|
||||
}
|
||||
|
||||
protected override Result DoFlush()
|
||||
@ -45,7 +46,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
case OperationId.InvalidateCache:
|
||||
case OperationId.QueryRange:
|
||||
return BaseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||
return _baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||
default:
|
||||
return ResultFs.UnsupportedOperateRangeForReadOnlyFile.Log();
|
||||
}
|
||||
|
@ -9,12 +9,6 @@ namespace LibHac.FsSystem
|
||||
private IFileSystem BaseFs { get; }
|
||||
private ReferenceCountedDisposable<IFileSystem> BaseFsShared { get; }
|
||||
|
||||
// Todo: Remove non-shared constructor
|
||||
public ReadOnlyFileSystem(IFileSystem baseFileSystem)
|
||||
{
|
||||
BaseFs = baseFileSystem;
|
||||
}
|
||||
|
||||
public ReadOnlyFileSystem(ReferenceCountedDisposable<IFileSystem> baseFileSystem)
|
||||
{
|
||||
BaseFsShared = baseFileSystem;
|
||||
@ -28,35 +22,35 @@ namespace LibHac.FsSystem
|
||||
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);
|
||||
|
||||
Result rc = BaseFs.OpenFile(out IFile baseFile, path, mode);
|
||||
using var baseFile = new UniqueRef<IFile>();
|
||||
Result rc = BaseFs.OpenFile(ref baseFile.Ref(), in path, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new ReadOnlyFile(baseFile);
|
||||
outFile.Reset(new ReadOnlyFile(ref baseFile.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return BaseFs.GetFreeSpaceSize(out freeSpace, path);
|
||||
return BaseFs.GetFreeSpaceSize(out freeSpace, in 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:
|
||||
// return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log();
|
||||
@ -64,7 +58,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
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:
|
||||
// return ResultFs.NotImplemented.Log();
|
||||
|
@ -39,9 +39,10 @@ namespace LibHac.FsSystem.RomFs
|
||||
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||
.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;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
return ResultFs.PathNotFound.Log();
|
||||
}
|
||||
|
||||
directory = new RomFsDirectory(this, position, mode);
|
||||
outDirectory.Reset(new RomFsDirectory(this, position, mode));
|
||||
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))
|
||||
{
|
||||
return ResultFs.PathNotFound.Log();
|
||||
@ -77,7 +74,7 @@ namespace LibHac.FsSystem.RomFs
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.Keys;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Fs;
|
||||
@ -148,91 +149,92 @@ namespace LibHac.FsSystem.Save
|
||||
|
||||
protected override Result DoCreateDirectory(in Path path)
|
||||
{
|
||||
Result result = SaveDataFileSystemCore.CreateDirectory(path);
|
||||
Result result = SaveDataFileSystemCore.CreateDirectory(in path);
|
||||
|
||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(in Path path)
|
||||
{
|
||||
Result result = SaveDataFileSystemCore.DeleteDirectory(path);
|
||||
Result result = SaveDataFileSystemCore.DeleteDirectory(in path);
|
||||
|
||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path);
|
||||
Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(in path);
|
||||
|
||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path);
|
||||
Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(in path);
|
||||
|
||||
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(in Path path)
|
||||
{
|
||||
Result result = SaveDataFileSystemCore.DeleteFile(path);
|
||||
Result result = SaveDataFileSystemCore.DeleteFile(in path);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -134,10 +134,9 @@ namespace LibHac.FsSystem.Save
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -146,15 +145,13 @@ namespace LibHac.FsSystem.Save
|
||||
return ResultFs.PathNotFound.Log();
|
||||
}
|
||||
|
||||
directory = new SaveDataDirectory(this, position, mode);
|
||||
outDirectory.Reset(new SaveDataDirectory(this, position, mode));
|
||||
|
||||
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);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -165,7 +162,7 @@ namespace LibHac.FsSystem.Save
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -95,14 +95,15 @@ namespace LibHac.FsSystem
|
||||
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)
|
||||
|
@ -111,16 +111,17 @@ namespace LibHac.FsSystem
|
||||
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);
|
||||
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);
|
||||
return BaseFileSystem.Target.OpenDirectory(out directory, path, mode);
|
||||
return BaseFileSystem.Target.OpenDirectory(ref outDirectory, path, mode);
|
||||
}
|
||||
|
||||
protected override Result DoCommit()
|
||||
|
@ -40,7 +40,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
private Result ResolveFullPath(ref Path outPath, in Path relativePath)
|
||||
{
|
||||
Path rootPath = _rootPath.GetPath();
|
||||
Path rootPath = _rootPath.DangerousGetPath();
|
||||
return outPath.Combine(in rootPath, in relativePath);
|
||||
}
|
||||
|
||||
@ -100,29 +100,26 @@ namespace LibHac.FsSystem
|
||||
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();
|
||||
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
||||
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;
|
||||
|
||||
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();
|
||||
Result rc = ResolveFullPath(ref fullPath.Ref(), in path);
|
||||
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;
|
||||
|
||||
return Result.Success;
|
||||
|
@ -39,15 +39,14 @@ namespace LibHac.FsSystem
|
||||
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
||||
ref FsIterationTaskClosure closure)
|
||||
{
|
||||
IDirectory directory = null;
|
||||
try
|
||||
{
|
||||
Result rc = fs.OpenDirectory(out directory, in workPath, OpenDirectoryMode.All);
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
|
||||
Result rc = fs.OpenDirectory(ref directory.Ref(), in workPath, OpenDirectoryMode.All);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
while (true)
|
||||
{
|
||||
rc = directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||
rc = directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (entriesRead == 0)
|
||||
@ -80,29 +79,22 @@ namespace LibHac.FsSystem
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
directory?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static Result CleanupDirectoryRecursivelyInternal(IFileSystem fs, ref Path workPath,
|
||||
ref DirectoryEntry dirEntry, FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
||||
ref FsIterationTaskClosure closure)
|
||||
{
|
||||
IDirectory directory = null;
|
||||
try
|
||||
{
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Result rc = fs.OpenDirectory(out directory, in workPath, OpenDirectoryMode.All);
|
||||
Result rc = fs.OpenDirectory(ref directory.Ref(), in workPath, OpenDirectoryMode.All);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||
rc = directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory.Dispose();
|
||||
directory = null;
|
||||
directory.Reset(null);
|
||||
|
||||
if (entriesRead == 0)
|
||||
break;
|
||||
@ -134,11 +126,6 @@ namespace LibHac.FsSystem
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
directory?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static Result IterateDirectoryRecursively(IFileSystem fs, in Path rootPath, ref DirectoryEntry dirEntry,
|
||||
FsIterationTask onEnterDir, FsIterationTask onExitDir, FsIterationTask onFile,
|
||||
@ -171,39 +158,35 @@ namespace LibHac.FsSystem
|
||||
in Path sourcePath, Span<byte> workBuffer)
|
||||
{
|
||||
// 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;
|
||||
|
||||
using (sourceFile)
|
||||
{
|
||||
rc = sourceFile.GetSize(out long fileSize);
|
||||
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(out IFile destFile, in destPath, OpenMode.Write);
|
||||
rc = destFileSystem.OpenFile(ref destFile.Ref(), in destPath, OpenMode.Write);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
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);
|
||||
rc = sourceFile.Get.Read(out long bytesRead, offset, workBuffer, ReadOption.None);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = destFile.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||
rc = destFile.Get.Write(offset, workBuffer.Slice(0, (int)bytesRead), WriteOption.None);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
remaining -= bytesRead;
|
||||
offset += bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -300,17 +283,16 @@ namespace LibHac.FsSystem
|
||||
|
||||
static Result OnFile(in Path path, in DirectoryEntry entry, ref FsIterationTaskClosure closure)
|
||||
{
|
||||
IFile file = null;
|
||||
try
|
||||
{
|
||||
Result rc = closure.SourceFileSystem.OpenFile(out file, in path, OpenMode.Read);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
Result rc = closure.SourceFileSystem.OpenFile(ref file.Ref(), in path, OpenMode.Read);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
long offset = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
rc = file.Read(out long bytesRead, offset, closure.Buffer, ReadOption.None);
|
||||
rc = file.Get.Read(out long bytesRead, offset, closure.Buffer, ReadOption.None);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (bytesRead < closure.Buffer.Length)
|
||||
@ -321,11 +303,6 @@ namespace LibHac.FsSystem
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
file?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
using var rootPath = new Path();
|
||||
Result rc = PathFunctions.SetUpFixedPath(ref rootPath.Ref(), RootPath);
|
||||
@ -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;
|
||||
try
|
||||
{
|
||||
tempUniqueLock = new UniqueLock<SemaphoreAdapter>(semaphore, new DeferLock());
|
||||
using var uniqueLock = new UniqueLock<SemaphoreAdapter>(semaphore, new DeferLock());
|
||||
|
||||
if (!tempUniqueLock.TryLock())
|
||||
{
|
||||
uniqueLock = default;
|
||||
if (!uniqueLock.TryLock())
|
||||
return ResultFs.OpenCountLimit.Log();
|
||||
}
|
||||
|
||||
uniqueLock = Shared.Move(ref tempUniqueLock);
|
||||
outUniqueLock.Set(ref uniqueLock.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
tempUniqueLock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static Result MakeUniqueLockWithPin<T>(out IUniqueLock uniqueLock, SemaphoreAdapter semaphore,
|
||||
ref ReferenceCountedDisposable<T> objectToPin) where T : class, IDisposable
|
||||
public static Result MakeUniqueLockWithPin<T>(ref UniqueRef<IUniqueLock> outUniqueLock,
|
||||
SemaphoreAdapter semaphore, ref ReferenceCountedDisposable<T> objectToPin) where T : class, IDisposable
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out uniqueLock);
|
||||
|
||||
UniqueLock<SemaphoreAdapter> tempUniqueLock = default;
|
||||
try
|
||||
{
|
||||
Result rc = TryAcquireCountSemaphore(out tempUniqueLock, semaphore);
|
||||
using var semaphoreAdapter = new UniqueLock<SemaphoreAdapter>();
|
||||
Result rc = TryAcquireCountSemaphore(ref semaphoreAdapter.Ref(), semaphore);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
uniqueLock = new UniqueLockWithPin<T>(ref tempUniqueLock, ref objectToPin);
|
||||
var lockWithPin = new UniqueLockWithPin<T>(ref semaphoreAdapter.Ref(), ref objectToPin);
|
||||
using var uniqueLock = new UniqueRef<IUniqueLock>(lockWithPin);
|
||||
|
||||
outUniqueLock.Set(ref uniqueLock.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
tempUniqueLock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using LibHac.Common;
|
||||
using static InlineIL.IL.Emit;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
@ -24,6 +25,22 @@ namespace LibHac.Os
|
||||
{
|
||||
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
|
||||
|
@ -107,9 +107,10 @@ namespace LibHac
|
||||
SwitchFsNca nca = null;
|
||||
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);
|
||||
string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca";
|
||||
@ -145,9 +146,10 @@ namespace LibHac
|
||||
|
||||
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)
|
||||
{
|
||||
@ -172,9 +174,10 @@ namespace LibHac
|
||||
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
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.Version = metadata.TitleVersion;
|
||||
title.Metadata = metadata;
|
||||
@ -216,11 +219,12 @@ namespace LibHac
|
||||
foreach (Title title in Titles.Values.Where(x => x.ControlNca != null))
|
||||
{
|
||||
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)
|
||||
|
@ -32,8 +32,9 @@ namespace LibHac
|
||||
XciPartition root = GetRootPartition();
|
||||
if (type == XciPartitionType.Root) return root;
|
||||
|
||||
root.OpenFile(out IFile partitionFile, type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
return new XciPartition(partitionFile.AsStorage());
|
||||
using var partitionFile = new UniqueRef<IFile>();
|
||||
root.OpenFile(ref partitionFile.Ref(), type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
return new XciPartition(partitionFile.Release().AsStorage());
|
||||
}
|
||||
|
||||
private XciPartition GetRootPartition()
|
||||
|
@ -36,9 +36,10 @@ namespace hactoolnet
|
||||
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
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using LibHac;
|
||||
using LibHac.Common;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Util;
|
||||
using static hactoolnet.Print;
|
||||
@ -23,7 +24,7 @@ namespace hactoolnet
|
||||
|
||||
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;
|
||||
int contentType = 0;
|
||||
@ -35,7 +36,7 @@ namespace hactoolnet
|
||||
|
||||
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;
|
||||
|
||||
break;
|
||||
|
@ -227,8 +227,9 @@ namespace hactoolnet
|
||||
IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
if (!pfs.FileExists("main.npdm")) return Validity.Unchecked;
|
||||
|
||||
pfs.OpenFile(out IFile npdmFile, "main.npdm".ToU8String(), OpenMode.Read).ThrowIfFailure();
|
||||
var npdm = new NpdmBinary(npdmFile.AsStream());
|
||||
using var npdmFile = new UniqueRef<IFile>();
|
||||
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);
|
||||
}
|
||||
@ -258,10 +259,12 @@ namespace hactoolnet
|
||||
if (nca.CanOpenSection(NcaSectionType.Code))
|
||||
{
|
||||
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())
|
||||
{
|
||||
var npdm = new NpdmBinary(file.AsStream(), null);
|
||||
var npdm = new NpdmBinary(file.Release().AsStream(), null);
|
||||
PrintItem(sb, colLen, "Title Name:", npdm.TitleName);
|
||||
}
|
||||
}
|
||||
|
@ -67,25 +67,22 @@ namespace hactoolnet
|
||||
string destFilename = ctx.Options.ReplaceFileDest;
|
||||
if (!destFilename.StartsWith("/")) destFilename = '/' + destFilename;
|
||||
|
||||
using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read))
|
||||
{
|
||||
save.OpenFile(out IFile outFile, destFilename.ToU8String(), OpenMode.ReadWrite).ThrowIfFailure();
|
||||
using var inFile = new UniqueRef<IFile>(new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read));
|
||||
|
||||
using (outFile)
|
||||
{
|
||||
inFile.GetSize(out long inFileSize).ThrowIfFailure();
|
||||
outFile.GetSize(out long outFileSize).ThrowIfFailure();
|
||||
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)
|
||||
{
|
||||
outFile.SetSize(inFileSize).ThrowIfFailure();
|
||||
outFile.Get.SetSize(inFileSize).ThrowIfFailure();
|
||||
}
|
||||
|
||||
inFile.CopyTo(outFile, ctx.Logger);
|
||||
inFile.Get.CopyTo(outFile.Get, ctx.Logger);
|
||||
|
||||
ctx.Logger.LogMessage($"Replaced file {destFilename}");
|
||||
}
|
||||
}
|
||||
|
||||
signNeeded = true;
|
||||
}
|
||||
|
@ -34,20 +34,45 @@ namespace LibHac.Tests.Fs
|
||||
|
||||
public IFileSystem Create()
|
||||
{
|
||||
DirectorySaveDataFileSystem
|
||||
.CreateNew(out DirectorySaveDataFileSystem saveFs, BaseFileSystem, true, true, true)
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, BaseFileSystem, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
|
||||
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()
|
||||
{
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
return (baseFs, saveFs);
|
||||
}
|
||||
@ -132,8 +157,7 @@ namespace LibHac.Tests.Fs
|
||||
baseFs.CreateFile("/0/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
Assert.Success(saveFs.GetEntryType(out _, "/file1"));
|
||||
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("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
||||
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
||||
@ -168,8 +191,7 @@ namespace LibHac.Tests.Fs
|
||||
// Set the existing files before initializing the save FS
|
||||
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
||||
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
||||
@ -202,8 +224,7 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
var originalExtraData = new SaveDataExtraData();
|
||||
originalExtraData.DataSize = 0x12345;
|
||||
@ -212,7 +233,7 @@ namespace LibHac.Tests.Fs
|
||||
Assert.Success(saveFs.CommitExtraData(false));
|
||||
|
||||
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.Equal(originalExtraData, extraData);
|
||||
@ -223,8 +244,7 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
var originalExtraData = new SaveDataExtraData();
|
||||
originalExtraData.DataSize = 0x12345;
|
||||
@ -233,7 +253,7 @@ namespace LibHac.Tests.Fs
|
||||
saveFs.CommitExtraData(false).ThrowIfFailure();
|
||||
|
||||
saveFs.Dispose();
|
||||
DirectorySaveDataFileSystem.CreateNew(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
var newExtraData = new SaveDataExtraData();
|
||||
newExtraData.DataSize = 0x67890;
|
||||
@ -251,8 +271,7 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
// Write extra data and close with committing
|
||||
var originalExtraData = new SaveDataExtraData();
|
||||
@ -262,7 +281,7 @@ namespace LibHac.Tests.Fs
|
||||
saveFs.CommitExtraData(false).ThrowIfFailure();
|
||||
|
||||
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
|
||||
var newExtraData = new SaveDataExtraData();
|
||||
@ -272,7 +291,7 @@ namespace LibHac.Tests.Fs
|
||||
saveFs.Dispose();
|
||||
|
||||
// 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.Equal(originalExtraData, extraData);
|
||||
@ -286,8 +305,7 @@ namespace LibHac.Tests.Fs
|
||||
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
||||
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
||||
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true)
|
||||
.ThrowIfFailure();
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
||||
|
||||
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
||||
|
||||
@ -302,7 +320,7 @@ namespace LibHac.Tests.Fs
|
||||
var timeStampGetter = new TimeStampGetter();
|
||||
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||
|
||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||
@ -330,7 +348,7 @@ namespace LibHac.Tests.Fs
|
||||
var timeStampGetter = new TimeStampGetter();
|
||||
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||
|
||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||
@ -358,7 +376,7 @@ namespace LibHac.Tests.Fs
|
||||
var timeStampGetter = new TimeStampGetter();
|
||||
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
||||
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
||||
|
||||
saveFs.CommitExtraData(true).ThrowIfFailure();
|
||||
@ -421,12 +439,13 @@ namespace LibHac.Tests.Fs
|
||||
var extraData = new SaveDataExtraData();
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -140,26 +140,22 @@ namespace LibHac.Tests.Fs
|
||||
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();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||
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();
|
||||
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
|
||||
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)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -23,14 +24,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/dir1/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||
fs.CreateFile("/dir2/file", data2.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||
|
||||
fs.OpenFile(out IFile file1, "/dir1/file", OpenMode.Write).ThrowIfFailure();
|
||||
fs.OpenFile(out IFile file2, "/dir2/file", OpenMode.Write).ThrowIfFailure();
|
||||
using var file1 = new UniqueRef<IFile>();
|
||||
using var file2 = new UniqueRef<IFile>();
|
||||
|
||||
file1.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||
file2.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||
fs.OpenFile(ref file1.Ref(), "/dir1/file", OpenMode.Write).ThrowIfFailure();
|
||||
fs.OpenFile(ref file2.Ref(), "/dir2/file", OpenMode.Write).ThrowIfFailure();
|
||||
|
||||
file1.Dispose();
|
||||
file2.Dispose();
|
||||
file1.Get.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||
file2.Get.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||
|
||||
file1.Reset();
|
||||
file2.Reset();
|
||||
|
||||
fs.Commit().ThrowIfFailure();
|
||||
fs.Dispose();
|
||||
@ -41,23 +45,18 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
byte[] readData1 = new byte[data1.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.Read(out long bytesRead, 0, readData1, ReadOption.None));
|
||||
Assert.Equal(data1.Length, bytesRead);
|
||||
}
|
||||
Assert.Success(file1.Get.Read(out long bytesReadFile1, 0, readData1, ReadOption.None));
|
||||
file1.Reset();
|
||||
Assert.Equal(data1.Length, bytesReadFile1);
|
||||
|
||||
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.Read(out long bytesRead, 0, readData2, ReadOption.None));
|
||||
Assert.Equal(data2.Length, bytesRead);
|
||||
}
|
||||
Assert.Success(file2.Get.Read(out long bytesReadFile2, 0, readData2, ReadOption.None));
|
||||
Assert.Equal(data2.Length, bytesReadFile2);
|
||||
|
||||
Assert.Equal(data2, readData2);
|
||||
}
|
||||
@ -109,9 +108,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateDirectory("/dir").ThrowIfFailure();
|
||||
fs.CreateFile("/dir/file", data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
||||
|
||||
fs.OpenFile(out IFile file, "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||
file.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||
file.Dispose();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||
file.Get.Write(0, data1, WriteOption.Flush).ThrowIfFailure();
|
||||
file.Reset();
|
||||
|
||||
// Commit and reopen the file system
|
||||
fs.Commit().ThrowIfFailure();
|
||||
@ -120,22 +120,19 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs = fsCreator.Create();
|
||||
|
||||
// Make changes to the file
|
||||
fs.OpenFile(out file, "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||
file.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||
file.Dispose();
|
||||
fs.OpenFile(ref file.Ref(), "/dir/file", OpenMode.Write).ThrowIfFailure();
|
||||
file.Get.Write(0, data2, WriteOption.Flush).ThrowIfFailure();
|
||||
file.Reset();
|
||||
|
||||
Assert.Success(fs.Rollback());
|
||||
|
||||
// The file should contain the original data after the rollback
|
||||
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.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||
Assert.Success(file.Get.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||
Assert.Equal(data1.Length, bytesRead);
|
||||
}
|
||||
|
||||
Assert.Equal(data1, readData);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -72,9 +73,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -26,9 +27,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -42,17 +44,18 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/dir/file1", 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 entry2 = new DirectoryEntry();
|
||||
var entry3 = new DirectoryEntry();
|
||||
var entry4 = new DirectoryEntry();
|
||||
|
||||
Assert.Success(dir.Read(out long entriesRead1, SpanHelpers.AsSpan(ref entry1)));
|
||||
Assert.Success(dir.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)));
|
||||
Assert.Success(dir.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 entriesRead1, SpanHelpers.AsSpan(ref entry1)));
|
||||
Assert.Success(dir.Get.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)));
|
||||
Assert.Success(dir.Get.Read(out long entriesRead3, SpanHelpers.AsSpan(ref entry3)));
|
||||
Assert.Success(dir.Get.Read(out long entriesRead4, SpanHelpers.AsSpan(ref entry4)));
|
||||
|
||||
Assert.Equal(1, entriesRead1);
|
||||
Assert.Equal(1, entriesRead2);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
@ -15,13 +16,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[20];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Read(out long bytesRead, 50, buffer, ReadOption.None));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Assert.Success(file.Get.Read(out long bytesRead, 50, buffer, ReadOption.None));
|
||||
Assert.Equal(20, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_OffsetPastEndOfFile_ReturnsOutOfRange()
|
||||
@ -31,13 +31,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Read(out _, 1, buffer, ReadOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Result rc = file.Get.Read(out _, 1, buffer, ReadOption.None);
|
||||
Assert.Result(ResultFs.OutOfRange, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_OpenModeNoRead_ReturnsInvalidOpenModeForRead()
|
||||
@ -47,13 +46,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Read(out _, 0, buffer, ReadOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
|
||||
Result rc = file.Get.Read(out _, 0, buffer, ReadOption.None);
|
||||
Assert.Result(ResultFs.ReadUnpermitted, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_NegativeOffset_ReturnsOutOfRange()
|
||||
@ -63,13 +61,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Read(out _, -5, buffer, ReadOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
|
||||
Result rc = file.Get.Read(out _, -5, buffer, ReadOption.None);
|
||||
Assert.Result(ResultFs.OutOfRange, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_OffsetPlusSizeOverflows_ReturnsOutOfRange()
|
||||
@ -79,13 +76,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
|
||||
Result rc = file.Get.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
|
||||
Assert.Result(ResultFs.OutOfRange, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_FileTooSmallToFillBuffer_BytesReadContainsAvailableByteCount()
|
||||
@ -95,13 +91,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[200];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Read(out long bytesRead, 90, buffer, ReadOption.None));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Assert.Success(file.Get.Read(out long bytesRead, 90, buffer, ReadOption.None));
|
||||
Assert.Equal(10, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileRead_FileTooSmallToFillBuffer_DoesPartialRead()
|
||||
@ -111,11 +106,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 100, CreateFileOptions.None);
|
||||
|
||||
// The contents of a created file are undefined, so zero the file
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
using (file)
|
||||
{
|
||||
file.Write(0, new byte[100], WriteOption.None);
|
||||
}
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
file.Get.Write(0, new byte[100], WriteOption.None);
|
||||
file.Reset();
|
||||
|
||||
byte[] bufferExpected = new byte[200];
|
||||
bufferExpected.AsSpan(10).Fill(0xCC);
|
||||
@ -123,12 +117,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
byte[] buffer = new byte[200];
|
||||
buffer.AsSpan().Fill(0xCC);
|
||||
|
||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Read(out _, 90, buffer, ReadOption.None));
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Assert.Success(file.Get.Read(out _, 90, buffer, ReadOption.None));
|
||||
Assert.Equal(bufferExpected, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -12,13 +13,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
fs.CreateFile("/file", 0, CreateFileOptions.None);
|
||||
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
||||
Result rc = file.SetSize(54321);
|
||||
file.Dispose();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||
Result rc = file.Get.SetSize(54321);
|
||||
file.Reset();
|
||||
|
||||
fs.OpenFile(out file, "/file", OpenMode.All);
|
||||
file.GetSize(out long fileSize);
|
||||
file.Dispose();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||
file.Get.GetSize(out long fileSize);
|
||||
|
||||
Assert.Success(rc);
|
||||
Assert.Equal(54321, fileSize);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
@ -16,18 +17,16 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
||||
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
file.Write(0, data, WriteOption.None);
|
||||
file.Dispose();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
file.Get.Write(0, data, WriteOption.None);
|
||||
file.Reset();
|
||||
|
||||
byte[] readData = new byte[data.Length];
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||
Assert.Success(file.Get.Read(out long bytesRead, 0, readData, ReadOption.None));
|
||||
Assert.Equal(data.Length, bytesRead);
|
||||
}
|
||||
|
||||
Assert.Equal(data, readData);
|
||||
}
|
||||
@ -40,13 +39,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Write(5, buffer, WriteOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
|
||||
Result rc = file.Get.Write(5, buffer, WriteOption.None);
|
||||
Assert.Result(ResultFs.FileExtensionWithoutOpenModeAllowAppend, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_OpenModeNoWrite_ReturnsInvalidOpenModeForWrite()
|
||||
@ -56,13 +54,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Write(5, buffer, WriteOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Result rc = file.Get.Write(5, buffer, WriteOption.None);
|
||||
Assert.Result(ResultFs.WriteUnpermitted, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_NegativeOffset_ReturnsOutOfRange()
|
||||
@ -72,13 +69,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Write(-5, buffer, WriteOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Result rc = file.Get.Write(-5, buffer, WriteOption.None);
|
||||
Assert.Result(ResultFs.OutOfRange, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_OffsetPlusSizeOverflows_ReturnsOutOfRange()
|
||||
@ -88,13 +84,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
Result rc = file.Write(long.MaxValue - 5, buffer, WriteOption.None);
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
Result rc = file.Get.Write(long.MaxValue - 5, buffer, WriteOption.None);
|
||||
Assert.Result(ResultFs.OutOfRange, rc);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_WritePartiallyPastEndOfFileAppendAllowed_FileIsExtended()
|
||||
@ -104,15 +99,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Write(5, buffer, WriteOption.None));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||
|
||||
file.GetSize(out long newSize);
|
||||
Assert.Success(file.Get.Write(5, buffer, WriteOption.None));
|
||||
|
||||
file.Get.GetSize(out long newSize);
|
||||
Assert.Equal(15, newSize);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_WritePastEndOfFileAppendAllowed_FileIsExtended()
|
||||
@ -122,15 +116,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
fs.CreateFile("/file", 10, CreateFileOptions.None);
|
||||
|
||||
byte[] buffer = new byte[10];
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Write(15, buffer, WriteOption.None));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||
|
||||
file.GetSize(out long newSize);
|
||||
Assert.Success(file.Get.Write(15, buffer, WriteOption.None));
|
||||
|
||||
file.Get.GetSize(out long newSize);
|
||||
Assert.Equal(25, newSize);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IFileWrite_WritePastEndOfFileAppendAllowed_DataIsWritten()
|
||||
@ -145,23 +138,21 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
byte[] writeBuffer = new byte[10];
|
||||
writeBuffer.AsSpan().Fill(0xCC);
|
||||
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.All);
|
||||
using (file)
|
||||
{
|
||||
Assert.Success(file.Write(15, writeBuffer, WriteOption.None));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.All);
|
||||
|
||||
Assert.Success(file.Get.Write(15, writeBuffer, WriteOption.None));
|
||||
|
||||
// Unwritten portions of new files are undefined, so write to the other portions
|
||||
file.Write(0, new byte[15], WriteOption.None);
|
||||
}
|
||||
file.Get.Write(0, new byte[15], WriteOption.None);
|
||||
file.Reset();
|
||||
|
||||
byte[] readBuffer = new byte[25];
|
||||
|
||||
fs.OpenFile(out file, "/file", OpenMode.Read);
|
||||
using (file)
|
||||
{
|
||||
file.Read(out _, 0, readBuffer, ReadOption.None);
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Read);
|
||||
|
||||
file.Get.Read(out _, 0, readBuffer, ReadOption.None);
|
||||
Assert.Equal(bufferExpected, readBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -13,7 +14,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -13,7 +14,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using Xunit;
|
||||
|
||||
@ -74,19 +75,18 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
fs.RenameFile("/file1", "/file2");
|
||||
|
||||
Assert.Success(fs.OpenFile(out IFile file1, "/file1", OpenMode.Read));
|
||||
Assert.Success(fs.OpenFile(out IFile file2, "/file2", OpenMode.Read));
|
||||
using var file1 = new UniqueRef<IFile>();
|
||||
using var file2 = new UniqueRef<IFile>();
|
||||
|
||||
using (file1)
|
||||
using (file2)
|
||||
{
|
||||
Assert.Success(file1.GetSize(out long file1Size));
|
||||
Assert.Success(file2.GetSize(out long file2Size));
|
||||
Assert.Success(fs.OpenFile(ref file1.Ref(), "/file1", OpenMode.Read));
|
||||
Assert.Success(fs.OpenFile(ref file2.Ref(), "/file2", OpenMode.Read));
|
||||
|
||||
Assert.Success(file1.Get.GetSize(out long file1Size));
|
||||
Assert.Success(file2.Get.GetSize(out long file2Size));
|
||||
|
||||
Assert.Equal(54321, file1Size);
|
||||
Assert.Equal(12345, file2Size);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenameFile_DataIsUnmodified()
|
||||
@ -97,17 +97,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
|
||||
|
||||
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
|
||||
|
||||
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
|
||||
file.Write(0, data, WriteOption.None);
|
||||
file.Dispose();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
fs.OpenFile(ref file.Ref(), "/file", OpenMode.Write);
|
||||
file.Get.Write(0, data, WriteOption.None);
|
||||
file.Reset();
|
||||
|
||||
fs.RenameFile("/file", "/renamed");
|
||||
|
||||
byte[] readData = new byte[data.Length];
|
||||
|
||||
fs.OpenFile(out file, "/renamed", OpenMode.Read);
|
||||
Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
|
||||
file.Dispose();
|
||||
fs.OpenFile(ref file.Ref(), "/renamed", OpenMode.Read);
|
||||
Result rc = file.Get.Read(out long bytesRead, 0, readData, ReadOption.None);
|
||||
|
||||
Assert.Success(rc);
|
||||
Assert.Equal(data.Length, bytesRead);
|
||||
|
@ -58,7 +58,8 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
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]
|
||||
@ -66,8 +67,9 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
|
||||
Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile", OpenMode.All));
|
||||
Assert.Success(file.GetSize(out long fileSize));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir/replacedFile", OpenMode.All));
|
||||
Assert.Success(file.Get.GetSize(out long fileSize));
|
||||
|
||||
Assert.Equal(2, fileSize);
|
||||
}
|
||||
@ -77,8 +79,9 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
|
||||
Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile", OpenMode.All));
|
||||
Assert.Success(fs.OpenFile(out _, "/dir2/upperFile", OpenMode.All));
|
||||
using var file = new UniqueRef<IFile>();
|
||||
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/lowerFile", OpenMode.All));
|
||||
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/upperFile", OpenMode.All));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -86,7 +89,8 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
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]
|
||||
@ -94,8 +98,9 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
|
||||
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir", OpenDirectoryMode.All));
|
||||
Assert.Equal(typeof(InMemoryFileSystem), dir.GetType().DeclaringType);
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/lowerDir", OpenDirectoryMode.All));
|
||||
Assert.Equal(typeof(InMemoryFileSystem), directory.Get.GetType().DeclaringType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -103,8 +108,9 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
|
||||
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All));
|
||||
Assert.Equal(typeof(LayeredFileSystem), dir.GetType().DeclaringType);
|
||||
using var directory = new UniqueRef<IDirectory>();
|
||||
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir", OpenDirectoryMode.All));
|
||||
Assert.Equal(typeof(LayeredFileSystem), directory.Get.GetType().DeclaringType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -122,9 +128,10 @@ namespace LibHac.Tests.Fs
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -134,9 +141,10 @@ namespace LibHac.Tests.Fs
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
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(2, entry.Size);
|
||||
}
|
||||
@ -147,9 +155,10 @@ namespace LibHac.Tests.Fs
|
||||
IFileSystem fs = CreateEmptyFileSystem();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -158,9 +167,10 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -170,16 +180,17 @@ namespace LibHac.Tests.Fs
|
||||
IFileSystem fs = CreateFileSystem();
|
||||
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
|
||||
long entriesRead;
|
||||
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);
|
||||
|
||||
Assert.Success(directory.GetEntryCount(out long entryCount));
|
||||
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
||||
Assert.Equal(3, entryCount);
|
||||
}
|
||||
|
||||
@ -188,9 +199,10 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user