Introduce UniqueRef<T> and use it in IFileSystem

This commit is contained in:
Alex Barney 2021-08-10 14:44:58 -07:00
parent 5f85c0b8e2
commit 01ca9e0412
76 changed files with 1469 additions and 1561 deletions

View 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;
}
}
}

View File

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

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

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

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

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

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

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

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

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

View File

@ -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();
}

View File

@ -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);

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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();
}

View File

@ -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();
}
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

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

View File

@ -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()

View File

@ -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;

View File

@ -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();
}
}
}
}

View File

@ -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

View File

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

View File

@ -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()

View File

@ -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
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -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);
}
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}