diff --git a/src/LibHac/Fs/Fsa/Registrar.cs b/src/LibHac/Fs/Fsa/Registrar.cs index 1a2e06f0..5ac0b76a 100644 --- a/src/LibHac/Fs/Fsa/Registrar.cs +++ b/src/LibHac/Fs/Fsa/Registrar.cs @@ -1,7 +1,7 @@ using System; using LibHac.Common; +using LibHac.Diag; using LibHac.Fs.Impl; -using LibHac.Util; namespace LibHac.Fs.Fsa; @@ -15,12 +15,93 @@ public interface ISaveDataAttributeGetter : IDisposable Result GetSaveDataAttribute(out SaveDataAttribute attribute); } +public interface IUnmountHookInvoker : IDisposable +{ + void Invoke(); +} + /// /// Contains functions for registering and unregistering mounted s. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) public static class Registrar { + private class UnmountHookFileSystem : IFileSystem + { + private UniqueRef _fileSystem; + private UniqueRef _unmountHookInvoker; + + public UnmountHookFileSystem(ref UniqueRef fileSystem, + ref UniqueRef unmountHookInvoker) + { + _fileSystem = new UniqueRef(ref fileSystem); + _unmountHookInvoker = new UniqueRef(ref unmountHookInvoker); + } + + public override void Dispose() + { + if (_unmountHookInvoker.HasValue) + _unmountHookInvoker.Get.Invoke(); + + _unmountHookInvoker.Destroy(); + _fileSystem.Destroy(); + + base.Dispose(); + } + + protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) => + _fileSystem.Get.CreateFile(in path, size, option); + + protected override Result DoDeleteFile(in Path path) => _fileSystem.Get.DeleteFile(in path); + + protected override Result DoCreateDirectory(in Path path) => _fileSystem.Get.CreateDirectory(in path); + + protected override Result DoDeleteDirectory(in Path path) => _fileSystem.Get.DeleteDirectory(in path); + + protected override Result DoDeleteDirectoryRecursively(in Path path) => + _fileSystem.Get.DeleteDirectoryRecursively(in path); + + protected override Result DoCleanDirectoryRecursively(in Path path) => + _fileSystem.Get.CleanDirectoryRecursively(in path); + + protected override Result DoRenameFile(in Path currentPath, in Path newPath) => + _fileSystem.Get.RenameFile(in currentPath, in newPath); + + protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) => + _fileSystem.Get.RenameDirectory(in currentPath, in newPath); + + protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) => + _fileSystem.Get.GetEntryType(out entryType, in path); + + protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) => + _fileSystem.Get.GetFreeSpaceSize(out freeSpace, in path); + + protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) => + _fileSystem.Get.GetTotalSpaceSize(out totalSpace, in path); + + protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) => + _fileSystem.Get.OpenFile(ref outFile, in path, mode); + + protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, + OpenDirectoryMode mode) => + _fileSystem.Get.OpenDirectory(ref outDirectory, in path, mode); + + protected override Result DoCommit() => _fileSystem.Get.Commit(); + + protected override Result DoCommitProvisionally(long counter) => + _fileSystem.Get.CommitProvisionally(counter); + + protected override Result DoRollback() => _fileSystem.Get.Rollback(); + + protected override Result DoFlush() => _fileSystem.Get.Flush(); + + protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path) => + _fileSystem.Get.GetFileTimeStampRaw(out timeStamp, in path); + + protected override Result DoQueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + in Path path) => _fileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, in path); + } + public static Result Register(this FileSystemClient fs, U8Span name, ref UniqueRef fileSystem) { using var attributeGetter = new UniqueRef(); @@ -51,12 +132,28 @@ public static class Registrar public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget, ref UniqueRef fileSystem, ref UniqueRef mountNameGenerator, - bool useDataCache, bool usePathCache) + bool useDataCache, IStorage storageForPurgeFileDataCache, bool usePathCache) + { + using var unmountHookInvoker = new UniqueRef(); + using var attributeGetter = new UniqueRef(); + + Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator, + ref attributeGetter.Ref(), useDataCache, storageForPurgeFileDataCache, usePathCache, + ref unmountHookInvoker.Ref()); + if (rc.IsFailure()) return rc.Miss(); + + return Result.Success; + } + + public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget, + ref UniqueRef fileSystem, ref UniqueRef mountNameGenerator, + bool useDataCache, IStorage storageForPurgeFileDataCache, bool usePathCache, + ref UniqueRef unmountHook) { using var attributeGetter = new UniqueRef(); Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator, - ref attributeGetter.Ref(), useDataCache, usePathCache, new Optional()); + ref attributeGetter.Ref(), useDataCache, storageForPurgeFileDataCache, usePathCache, ref unmountHook); if (rc.IsFailure()) return rc.Miss(); return Result.Success; @@ -64,12 +161,14 @@ public static class Registrar public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget, ref UniqueRef fileSystem, ref UniqueRef mountNameGenerator, - bool useDataCache, bool usePathCache, Optional dataId) + ref UniqueRef saveAttributeGetter, bool useDataCache, + IStorage storageForPurgeFileDataCache, bool usePathCache) { - using var attributeGetter = new UniqueRef(); + using var unmountHookInvoker = new UniqueRef(); Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator, - ref attributeGetter.Ref(), useDataCache, usePathCache, dataId); + ref saveAttributeGetter, useDataCache, storageForPurgeFileDataCache, usePathCache, + ref unmountHookInvoker.Ref()); if (rc.IsFailure()) return rc.Miss(); return Result.Success; @@ -77,29 +176,29 @@ public static class Registrar public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget, ref UniqueRef fileSystem, ref UniqueRef mountNameGenerator, - ref UniqueRef saveAttributeGetter, bool useDataCache, bool usePathCache) + ref UniqueRef saveAttributeGetter, bool useDataCache, + IStorage storageForPurgeFileDataCache, bool usePathCache, ref UniqueRef unmountHook) { - Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator, - ref saveAttributeGetter, useDataCache, usePathCache, new Optional()); - if (rc.IsFailure()) return rc.Miss(); + if (useDataCache) + Assert.SdkAssert(storageForPurgeFileDataCache is not null); - return Result.Success; - } + using (var unmountHookFileSystem = + new UniqueRef(new UnmountHookFileSystem(ref fileSystem, ref unmountHook))) + { + fileSystem.Set(ref unmountHookFileSystem.Ref()); + } + + if (!fileSystem.HasValue) + return ResultFs.AllocationMemoryFailedInRegisterB.Log(); - public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget, - ref UniqueRef fileSystem, ref UniqueRef mountNameGenerator, - ref UniqueRef saveAttributeGetter, bool useDataCache, bool usePathCache, - Optional dataId) - { using var accessor = new UniqueRef(new FileSystemAccessor(fs.Hos, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator, ref saveAttributeGetter)); if (!accessor.HasValue) return ResultFs.AllocationMemoryFailedInRegisterB.Log(); - // accessor.Get.SetFileDataCacheAttachable(useDataCache); + accessor.Get.SetFileDataCacheAttachable(useDataCache, storageForPurgeFileDataCache); accessor.Get.SetPathBasedFileDataCacheAttachable(usePathCache); - // accessor.Get.SetDataId(dataId); Result rc = fs.Impl.Register(ref accessor.Ref()); if (rc.IsFailure()) return rc.Miss(); diff --git a/src/LibHac/Fs/Shim/SaveData.cs b/src/LibHac/Fs/Shim/SaveData.cs index 704f58d6..9a11a4cd 100644 --- a/src/LibHac/Fs/Shim/SaveData.cs +++ b/src/LibHac/Fs/Shim/SaveData.cs @@ -50,7 +50,7 @@ public static class SaveData using var mountNameGenerator = new UniqueRef(); rc = fs.Fs.Register(mountName, fileSystemAdapterRaw, ref fileSystemAdapter.Ref(), - ref mountNameGenerator.Ref(), false, true); + ref mountNameGenerator.Ref(), false, null, true); if (rc.IsFailure()) return rc.Miss(); return Result.Success; @@ -291,4 +291,4 @@ public static class SaveData return rc; } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/SystemSaveData.cs b/src/LibHac/Fs/Shim/SystemSaveData.cs index c55c85c0..3de0cab7 100644 --- a/src/LibHac/Fs/Shim/SystemSaveData.cs +++ b/src/LibHac/Fs/Shim/SystemSaveData.cs @@ -87,7 +87,7 @@ public static class SystemSaveData { using var mountNameGenerator = new UniqueRef(); return fs.Register(mountName, fileSystemAdapterRaw, ref fileSystemAdapter.Ref(), - ref mountNameGenerator.Ref(), false, false); + ref mountNameGenerator.Ref(), false, null, false); } else { @@ -95,4 +95,4 @@ public static class SystemSaveData } } } -} +} \ No newline at end of file