From 45975ddadd88c6760726691fd418eda412a98353 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 9 Mar 2024 18:38:04 -0700 Subject: [PATCH] Implement ApplicationTemporaryFileSystem --- build/CodeGen/results.csv | 1 + src/LibHac/Fs/ResultFs.cs | 2 + .../ApplicationTemporaryFileSystem.cs | 141 +++++++++++++----- .../Save/IntegritySaveDataFileSystemDriver.cs | 2 +- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/build/CodeGen/results.csv b/build/CodeGen/results.csv index 520d2e68..f6eeebe6 100644 --- a/build/CodeGen/results.csv +++ b/build/CodeGen/results.csv @@ -1069,6 +1069,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,6396,,,,UnsupportedRollbackOnlyModifiedForDirectorySaveDataFileSystem, 2,6397,,,,UnsupportedOperateRangeForRegionSwitchStorage, 2,6398,,,,UnsupportedOperateRangeForSaveDataFile, +2,6399,,,,UnsupportedOperateRangeForApplicationTemporaryFile, 2,6400,6449,,,PermissionDenied, 2,6403,,,,HostFileSystemOperationDisabled,Returned when opening a host FS on a retail device. diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index ad9fb24f..b6b9cdc5 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -1962,6 +1962,8 @@ public static class ResultFs public static Result.Base UnsupportedOperateRangeForRegionSwitchStorage => new Result.Base(ModuleFs, 6397); /// Error code: 2002-6398; Inner value: 0x31fc02 public static Result.Base UnsupportedOperateRangeForSaveDataFile => new Result.Base(ModuleFs, 6398); + /// Error code: 2002-6399; Inner value: 0x31fe02 + public static Result.Base UnsupportedOperateRangeForApplicationTemporaryFile => new Result.Base(ModuleFs, 6399); /// Error code: 2002-6400; Range: 6400-6449; Inner value: 0x320002 public static Result.Base PermissionDenied { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6400, 6449); } diff --git a/src/LibHac/FsSystem/ApplicationTemporaryFileSystem.cs b/src/LibHac/FsSystem/ApplicationTemporaryFileSystem.cs index 0629c0f1..a3a61a29 100644 --- a/src/LibHac/FsSystem/ApplicationTemporaryFileSystem.cs +++ b/src/LibHac/FsSystem/ApplicationTemporaryFileSystem.cs @@ -1,7 +1,9 @@ // ReSharper disable UnusedMember.Local UnusedType.Local #pragma warning disable CS0169 // Field is never used using System; +using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Diag; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem.Save; @@ -14,43 +16,75 @@ file class ApplicationTemporaryFile : IFile public ApplicationTemporaryFile(ref UniqueRef file) { - throw new NotImplementedException(); + _file = new UniqueRef(ref file); + + Assert.SdkRequiresNotNull(in _file); } public override void Dispose() { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + _file.Destroy(); + base.Dispose(); } protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + Result res = _file.Get.Read(out bytesRead, offset, destination); + + if (res.IsFailure()) + { + if (ResultFs.InvalidSaveDataFileReadOffset.Includes(res)) + { + return ResultFs.OutOfRange.LogConverted(res); + } + + return res.Miss(); + } + + return Result.Success; } protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + return _file.Get.Write(offset, source, in option).Ret(); } protected override Result DoFlush() { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + return _file.Get.Flush().Ret(); } protected override Result DoSetSize(long size) { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + return _file.Get.SetSize(size).Ret(); } protected override Result DoGetSize(out long size) { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + return _file.Get.GetSize(out size).Ret(); } protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) { - throw new NotImplementedException(); + Assert.SdkRequiresNotNull(in _file); + + if (operationId == OperationId.InvalidateCache) + return ResultFs.UnsupportedOperateRangeForApplicationTemporaryFile.Log(); + + return _file.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer).Ret(); } } @@ -65,140 +99,177 @@ public class ApplicationTemporaryFileSystem : ISaveDataFileSystem, ISaveDataExtr public ApplicationTemporaryFileSystem() { - throw new NotImplementedException(); + _baseStorage = new SharedRef(); + _saveFsDriver = new IntegritySaveDataFileSystemDriver(); + _isInitialized = false; + _cacheObserver = null; } public override void Dispose() { - throw new NotImplementedException(); + if (_isInitialized) + { + _saveFsDriver.Commit().IgnoreResult(); + _saveFsDriver.FinalizeObject(); + _cacheObserver?.Unregister(_spaceId, _saveDataId); + + _isInitialized = false; + } + + _saveFsDriver.Dispose(); + _baseStorage.Destroy(); + base.Dispose(); } public Result Initialize(IStorage baseStorage, IBufferManager bufferManager, IMacGenerator macGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector) { - throw new NotImplementedException(); + Result res = baseStorage.GetSize(out long size); + if (res.IsFailure()) return res.Miss(); + + using var baseSubStorage = new ValueSubStorage(baseStorage, 0, size); + res = _saveFsDriver.Initialize(in baseSubStorage, bufferManager, macGenerator, hashGeneratorFactorySelector); + if (res.IsFailure()) return res.Miss(); + + _isInitialized = true; + + return Result.Success; } public Result Initialize(ref readonly SharedRef baseStorage, IBufferManager bufferManager, IMacGenerator macGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector) { - throw new NotImplementedException(); + _baseStorage.SetByCopy(in baseStorage); + + return Initialize(_baseStorage.Get, bufferManager, macGenerator, hashGeneratorFactorySelector).Ret(); } protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option) { - throw new NotImplementedException(); + return _saveFsDriver.CreateFile(in path, size, option).Ret(); } protected override Result DoDeleteFile(ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.DeleteFile(in path).Ret(); } protected override Result DoCreateDirectory(ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.CreateDirectory(in path).Ret(); } protected override Result DoDeleteDirectory(ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.DeleteDirectory(in path).Ret(); } protected override Result DoDeleteDirectoryRecursively(ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.DeleteDirectoryRecursively(in path).Ret(); } protected override Result DoCleanDirectoryRecursively(ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.CleanDirectoryRecursively(in path).Ret(); } protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath) { - throw new NotImplementedException(); + return _saveFsDriver.RenameFile(in currentPath, in newPath).Ret(); } protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath) { - throw new NotImplementedException(); + return _saveFsDriver.RenameDirectory(in currentPath, in newPath).Ret(); } protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.GetEntryType(out entryType, in path).Ret(); } protected override Result DoOpenFile(ref UniqueRef outFile, ref readonly Path path, OpenMode mode) { - throw new NotImplementedException(); + using var file = new UniqueRef(); + Result res = _saveFsDriver.OpenFile(ref file.Ref, in path, mode); + if (res.IsFailure()) return res.Miss(); + + using var wrapperFile = new UniqueRef(new ApplicationTemporaryFile(ref file.Ref)); + + outFile.Set(ref wrapperFile.Ref); + return Result.Success; } protected override Result DoOpenDirectory(ref UniqueRef outDirectory, ref readonly Path path, OpenDirectoryMode mode) { - throw new NotImplementedException(); + return _saveFsDriver.OpenDirectory(ref outDirectory, in path, mode).Ret(); } protected override Result DoCommit() { - throw new NotImplementedException(); + return _saveFsDriver.Commit().Ret(); } protected override Result DoCommitProvisionally(long counter) { - throw new NotImplementedException(); + return ResultFs.UnsupportedCommitProvisionallyForApplicationTemporaryFileSystem.Log(); } protected override Result DoRollback() { - throw new NotImplementedException(); + return Result.Success; } protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.GetFreeSpaceSize(out freeSpace, in path).Ret(); } protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path) { - throw new NotImplementedException(); + return _saveFsDriver.GetTotalSpaceSize(out totalSpace, in path).Ret(); } public override bool IsSaveDataFileSystemCacheEnabled() { - throw new NotImplementedException(); + return false; } public override Result RollbackOnlyModified() { - throw new NotImplementedException(); + return ResultFs.UnsupportedRollbackOnlyModifiedForApplicationTemporaryFileSystem.Log(); } protected override Result DoGetFileSystemAttribute(out FileSystemAttribute outAttribute) { - throw new NotImplementedException(); + return _saveFsDriver.GetFileSystemAttribute(out outAttribute).Ret(); } public override Result WriteExtraData(in SaveDataExtraData extraData) { - throw new NotImplementedException(); + return _saveFsDriver.WriteExtraData(in Unsafe.As(ref Unsafe.AsRef(in extraData))).Ret(); } public override Result CommitExtraData(bool updateTimeStamp) { - throw new NotImplementedException(); + return DoCommit().Ret(); } public override Result ReadExtraData(out SaveDataExtraData extraData) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out extraData); + _saveFsDriver.ReadExtraData(out Unsafe.As(ref extraData)); + + return Result.Success; } public override void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId, ulong saveDataId) { - throw new NotImplementedException(); + _cacheObserver = observer; + _spaceId = spaceId; + _saveDataId = saveDataId; } } \ No newline at end of file diff --git a/src/LibHac/FsSystem/Save/IntegritySaveDataFileSystemDriver.cs b/src/LibHac/FsSystem/Save/IntegritySaveDataFileSystemDriver.cs index 751443df..9b257ce3 100644 --- a/src/LibHac/FsSystem/Save/IntegritySaveDataFileSystemDriver.cs +++ b/src/LibHac/FsSystem/Save/IntegritySaveDataFileSystemDriver.cs @@ -66,7 +66,7 @@ public class IntegritySaveDataFileSystemDriver : ProxyFileSystemWithRetryingBuff throw new NotImplementedException(); } - public void WriteExtraData(in IntegritySaveDataFileSystem.ExtraData extraData) + public Result WriteExtraData(in IntegritySaveDataFileSystem.ExtraData extraData) { throw new NotImplementedException(); }