mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Fixup some mounted-FS-related classes and update them to 13.1.0
- FileSystemAccessor - FileAccessor - DirectoryAccessor - MountTable - UserMountTable - FileDataCacheAccessor - IFileDataCache - GlobalFileDataCacheAccessorReadableScopedPointer - FileDataCache shim functions - PathBasedFileDataCache shim functions
This commit is contained in:
parent
375b5b9220
commit
cf7062788f
14 changed files with 414 additions and 142 deletions
13
src/LibHac/Common/Box.cs
Normal file
13
src/LibHac/Common/Box.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace LibHac.Common;
|
||||
|
||||
public class Box<T> where T : struct
|
||||
{
|
||||
private T _value;
|
||||
|
||||
public ref T Value => ref _value;
|
||||
|
||||
public Box()
|
||||
{
|
||||
_value = new T();
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ internal struct FileSystemClientGlobals : IDisposable
|
|||
public FsContextHandlerGlobals FsContextHandler;
|
||||
public ResultHandlingUtilityGlobals ResultHandlingUtility;
|
||||
public DirectorySaveDataFileSystemGlobals DirectorySaveDataFileSystem;
|
||||
public FileDataCacheShim.Globals FileDataCache;
|
||||
|
||||
public void Initialize(FileSystemClient fsClient, HorizonClient horizonClient)
|
||||
{
|
||||
|
@ -60,4 +61,4 @@ public readonly struct FileSystemClientImpl
|
|||
internal ref FileSystemClientGlobals Globals => ref Fs.Globals;
|
||||
|
||||
internal FileSystemClientImpl(FileSystemClient parentClient) => Fs = parentClient;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ using LibHac.Fs.Fsa;
|
|||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to a directory in a mounted file system and handles closing the directory.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class DirectoryAccessor : IDisposable
|
||||
{
|
||||
private UniqueRef<IDirectory> _directory;
|
||||
|
@ -35,4 +39,4 @@ internal class DirectoryAccessor : IDisposable
|
|||
{
|
||||
return _directory.Get.GetEntryCount(out entryCount);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.Os;
|
||||
using static LibHac.Fs.Impl.AccessLogStrings;
|
||||
|
||||
|
@ -15,6 +16,10 @@ internal enum WriteState
|
|||
Failed,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to a mount <see cref="IFile"/> and handles caching it.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class FileAccessor : IDisposable
|
||||
{
|
||||
private const string NeedFlushMessage = "Error: nn::fs::CloseFile() failed because the file was not flushed.\n";
|
||||
|
@ -24,8 +29,7 @@ internal class FileAccessor : IDisposable
|
|||
private WriteState _writeState;
|
||||
private Result _lastResult;
|
||||
private OpenMode _openMode;
|
||||
private FilePathHash _filePathHash;
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private Box<FilePathHash> _filePathHash;
|
||||
private int _pathHashIndex;
|
||||
|
||||
internal HorizonClient Hos { get; }
|
||||
|
@ -59,7 +63,7 @@ internal class FileAccessor : IDisposable
|
|||
public WriteState GetWriteState() => _writeState;
|
||||
public FileSystemAccessor GetParent() => _parentFileSystem;
|
||||
|
||||
public void SetFilePathHash(FilePathHash filePathHash, int index)
|
||||
public void SetFilePathHash(Box<FilePathHash> filePathHash, int index)
|
||||
{
|
||||
_filePathHash = filePathHash;
|
||||
_pathHashIndex = index;
|
||||
|
@ -73,18 +77,18 @@ internal class FileAccessor : IDisposable
|
|||
return result;
|
||||
}
|
||||
|
||||
public Result ReadWithoutCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||
in ReadOption option)
|
||||
{
|
||||
return _file.Get.Read(out bytesRead, offset, destination, in option);
|
||||
}
|
||||
|
||||
private Result ReadWithCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||
in ReadOption option, bool usePathCache, bool useDataCache)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ReadWithoutCacheAccessLog(out long bytesRead, long offset, Span<byte> destination,
|
||||
in ReadOption option)
|
||||
{
|
||||
return _file.Get.Read(out bytesRead, offset, destination, in option);
|
||||
}
|
||||
|
||||
public Result Read(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out bytesRead);
|
||||
|
@ -113,42 +117,36 @@ internal class FileAccessor : IDisposable
|
|||
return _lastResult;
|
||||
}
|
||||
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
||||
bool usePathCache = _parentFileSystem is not null && _filePathHash.Data != 0;
|
||||
bool usePathCache = _parentFileSystem is not null && _filePathHash is not null;
|
||||
bool useDataCache = Hos.Fs.Impl.IsGlobalFileDataCacheEnabled() && _parentFileSystem is not null &&
|
||||
_parentFileSystem.IsFileDataCacheAttachable();
|
||||
|
||||
// Todo: Call IsGlobalFileDataCacheEnabled
|
||||
#pragma warning disable 162
|
||||
bool useDataCache = false && _parentFileSystem is not null && _parentFileSystem.IsFileDataCacheAttachable();
|
||||
#pragma warning restore 162
|
||||
if (usePathCache || useDataCache)
|
||||
{
|
||||
return ReadWithCacheAccessLog(out bytesRead, offset, destination, in option, usePathCache,
|
||||
useDataCache);
|
||||
}
|
||||
|
||||
if (Hos.Fs.Impl.IsEnabledAccessLog() && Hos.Fs.Impl.IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
Tick start = Hos.Os.GetSystemTick();
|
||||
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
||||
Tick end = Hos.Os.GetSystemTick();
|
||||
|
||||
var sb = new U8StringBuilder(logBuffer, true);
|
||||
sb.Append(LogOffset).AppendFormat(offset)
|
||||
.Append(LogSize).AppendFormat(destination.Length)
|
||||
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
||||
|
||||
Hos.Fs.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
||||
nameof(UserFile.ReadFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Hos.Fs.Impl.IsEnabledAccessLog() && Hos.Fs.Impl.IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
Tick start = Hos.Os.GetSystemTick();
|
||||
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
||||
Tick end = Hos.Os.GetSystemTick();
|
||||
|
||||
var sb = new U8StringBuilder(logBuffer, true);
|
||||
sb.Append(LogOffset).AppendFormat(offset)
|
||||
.Append(LogSize).AppendFormat(destination.Length)
|
||||
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
||||
|
||||
Hos.Fs.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
||||
nameof(UserFile.ReadFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
||||
}
|
||||
|
||||
return rc;
|
||||
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
||||
}
|
||||
// ReSharper restore ConditionIsAlwaysTrueOrFalse
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
public Result Write(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||
|
@ -159,9 +157,11 @@ internal class FileAccessor : IDisposable
|
|||
using ScopedSetter<WriteState> setter =
|
||||
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
||||
|
||||
if (_filePathHash.Data != 0)
|
||||
if (_filePathHash is not null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result rc = UpdateLastResult(Hos.Fs.Impl.WriteViaPathBasedFileDataCache(_file.Get, (int)GetOpenMode(),
|
||||
_parentFileSystem, in _filePathHash.Value, _pathHashIndex, offset, source, in option));
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -193,19 +193,27 @@ internal class FileAccessor : IDisposable
|
|||
if (_lastResult.IsFailure())
|
||||
return _lastResult;
|
||||
|
||||
WriteState oldWriteState = _writeState;
|
||||
WriteState originalWriteState = _writeState;
|
||||
using ScopedSetter<WriteState> setter =
|
||||
ScopedSetter<WriteState>.MakeScopedSetter(ref _writeState, WriteState.Failed);
|
||||
|
||||
Result rc = UpdateLastResult(_file.Get.SetSize(size));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (_filePathHash.Data != 0)
|
||||
if (_filePathHash is not null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
|
||||
Result rc = UpdateLastResult(_file.Get.SetSize(size));
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntry(_parentFileSystem, in _filePathHash.Value, _pathHashIndex);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
}
|
||||
else
|
||||
{
|
||||
Result rc = UpdateLastResult(_file.Get.SetSize(size));
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
setter.Set(oldWriteState);
|
||||
setter.Set(originalWriteState);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -224,4 +232,4 @@ internal class FileAccessor : IDisposable
|
|||
{
|
||||
return _file.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.Os;
|
||||
using LibHac.Util;
|
||||
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
||||
|
@ -10,6 +11,13 @@ using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
|||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to a mounted <see cref="IFileSystem"/> and contains metadata and objects related to it.
|
||||
/// This data includes the mount name, open files and directories, whether the access log is enabled for this file
|
||||
/// system, whether caching is being used, how to get a save file system's <see cref="SaveDataAttribute"/> and
|
||||
/// the target used to include a save file system in a multi-commit operation.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class FileSystemAccessor : IDisposable
|
||||
{
|
||||
private const string EmptyMountNameMessage = "Error: Mount failed because the mount name was empty.\n";
|
||||
|
@ -31,7 +39,7 @@ internal class FileSystemAccessor : IDisposable
|
|||
private bool _isPathCacheAttached;
|
||||
private IMultiCommitTarget _multiCommitTarget;
|
||||
private PathFlags _pathFlags;
|
||||
private Optional<Ncm.DataId> _dataId;
|
||||
private IStorage _storageForPurgeFileDataCache;
|
||||
|
||||
internal HorizonClient Hos { get; }
|
||||
|
||||
|
@ -44,7 +52,7 @@ internal class FileSystemAccessor : IDisposable
|
|||
_fileSystem = new UniqueRef<IFileSystem>(ref fileSystem);
|
||||
_openFiles = new LinkedList<FileAccessor>();
|
||||
_openDirectories = new LinkedList<DirectoryAccessor>();
|
||||
_openListLock.Initialize();
|
||||
_openListLock = new SdkMutexType();
|
||||
_mountNameGenerator = new UniqueRef<ICommonMountNameGenerator>(ref mountNameGenerator);
|
||||
_saveDataAttributeGetter = new UniqueRef<ISaveDataAttributeGetter>(ref saveAttributeGetter);
|
||||
_multiCommitTarget = multiCommitTarget;
|
||||
|
@ -90,7 +98,8 @@ internal class FileSystemAccessor : IDisposable
|
|||
|
||||
if (_isPathCacheAttached)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntries(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +122,16 @@ internal class FileSystemAccessor : IDisposable
|
|||
}
|
||||
|
||||
public void SetAccessLog(bool isEnabled) => _isAccessLogEnabled = isEnabled;
|
||||
public void SetFileDataCacheAttachable(bool isAttachable) => _isDataCacheAttachable = isAttachable;
|
||||
|
||||
public void SetFileDataCacheAttachable(bool isAttachable, IStorage storageForPurgeFileDataCache)
|
||||
{
|
||||
if (isAttachable)
|
||||
Assert.SdkAssert(storageForPurgeFileDataCache is not null);
|
||||
|
||||
_isDataCacheAttachable = isAttachable;
|
||||
_storageForPurgeFileDataCache = storageForPurgeFileDataCache;
|
||||
}
|
||||
|
||||
public void SetPathBasedFileDataCacheAttachable(bool isAttachable) => _isPathCacheAttachable = isAttachable;
|
||||
|
||||
public bool IsEnabledAccessLog() => _isAccessLogEnabled;
|
||||
|
@ -126,10 +144,7 @@ internal class FileSystemAccessor : IDisposable
|
|||
_isPathCacheAttached = true;
|
||||
}
|
||||
|
||||
public Optional<Ncm.DataId> GetDataId() => _dataId;
|
||||
public void SetDataId(Optional<Ncm.DataId> dataId) => _dataId = dataId;
|
||||
|
||||
public Result SetUpPath(ref Path path, U8Span pathBuffer)
|
||||
private Result SetUpPath(ref Path path, U8Span pathBuffer)
|
||||
{
|
||||
Result rc = PathFormatter.IsNormalized(out bool isNormalized, out _, pathBuffer, _pathFlags);
|
||||
|
||||
|
@ -168,7 +183,12 @@ internal class FileSystemAccessor : IDisposable
|
|||
|
||||
if (_isPathCacheAttached)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
|
||||
rc = _fileSystem.Get.CreateFile(in pathNormalized, size, option);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntry(this, in pathNormalized);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -251,7 +271,12 @@ internal class FileSystemAccessor : IDisposable
|
|||
|
||||
if (_isPathCacheAttached)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
|
||||
rc = _fileSystem.Get.RenameFile(in currentPathNormalized, in newPathNormalized);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntry(this, in newPathNormalized);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -274,7 +299,12 @@ internal class FileSystemAccessor : IDisposable
|
|||
|
||||
if (_isPathCacheAttached)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
|
||||
rc = _fileSystem.Get.RenameDirectory(in currentPathNormalized, in newPathNormalized);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntries(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -347,11 +377,17 @@ internal class FileSystemAccessor : IDisposable
|
|||
{
|
||||
if (mode.HasFlag(OpenMode.AllowAppend))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using UniqueLock lk = Hos.Fs.Impl.LockPathBasedFileDataCacheEntries();
|
||||
Hos.Fs.Impl.InvalidatePathBasedFileDataCacheEntry(this, in pathNormalized);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var hash = new Box<FilePathHash>();
|
||||
|
||||
if (Hos.Fs.Impl.FindPathBasedFileDataCacheEntry(out hash.Value, out int hashIndex, this, in pathNormalized))
|
||||
{
|
||||
accessor.SetFilePathHash(hash, hashIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,6 +468,13 @@ internal class FileSystemAccessor : IDisposable
|
|||
return Result.Success;
|
||||
}
|
||||
|
||||
public void PurgeFileDataCache(FileDataCacheAccessor accessor)
|
||||
{
|
||||
Assert.SdkAssert(_storageForPurgeFileDataCache is not null);
|
||||
|
||||
accessor.Purge(_storageForPurgeFileDataCache);
|
||||
}
|
||||
|
||||
public U8Span GetName()
|
||||
{
|
||||
return new U8Span(_mountName.Name);
|
||||
|
@ -470,11 +513,6 @@ internal class FileSystemAccessor : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void PurgeFileDataCache(FileDataCacheAccessor cacheAccessor)
|
||||
{
|
||||
cacheAccessor.Purge(_fileSystem.Get);
|
||||
}
|
||||
|
||||
internal void NotifyCloseFile(FileAccessor file)
|
||||
{
|
||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _openListLock);
|
||||
|
@ -673,4 +711,4 @@ internal class FileSystemAccessor : IDisposable
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Os;
|
||||
using LibHac.Util;
|
||||
|
||||
|
@ -14,7 +13,7 @@ namespace LibHac.Fs.Impl;
|
|||
/// Holds a list of <see cref="FileSystemAccessor"/>s that are indexed by their name.
|
||||
/// These may be retrieved or removed using their name as a key.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class MountTable : IDisposable
|
||||
{
|
||||
private LinkedList<FileSystemAccessor> _fileSystemList;
|
||||
|
@ -76,9 +75,11 @@ internal class MountTable : IDisposable
|
|||
currentNode is not null;
|
||||
currentNode = currentNode.Next)
|
||||
{
|
||||
if (!Matches(currentNode.Value, name)) continue;
|
||||
accessor = currentNode.Value;
|
||||
return Result.Success;
|
||||
if (Matches(currentNode.Value, name))
|
||||
{
|
||||
accessor = currentNode.Value;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultFs.NotMounted.Log();
|
||||
|
@ -121,44 +122,4 @@ internal class MountTable : IDisposable
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetDataIdCount()
|
||||
{
|
||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
|
||||
currentNode is not null;
|
||||
currentNode = currentNode.Next)
|
||||
{
|
||||
if (currentNode.Value.GetDataId().HasValue)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public Result ListDataId(out int dataIdCount, Span<DataId> dataIdBuffer)
|
||||
{
|
||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
|
||||
currentNode is not null && count < dataIdBuffer.Length;
|
||||
currentNode = currentNode.Next)
|
||||
{
|
||||
Optional<DataId> dataId = currentNode.Value.GetDataId();
|
||||
|
||||
if (dataId.HasValue)
|
||||
{
|
||||
dataIdBuffer[count] = dataId.Value;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
dataIdCount = count;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
|
@ -97,9 +97,9 @@ public static class Registrar
|
|||
if (!accessor.HasValue)
|
||||
return ResultFs.AllocationMemoryFailedInRegisterB.Log();
|
||||
|
||||
accessor.Get.SetFileDataCacheAttachable(useDataCache);
|
||||
// accessor.Get.SetFileDataCacheAttachable(useDataCache);
|
||||
accessor.Get.SetPathBasedFileDataCacheAttachable(usePathCache);
|
||||
accessor.Get.SetDataId(dataId);
|
||||
// accessor.Get.SetDataId(dataId);
|
||||
|
||||
Result rc = fs.Impl.Register(ref accessor.Ref());
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
@ -111,4 +111,4 @@ public static class Registrar
|
|||
{
|
||||
fs.Impl.Unregister(name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.Ncm;
|
||||
|
||||
namespace LibHac.Fs.Fsa;
|
||||
|
||||
|
@ -18,7 +16,7 @@ internal struct UserMountTableGlobals
|
|||
/// <summary>
|
||||
/// Contains functions for adding, removing and retrieving <see cref="FileSystemAccessor"/>s from the mount table.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal static class UserMountTable
|
||||
{
|
||||
public static Result Register(this FileSystemClientImpl fs, ref UniqueRef<FileSystemAccessor> fileSystem)
|
||||
|
@ -35,15 +33,4 @@ internal static class UserMountTable
|
|||
{
|
||||
fs.Globals.UserMountTable.MountTable.Unmount(name);
|
||||
}
|
||||
|
||||
public static int GetMountedDataIdCount(this FileSystemClientImpl fs)
|
||||
{
|
||||
return fs.Globals.UserMountTable.MountTable.GetDataIdCount();
|
||||
}
|
||||
|
||||
public static Result ListMountedDataId(this FileSystemClientImpl fs, out int dataIdCount,
|
||||
Span<DataId> dataIdBuffer)
|
||||
{
|
||||
return fs.Globals.UserMountTable.MountTable.ListDataId(out dataIdCount, dataIdBuffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,9 +3,13 @@ using LibHac.Fs.Fsa;
|
|||
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to an <see cref="IFileDataCache"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class FileDataCacheAccessor
|
||||
{
|
||||
private IFileDataCache _cache;
|
||||
private readonly IFileDataCache _cache;
|
||||
|
||||
public FileDataCacheAccessor(IFileDataCache cache)
|
||||
{
|
||||
|
@ -18,8 +22,8 @@ internal class FileDataCacheAccessor
|
|||
return _cache.Read(file, out bytesRead, offset, destination, in option, ref cacheAccessResult);
|
||||
}
|
||||
|
||||
public void Purge(IFileSystem fileSystem)
|
||||
public void Purge(IStorage storage)
|
||||
{
|
||||
_cache.Purge(fileSystem);
|
||||
_cache.Purge(storage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
namespace LibHac.Fs.Impl;
|
||||
using LibHac.Common.FixedArrays;
|
||||
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
public struct FilePathHash
|
||||
{
|
||||
public int Data;
|
||||
}
|
||||
public Array4<byte> Data;
|
||||
}
|
|
@ -7,11 +7,15 @@ using LibHac.Fs.Fsa;
|
|||
namespace LibHac.Fs.Impl;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
/// <summary>
|
||||
/// Provides a system for caching reads to one or more file systems.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal abstract class IFileDataCache : IDisposable
|
||||
{
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract void Purge(IFileSystem fileSystem);
|
||||
public abstract void Purge(IStorage storage);
|
||||
|
||||
protected abstract Result DoRead(IFile file, out long bytesRead, long offset, Span<byte> destination,
|
||||
in ReadOption option, ref FileDataCacheAccessResult cacheAccessResult);
|
||||
|
@ -88,4 +92,4 @@ internal struct FileDataCacheAccessResult
|
|||
_regionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
183
src/LibHac/Fs/Shim/FileDataCache.cs
Normal file
183
src/LibHac/Fs/Shim/FileDataCache.cs
Normal file
|
@ -0,0 +1,183 @@
|
|||
// ReSharper disable UnusedMember.Local
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.Os;
|
||||
|
||||
namespace LibHac.Fs.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles getting scoped read access to the global file data cache.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal struct GlobalFileDataCacheAccessorReadableScopedPointer : IDisposable
|
||||
{
|
||||
private FileDataCacheAccessor _accessor;
|
||||
private ReaderWriterLock _lock;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_lock?.ReleaseReadLock();
|
||||
}
|
||||
|
||||
public readonly FileDataCacheAccessor Get() => _accessor;
|
||||
|
||||
public void Set(FileDataCacheAccessor accessor, ReaderWriterLock rwLock)
|
||||
{
|
||||
if (_lock is not null && _lock != rwLock)
|
||||
_lock.ReleaseReadLock();
|
||||
|
||||
_accessor = accessor;
|
||||
_lock = rwLock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
public static class FileDataCacheShim
|
||||
{
|
||||
internal struct Globals : IDisposable
|
||||
{
|
||||
public nint FileSystemProxyServiceObjectInitGuard;
|
||||
public GlobalFileDataCacheAccessorHolder GlobalFileDataCacheAccessorHolder;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GlobalFileDataCacheAccessorHolder.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal class GlobalFileDataCacheAccessorHolder
|
||||
{
|
||||
private FileDataCacheAccessor _accessor;
|
||||
private ReaderWriterLock _accessorLock;
|
||||
private long _cacheSize;
|
||||
private bool _isDefault;
|
||||
|
||||
public GlobalFileDataCacheAccessorHolder(HorizonClient hos)
|
||||
{
|
||||
_accessorLock = new ReaderWriterLock(hos.Os);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_accessorLock?.Dispose();
|
||||
}
|
||||
|
||||
public ReaderWriterLock GetLock() => _accessorLock;
|
||||
|
||||
public bool HasAccessor()
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsReadLockHeld() || _accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
|
||||
return _accessor is not null;
|
||||
}
|
||||
|
||||
public void SetAccessor()
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
|
||||
_accessor = null;
|
||||
}
|
||||
|
||||
public void SetAccessor(FileDataCacheAccessor accessor, long cacheSize, bool isDefault)
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
|
||||
_accessor = accessor;
|
||||
_cacheSize = cacheSize;
|
||||
_isDefault = isDefault;
|
||||
}
|
||||
|
||||
public FileDataCacheAccessor GetAccessor()
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsReadLockHeld() || _accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
|
||||
return _accessor;
|
||||
}
|
||||
|
||||
public long GetCacheSize()
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsReadLockHeld() || _accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
|
||||
return _cacheSize;
|
||||
}
|
||||
|
||||
public bool IsDefaultGlobalFileDataCache()
|
||||
{
|
||||
Assert.SdkAssert(_accessorLock.IsReadLockHeld() || _accessorLock.IsWriteLockHeldByCurrentThread());
|
||||
Assert.SdkNotNull(_accessor);
|
||||
|
||||
return _isDefault;
|
||||
}
|
||||
}
|
||||
|
||||
private static GlobalFileDataCacheAccessorHolder GetGlobalFileDataCacheAccessorHolder(FileSystemClient fs)
|
||||
{
|
||||
ref Globals g = ref fs.Globals.FileDataCache;
|
||||
using var guard = new InitializationGuard(ref g.FileSystemProxyServiceObjectInitGuard,
|
||||
fs.Globals.InitMutex);
|
||||
|
||||
if (!guard.IsInitialized)
|
||||
{
|
||||
g.GlobalFileDataCacheAccessorHolder = new GlobalFileDataCacheAccessorHolder(fs.Hos);
|
||||
}
|
||||
|
||||
return g.GlobalFileDataCacheAccessorHolder;
|
||||
}
|
||||
|
||||
private static Result EnableGlobalFileDataCacheImpl(FileSystemClient fs, Memory<byte> buffer, bool isDefault)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static Result DisableGlobalFileDataCacheImpl(FileSystemClient fs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static int PrintDefaultGlobalFileDataCacheAccessLog(Span<byte> textBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static bool IsGlobalFileDataCacheEnabled(this FileSystemClientImpl fs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool TryGetGlobalFileDataCacheAccessor(this FileSystemClientImpl fs,
|
||||
ref GlobalFileDataCacheAccessorReadableScopedPointer scopedPointer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static void SetGlobalFileDataCacheAccessorForDebug(this FileSystemClientImpl fs,
|
||||
FileDataCacheAccessor accessor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void EnableGlobalFileDataCache(this FileSystemClient fs, Memory<byte> buffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void DisableGlobalFileDataCache(this FileSystemClient fs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void EnableDefaultGlobalFileDataCache(this FileSystemClient fs, Memory<byte> buffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool IsDefaultGlobalFileDataCacheEnabled(this FileSystemClient fs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
62
src/LibHac/Fs/Shim/PathBasedFileDataCache.cs
Normal file
62
src/LibHac/Fs/Shim/PathBasedFileDataCache.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
|
||||
namespace LibHac.Fs.Shim;
|
||||
|
||||
public static class PathBasedFileDataCacheShim
|
||||
{
|
||||
internal static UniqueLock LockPathBasedFileDataCacheEntries(this FileSystemClientImpl fs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static void InvalidatePathBasedFileDataCacheEntries(this FileSystemClientImpl fs,
|
||||
FileSystemAccessor fsAccessor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static void InvalidatePathBasedFileDataCacheEntry(this FileSystemClientImpl fs,
|
||||
FileSystemAccessor fsAccessor, in Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static void InvalidatePathBasedFileDataCacheEntry(this FileSystemClientImpl fs,
|
||||
FileSystemAccessor fsAccessor, in FilePathHash hash, int hashIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static bool FindPathBasedFileDataCacheEntry(this FileSystemClientImpl fs, out FilePathHash outHash,
|
||||
out int outHashIndex, FileSystemAccessor fsAccessor, in Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static Result ReadViaPathBasedFileDataCache(this FileSystemClientImpl fs, IFile file, int openMode,
|
||||
FileSystemAccessor fileSystem, in FilePathHash hash, int hashIndex, out long bytesRead, long offset,
|
||||
Span<byte> buffer, in ReadOption option, ref FileDataCacheAccessResult outCacheAccessResult)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static Result WriteViaPathBasedFileDataCache(this FileSystemClientImpl fs, IFile file, int openMode,
|
||||
FileSystemAccessor fileSystem, in FilePathHash hash, int hashIndex, long offset, ReadOnlySpan<byte> buffer,
|
||||
in WriteOption option)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Result EnableIndividualFileDataCache(this FileSystemClient fs, U8Span path, Memory<byte> buffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void DisableIndividualFileDataCache(this FileSystemClient fs, U8Span path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -98,7 +98,7 @@ public static class ReaderWriterLockApi
|
|||
}
|
||||
}
|
||||
|
||||
public class ReaderWriterLock : ISharedMutex
|
||||
public class ReaderWriterLock : ISharedMutex, IDisposable
|
||||
{
|
||||
public const int ReaderWriterLockCountMax = (1 << 15) - 1;
|
||||
public const int ReadWriteLockWaiterCountMax = (1 << 8) - 1;
|
||||
|
@ -112,6 +112,11 @@ public class ReaderWriterLock : ISharedMutex
|
|||
_os.InitializeReaderWriterLock(ref _rwLock);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_os.FinalizeReaderWriterLock(ref _rwLock);
|
||||
}
|
||||
|
||||
public void AcquireReadLock()
|
||||
{
|
||||
_os.AcquireReadLock(ref _rwLock);
|
||||
|
@ -191,4 +196,4 @@ public class ReaderWriterLock : ISharedMutex
|
|||
{
|
||||
return ref _rwLock;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue