From e24ee1b956ac893ef6d87051d603ae1d951e7c35 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 24 Apr 2022 16:51:51 -0700 Subject: [PATCH] Update IResultConvertFile and use the new save cache manager --- build/CodeGen/results.csv | 1 + src/LibHac/Fs/FsEnums.cs | 6 + src/LibHac/Fs/ResultFs.cs | 2 + .../FsCreator/ISaveDataFileSystemCreator.cs | 8 +- .../FsCreator/SaveDataFileSystemCreator.cs | 68 +++---- .../SaveDataResultConvertFileSystem.cs | 127 +++++++++++++ .../SaveDataResultConverter.cs} | 105 ++--------- .../Impl/SaveDataFileSystemCacheRegister.cs | 2 +- src/LibHac/FsSrv/Impl/SaveDataProperties.cs | 50 ++++- .../FsSrv/SaveDataFileSystemServiceImpl.cs | 128 +++++++------ .../IResultConvertFileSystem.cs | 104 ++++++----- .../ISaveDataFileSystemCacheManager.cs | 17 -- .../SaveDataFileSystemCacheManager.cs | 171 ------------------ .../SaveDataFileSystemCacheRegisterBase.cs | 132 -------------- .../FsSystem/SaveDataFileSystemHolder.cs | 59 ------ 15 files changed, 352 insertions(+), 628 deletions(-) create mode 100644 src/LibHac/FsSrv/FsCreator/SaveDataResultConvertFileSystem.cs rename src/LibHac/FsSrv/{Impl/SaveDataResultConvertFileSystem.cs => FsCreator/SaveDataResultConverter.cs} (58%) rename src/LibHac/{FsSrv/Impl => FsSystem}/IResultConvertFileSystem.cs (54%) delete mode 100644 src/LibHac/FsSystem/ISaveDataFileSystemCacheManager.cs delete mode 100644 src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs delete mode 100644 src/LibHac/FsSystem/SaveDataFileSystemCacheRegisterBase.cs delete mode 100644 src/LibHac/FsSystem/SaveDataFileSystemHolder.cs diff --git a/build/CodeGen/results.csv b/build/CodeGen/results.csv index bba44f13..9b30f760 100644 --- a/build/CodeGen/results.csv +++ b/build/CodeGen/results.csv @@ -672,6 +672,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,4301,4499,,,SaveDataCorrupted, 2,4302,,,,UnsupportedSaveDataVersion, 2,4303,,,,InvalidSaveDataEntryType, +2,4304,,,,ReconstructibleSaveDataCorrupted, 2,4311,4319,,,SaveDataFileSystemCorrupted, 2,4312,,,,InvalidJournalIntegritySaveDataHashSize, diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index dc10a21e..d0e2d0d7 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -170,6 +170,12 @@ public enum SaveDataRank : byte Secondary = 1 } +public enum SaveDataFormatType : byte +{ + Normal = 0, + NoJournal = 1 +} + [Flags] public enum SaveDataFlags { diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 047d884b..20ee475b 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -1210,6 +1210,8 @@ public static class ResultFs public static Result.Base UnsupportedSaveDataVersion => new Result.Base(ModuleFs, 4302); /// Error code: 2002-4303; Inner value: 0x219e02 public static Result.Base InvalidSaveDataEntryType => new Result.Base(ModuleFs, 4303); + /// Error code: 2002-4304; Inner value: 0x21a002 + public static Result.Base ReconstructibleSaveDataCorrupted => new Result.Base(ModuleFs, 4304); /// Error code: 2002-4311; Range: 4311-4319; Inner value: 0x21ae02 public static Result.Base SaveDataFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4311, 4319); } diff --git a/src/LibHac/FsSrv/FsCreator/ISaveDataFileSystemCreator.cs b/src/LibHac/FsSrv/FsCreator/ISaveDataFileSystemCreator.cs index ac66ca69..be6a6c27 100644 --- a/src/LibHac/FsSrv/FsCreator/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/ISaveDataFileSystemCreator.cs @@ -10,12 +10,10 @@ public interface ISaveDataFileSystemCreator { Result CreateFile(out IFile file, IFileSystem sourceFileSystem, ulong saveDataId, OpenMode openMode); - Result Create(ref SharedRef outFileSystem, - ref SharedRef outExtraDataAccessor, - ISaveDataFileSystemCacheManager cacheManager, ref SharedRef baseFileSystem, - SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, + Result Create(ref SharedRef outFileSystem, ref SharedRef baseFileSystem, + SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool isDeviceUniqueMac, bool isJournalingSupported, bool isMultiCommitSupported, bool openReadOnly, bool openShared, - ISaveDataCommitTimeStampGetter timeStampGetter); + ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible); Result CreateExtraDataAccessor(ref SharedRef outExtraDataAccessor, ref SharedRef baseFileSystem); diff --git a/src/LibHac/FsSrv/FsCreator/SaveDataFileSystemCreator.cs b/src/LibHac/FsSrv/FsCreator/SaveDataFileSystemCreator.cs index 86c0d922..ca94f92d 100644 --- a/src/LibHac/FsSrv/FsCreator/SaveDataFileSystemCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/SaveDataFileSystemCreator.cs @@ -3,12 +3,9 @@ using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Common.FixedArrays; using LibHac.Common.Keys; -using LibHac.Diag; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.Save; using LibHac.Util; using OpenType = LibHac.FsSrv.SaveDataOpenTypeSetFileStorage.OpenType; @@ -17,10 +14,15 @@ namespace LibHac.FsSrv.FsCreator; public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator { + // Option to disable some restrictions enforced in actual FS. + private static readonly bool EnforceSaveTypeRestrictions = false; + + // ReSharper disable once NotAccessedField.Local private IBufferManager _bufferManager; private RandomDataGenerator _randomGenerator; // LibHac Additions + // ReSharper disable once NotAccessedField.Local private KeySet _keySet; private FileSystemServer _fsServer; @@ -38,54 +40,56 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator throw new NotImplementedException(); } - public Result Create(ref SharedRef outFileSystem, - ref SharedRef outExtraDataAccessor, - ISaveDataFileSystemCacheManager cacheManager, ref SharedRef baseFileSystem, - SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, + public Result Create(ref SharedRef outFileSystem, ref SharedRef baseFileSystem, + SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool isDeviceUniqueMac, bool isJournalingSupported, bool isMultiCommitSupported, bool openReadOnly, bool openShared, - ISaveDataCommitTimeStampGetter timeStampGetter) + ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible) { Unsafe.SkipInit(out Array18 saveImageNameBuffer); - Assert.SdkRequiresNotNull(cacheManager); - using var saveImageName = new Path(); Result rc = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer.Items, saveDataId); - if (rc.IsFailure()) return rc; + if (rc.IsFailure()) return rc.Miss(); rc = baseFileSystem.Get.GetEntryType(out DirectoryEntryType type, in saveImageName); if (rc.IsFailure()) { - return ResultFs.PathNotFound.Includes(rc) ? ResultFs.TargetNotFound.LogConverted(rc) : rc; + return ResultFs.PathNotFound.Includes(rc) ? ResultFs.TargetNotFound.LogConverted(rc) : rc.Miss(); } + using var saveDataFs = new SharedRef(); + if (type == DirectoryEntryType.Directory) { - if (!allowDirectorySaveData) - return ResultFs.InvalidSaveDataEntryType.Log(); + if (EnforceSaveTypeRestrictions) + { + if (!allowDirectorySaveData) + return ResultFs.InvalidSaveDataEntryType.Log(); + } - using var baseFs = - new UniqueRef(new SubdirectoryFileSystem(ref baseFileSystem)); + // Get a file system over the save directory + using var baseFs = new UniqueRef(new SubdirectoryFileSystem(ref baseFileSystem)); if (!baseFs.HasValue) return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorA.Log(); rc = baseFs.Get.Initialize(in saveImageName); - if (rc.IsFailure()) return rc; + if (rc.IsFailure()) return rc.Miss(); + // Create and initialize the directory save data FS using UniqueRef tempFs = UniqueRef.Create(ref baseFs.Ref()); using var saveDirFs = new SharedRef( new DirectorySaveDataFileSystem(ref tempFs.Ref(), _fsServer.Hos.Fs)); + if (!saveDirFs.HasValue) + return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorB.Log(); + rc = saveDirFs.Get.Initialize(isJournalingSupported, isMultiCommitSupported, !openReadOnly, timeStampGetter, _randomGenerator); - if (rc.IsFailure()) return rc; + if (rc.IsFailure()) return rc.Miss(); - outFileSystem.SetByCopy(in saveDirFs); - outExtraDataAccessor.SetByCopy(in saveDirFs); - - return Result.Success; + saveDataFs.SetByMove(ref saveDirFs.Ref()); } else { @@ -98,18 +102,16 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator OpenMode.ReadWrite, openType); if (rc.IsFailure()) return rc; - if (!isJournalingSupported) - { - throw new NotImplementedException(); - } - - using var saveFs = new SharedRef(new SaveDataFileSystem(_keySet, fileStorage.Get, - IntegrityCheckLevel.ErrorOnInvalid, false)); - - // Todo: ISaveDataExtraDataAccessor - - return Result.Success; + throw new NotImplementedException(); } + + // Wrap the save FS in a result convert FS and set it as the output FS + using var resultConvertFs = new SharedRef( + new SaveDataResultConvertFileSystem(ref saveDataFs.Ref(), isReconstructible)); + + outFileSystem.SetByMove(ref resultConvertFs.Ref()); + + return Result.Success; } public Result CreateExtraDataAccessor(ref SharedRef outExtraDataAccessor, diff --git a/src/LibHac/FsSrv/FsCreator/SaveDataResultConvertFileSystem.cs b/src/LibHac/FsSrv/FsCreator/SaveDataResultConvertFileSystem.cs new file mode 100644 index 00000000..a9bcb457 --- /dev/null +++ b/src/LibHac/FsSrv/FsCreator/SaveDataResultConvertFileSystem.cs @@ -0,0 +1,127 @@ +using LibHac.Common; +using LibHac.Fs; +using LibHac.Fs.Fsa; +using LibHac.FsSystem; +using static LibHac.FsSrv.FsCreator.SaveDataResultConverter; + +namespace LibHac.FsSrv.FsCreator; + +/// +/// Wraps an , converting its returned s +/// to save-data-specific s. +/// +/// Based on FS 14.1.0 (nnSdk 14.3.0) +public class SaveDataResultConvertFile : IResultConvertFile +{ + private bool _isReconstructible; + + public SaveDataResultConvertFile(ref UniqueRef baseFile, bool isReconstructible) : base(ref baseFile) + { + _isReconstructible = isReconstructible; + } + + protected override Result ConvertResult(Result result) + { + return ConvertSaveDataFsResult(result, _isReconstructible).Ret(); + } +} + +/// +/// Wraps an , converting its returned s +/// to save-data-specific s. +/// +/// Based on FS 14.1.0 (nnSdk 14.3.0) +public class SaveDataResultConvertDirectory : IResultConvertDirectory +{ + private bool _isReconstructible; + + public SaveDataResultConvertDirectory(ref UniqueRef baseDirectory, bool isReconstructible) : base( + ref baseDirectory) + { + _isReconstructible = isReconstructible; + } + + protected override Result ConvertResult(Result result) + { + return ConvertSaveDataFsResult(result, _isReconstructible).Ret(); + } +} + +/// +/// Wraps an , converting its returned s +/// to save-data-specific s. +/// +/// Based on FS 14.1.0 (nnSdk 14.3.0) +public class SaveDataResultConvertFileSystem : IResultConvertFileSystem +{ + private bool _isReconstructible; + + public SaveDataResultConvertFileSystem(ref SharedRef baseFileSystem, bool isReconstructible) : + base(ref baseFileSystem) + { + _isReconstructible = isReconstructible; + } + + public override Result WriteExtraData(in SaveDataExtraData extraData) + { + return ConvertSaveDataFsResult(GetFileSystem().WriteExtraData(in extraData), _isReconstructible).Ret(); + } + + public override Result CommitExtraData(bool updateTimeStamp) + { + return ConvertSaveDataFsResult(GetFileSystem().CommitExtraData(updateTimeStamp), _isReconstructible).Ret(); + } + + public override Result ReadExtraData(out SaveDataExtraData extraData) + { + return ConvertSaveDataFsResult(GetFileSystem().ReadExtraData(out extraData), _isReconstructible).Ret(); + } + + public override Result RollbackOnlyModified() + { + return ConvertSaveDataFsResult(GetFileSystem().RollbackOnlyModified(), _isReconstructible).Ret(); + } + + protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) + { + using var file = new UniqueRef(); + Result rc = ConvertResult(GetFileSystem().OpenFile(ref file.Ref(), in path, mode)); + if (rc.IsFailure()) return rc.Miss(); + + using UniqueRef resultConvertFile = + new(new SaveDataResultConvertFile(ref file.Ref(), _isReconstructible)); + + outFile.Set(ref resultConvertFile.Ref()); + return Result.Success; + } + + protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, + OpenDirectoryMode mode) + { + using var directory = new UniqueRef(); + Result rc = ConvertResult(GetFileSystem().OpenDirectory(ref directory.Ref(), in path, mode)); + if (rc.IsFailure()) return rc.Miss(); + + using UniqueRef resultConvertDirectory = + new(new SaveDataResultConvertDirectory(ref directory.Ref(), _isReconstructible)); + + outDirectory.Set(ref resultConvertDirectory.Ref()); + return Result.Success; + } + + protected override Result ConvertResult(Result result) + { + return ConvertSaveDataFsResult(result, _isReconstructible).Ret(); + } + + public override bool IsSaveDataFileSystemCacheEnabled() + { + return GetFileSystem().IsSaveDataFileSystemCacheEnabled(); + } + + public override void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, + SaveDataSpaceId spaceId, ulong saveDataId) + { + GetFileSystem().RegisterExtraDataAccessorObserver(observer, spaceId, saveDataId); + } +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/Impl/SaveDataResultConvertFileSystem.cs b/src/LibHac/FsSrv/FsCreator/SaveDataResultConverter.cs similarity index 58% rename from src/LibHac/FsSrv/Impl/SaveDataResultConvertFileSystem.cs rename to src/LibHac/FsSrv/FsCreator/SaveDataResultConverter.cs index e53dffc8..98df4f6b 100644 --- a/src/LibHac/FsSrv/Impl/SaveDataResultConvertFileSystem.cs +++ b/src/LibHac/FsSrv/FsCreator/SaveDataResultConverter.cs @@ -1,15 +1,13 @@ -using LibHac.Common; -using LibHac.Diag; +using LibHac.Diag; using LibHac.Fs; -using LibHac.Fs.Fsa; -namespace LibHac.FsSrv.Impl; +namespace LibHac.FsSrv.FsCreator; /// /// Contains functions for converting internal save data s to external s. /// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public static class SaveDataResultConvert +/// Based on FS 14.1.0 (nnSdk 14.3.0) +public static class SaveDataResultConverter { private static Result ConvertCorruptedResult(Result result) { @@ -32,8 +30,7 @@ public static class SaveDataResultConvert Assert.SdkAssert(false); } - - if (ResultFs.HostFileSystemCorrupted.Includes(result)) + else if (ResultFs.HostFileSystemCorrupted.Includes(result)) { if (ResultFs.HostEntryCorrupted.Includes(result)) return ResultFs.SaveDataHostEntryCorrupted.LogConverted(result); @@ -49,8 +46,7 @@ public static class SaveDataResultConvert Assert.SdkAssert(false); } - - if (ResultFs.DatabaseCorrupted.Includes(result)) + else if (ResultFs.DatabaseCorrupted.Includes(result)) { if (ResultFs.InvalidAllocationTableBlock.Includes(result)) return ResultFs.InvalidSaveDataAllocationTableBlock.LogConverted(result); @@ -75,8 +71,7 @@ public static class SaveDataResultConvert Assert.SdkAssert(false); } - - if (ResultFs.ZeroBitmapFileCorrupted.Includes(result)) + else if (ResultFs.ZeroBitmapFileCorrupted.Includes(result)) { if (ResultFs.IncompleteBlockInZeroBitmapHashStorageFile.Includes(result)) return ResultFs.IncompleteBlockInZeroBitmapHashStorageFileSaveData.LogConverted(result); @@ -87,11 +82,8 @@ public static class SaveDataResultConvert return result; } - public static Result ConvertSaveFsDriverPrivateResult(Result result) + private static Result ConvertResult(Result result) { - if (result.IsSuccess()) - return result; - if (ResultFs.UnsupportedVersion.Includes(result)) return ResultFs.UnsupportedSaveDataVersion.LogConverted(result); @@ -101,7 +93,7 @@ public static class SaveDataResultConvert ResultFs.DatabaseCorrupted.Includes(result) || ResultFs.ZeroBitmapFileCorrupted.Includes(result)) { - return ConvertCorruptedResult(result); + return ConvertCorruptedResult(result).Miss(); } if (ResultFs.FatFileSystemCorrupted.Includes(result)) @@ -116,9 +108,6 @@ public static class SaveDataResultConvert if (ResultFs.AlreadyExists.Includes(result)) return ResultFs.PathAlreadyExists.LogConverted(result); - if (ResultFs.InvalidOffset.Includes(result)) - return ResultFs.OutOfRange.LogConverted(result); - if (ResultFs.IncompatiblePath.Includes(result) || ResultFs.FileNotFound.Includes(result)) { @@ -127,77 +116,19 @@ public static class SaveDataResultConvert return result; } -} -/// -/// Wraps an , converting its returned s -/// to save-data-specific s. -/// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public class SaveDataResultConvertFile : IResultConvertFile -{ - public SaveDataResultConvertFile(ref UniqueRef baseFile) : base(ref baseFile) + public static Result ConvertSaveDataFsResult(Result result, bool isReconstructible) { - } + if (result.IsSuccess()) + return Result.Success; - protected override Result ConvertResult(Result result) - { - return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(result); - } -} + Result convertedResult = ConvertResult(result); -/// -/// Wraps an , converting its returned s -/// to save-data-specific s. -/// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public class SaveDataResultConvertDirectory : IResultConvertDirectory -{ - public SaveDataResultConvertDirectory(ref UniqueRef baseDirectory) : base(ref baseDirectory) - { - } + if (isReconstructible && ResultFs.SaveDataCorrupted.Includes(convertedResult)) + { + return ResultFs.ReconstructibleSaveDataCorrupted.LogConverted(convertedResult); + } - protected override Result ConvertResult(Result result) - { - return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(result); - } -} - -/// -/// Wraps an , converting its returned s -/// to save-data-specific s. -/// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public class SaveDataResultConvertFileSystem : IResultConvertFileSystem -{ - public SaveDataResultConvertFileSystem(ref SharedRef baseFileSystem) - : base(ref baseFileSystem) - { - } - - protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) - { - using var file = new UniqueRef(); - Result rc = ConvertResult(BaseFileSystem.Get.OpenFile(ref file.Ref(), path, mode)); - if (rc.IsFailure()) return rc; - - outFile.Reset(new SaveDataResultConvertFile(ref file.Ref())); - return Result.Success; - } - - protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, - OpenDirectoryMode mode) - { - using var directory = new UniqueRef(); - Result rc = ConvertResult(BaseFileSystem.Get.OpenDirectory(ref directory.Ref(), path, mode)); - if (rc.IsFailure()) return rc; - - outDirectory.Reset(new SaveDataResultConvertDirectory(ref directory.Ref())); - return Result.Success; - } - - protected override Result ConvertResult(Result result) - { - return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(result); + return convertedResult; } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs b/src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs index c2166d00..a1fc90ce 100644 --- a/src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs +++ b/src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs @@ -7,7 +7,7 @@ namespace LibHac.FsSrv.Impl; /// /// Wraps an . -/// Upon disposal the base file system is returned to the provided . +/// Upon disposal the base file system is returned to the provided . /// /// Based on FS 14.1.0 (nnSdk 14.3.0) public class SaveDataFileSystemCacheRegister : IFileSystem diff --git a/src/LibHac/FsSrv/Impl/SaveDataProperties.cs b/src/LibHac/FsSrv/Impl/SaveDataProperties.cs index 82070e27..dec1956e 100644 --- a/src/LibHac/FsSrv/Impl/SaveDataProperties.cs +++ b/src/LibHac/FsSrv/Impl/SaveDataProperties.cs @@ -8,6 +8,20 @@ public static class SaveDataProperties public const long DefaultSaveDataBlockSize = 0x4000; public const long BcatSaveDataJournalSize = 0x200000; + public static bool IsJournalingSupported(SaveDataFormatType type) + { + switch (type) + { + case SaveDataFormatType.Normal: + return true; + case SaveDataFormatType.NoJournal: + return false; + default: + Abort.UnexpectedDefault(); + return default; + } + } + public static bool IsJournalingSupported(SaveDataType type) { switch (type) @@ -67,7 +81,6 @@ public static class SaveDataProperties switch (type) { case SaveDataType.System: - case SaveDataType.SystemBcat: return true; case SaveDataType.Account: case SaveDataType.Bcat: @@ -86,7 +99,6 @@ public static class SaveDataProperties switch (type) { case SaveDataType.System: - case SaveDataType.SystemBcat: return true; case SaveDataType.Account: case SaveDataType.Bcat: @@ -99,4 +111,36 @@ public static class SaveDataProperties return default; } } -} + + public static bool IsReconstructible(SaveDataType type, SaveDataSpaceId spaceId) + { + switch (spaceId) + { + case SaveDataSpaceId.System: + case SaveDataSpaceId.User: + case SaveDataSpaceId.ProperSystem: + case SaveDataSpaceId.SafeMode: + switch (type) + { + case SaveDataType.System: + case SaveDataType.Account: + case SaveDataType.Device: + return false; + case SaveDataType.Bcat: + case SaveDataType.Temporary: + case SaveDataType.Cache: + return true; + default: + Abort.UnexpectedDefault(); + return default; + } + case SaveDataSpaceId.SdSystem: + case SaveDataSpaceId.Temporary: + case SaveDataSpaceId.SdUser: + return true; + default: + Abort.UnexpectedDefault(); + return default; + } + } +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs index dde416ac..0876cfaa 100644 --- a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs @@ -20,7 +20,7 @@ public class SaveDataFileSystemServiceImpl private Configuration _config; private EncryptionSeed _encryptionSeed; - private FsSystem.SaveDataFileSystemCacheManager _saveDataFsCacheManager; + private SaveDataFileSystemCacheManager _saveDataFsCacheManager; private SaveDataExtraDataAccessorCacheManager _extraDataCacheManager; // Save data porter manager private bool _isSdCardAccessible; @@ -47,7 +47,7 @@ public class SaveDataFileSystemServiceImpl public SaveDataFileSystemServiceImpl(in Configuration configuration) { _config = configuration; - _saveDataFsCacheManager = new FsSystem.SaveDataFileSystemCacheManager(); + _saveDataFsCacheManager = new SaveDataFileSystemCacheManager(); _extraDataCacheManager = new SaveDataExtraDataAccessorCacheManager(); _timeStampGetter = new TimeStampGetter(this); @@ -116,6 +116,7 @@ public class SaveDataFileSystemServiceImpl } } + // 14.3.0 public Result OpenSaveDataFileSystem(ref SharedRef outFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, in Path saveDataRootPath, bool openReadOnly, SaveDataType type, bool cacheExtraData) { @@ -124,66 +125,65 @@ public class SaveDataFileSystemServiceImpl Result rc = OpenSaveDataDirectoryFileSystem(ref fileSystem.Ref(), spaceId, in saveDataRootPath, true); if (rc.IsFailure()) return rc.Miss(); - bool allowDirectorySaveData = IsAllowedDirectorySaveData2(spaceId, in saveDataRootPath); + bool isEmulatedOnHost = IsAllowedDirectorySaveData(spaceId, in saveDataRootPath); - // Note: When directory save data is allowed, Nintendo creates the save directory if it doesn't exist. - // This bypasses normal save data creation, leaving the save with empty extra data. - // Instead, we return that the save doesn't exist if the directory is missing. - - using var saveDataFs = new SharedRef(); - using var cachedFs = new SharedRef(); - - // Note: Nintendo doesn't cache directory save data - // if (!allowDirectorySaveData) + if (isEmulatedOnHost) { - // Check if we have the requested file system cached - if (_saveDataFsCacheManager.GetCache(ref cachedFs.Ref(), spaceId, saveDataId)) - { - using var registerBase = new SharedRef( - new SaveDataFileSystemCacheRegisterBase(ref cachedFs.Ref(), - _saveDataFsCacheManager)); - - using var resultConvertFs = new SharedRef( - new SaveDataResultConvertFileSystem(ref registerBase.Ref())); - - saveDataFs.SetByMove(ref resultConvertFs.Ref()); - } - } - - // Create a new file system if it's not in the cache - if (!saveDataFs.HasValue) - { - using UniqueLockRef scopedLock = _extraDataCacheManager.GetScopedLock(); - using var extraDataAccessor = new SharedRef(); - - bool openShared = SaveDataProperties.IsSharedOpenNeeded(type); - bool isMultiCommitSupported = SaveDataProperties.IsMultiCommitSupported(type); - bool isJournalingSupported = SaveDataProperties.IsJournalingSupported(type); - bool useDeviceUniqueMac = IsDeviceUniqueMac(spaceId); - - rc = _config.SaveFsCreator.Create(ref saveDataFs.Ref(), ref extraDataAccessor.Ref(), - _saveDataFsCacheManager, ref fileSystem.Ref(), spaceId, saveDataId, allowDirectorySaveData, - useDeviceUniqueMac, isJournalingSupported, isMultiCommitSupported, openReadOnly, openShared, - _timeStampGetter); + // Create the save data directory on the host if needed. + Unsafe.SkipInit(out Array18 saveDirectoryNameBuffer); + using var saveDirectoryName = new Path(); + rc = PathFunctions.SetUpFixedPathSaveId(ref saveDirectoryName.Ref(), saveDirectoryNameBuffer.Items, saveDataId); if (rc.IsFailure()) return rc.Miss(); - // Cache the extra data accessor if needed - if (cacheExtraData && extraDataAccessor.HasValue) + rc = FsSystem.Utility.EnsureDirectory(fileSystem.Get, in saveDirectoryName); + if (rc.IsFailure()) return rc.Miss(); + } + + using var saveDataFs = new SharedRef(); + + using (_saveDataFsCacheManager.GetScopedLock()) + using (_extraDataCacheManager.GetScopedLock()) + { + if (isEmulatedOnHost || !_saveDataFsCacheManager.GetCache(ref saveDataFs.Ref(), spaceId, saveDataId)) { - extraDataAccessor.Get.RegisterExtraDataAccessorObserver(_extraDataCacheManager, spaceId, saveDataId); + bool isDeviceUniqueMac = IsDeviceUniqueMac(spaceId); + bool isJournalingSupported = SaveDataProperties.IsJournalingSupported(type); + bool isMultiCommitSupported = SaveDataProperties.IsMultiCommitSupported(type); + bool openShared = SaveDataProperties.IsSharedOpenNeeded(type); + bool isReconstructible = SaveDataProperties.IsReconstructible(type, spaceId); + + rc = _config.SaveFsCreator.Create(ref saveDataFs.Ref(), ref fileSystem.Ref(), spaceId, saveDataId, + isEmulatedOnHost, isDeviceUniqueMac, isJournalingSupported, isMultiCommitSupported, + openReadOnly, openShared, _timeStampGetter, isReconstructible); + if (rc.IsFailure()) return rc.Miss(); + } + + if (!isEmulatedOnHost && cacheExtraData) + { + using SharedRef extraDataAccessor = + SharedRef.CreateCopy(in saveDataFs); rc = _extraDataCacheManager.Register(in extraDataAccessor, spaceId, saveDataId); if (rc.IsFailure()) return rc.Miss(); } } + using var registerFs = new SharedRef( + new SaveDataFileSystemCacheRegister(ref saveDataFs.Ref(), _saveDataFsCacheManager, spaceId, saveDataId)); + if (openReadOnly) { - outFileSystem.Reset(new ReadOnlyFileSystem(ref saveDataFs.Ref())); + using SharedRef tempFs = SharedRef.CreateMove(ref registerFs.Ref()); + using var readOnlyFileSystem = new SharedRef(new ReadOnlyFileSystem(ref tempFs.Ref())); + + if (!readOnlyFileSystem.HasValue) + return ResultFs.AllocationMemoryFailedInSaveDataFileSystemServiceImplB.Log(); + + outFileSystem.SetByMove(ref readOnlyFileSystem.Ref()); } else { - outFileSystem.SetByMove(ref saveDataFs.Ref()); + outFileSystem.SetByMove(ref registerFs.Ref()); } return Result.Success; @@ -339,15 +339,15 @@ public class SaveDataFileSystemServiceImpl rc = FsSystem.Utility.EnsureDirectory(fileSystem.Get, in saveImageName); if (rc.IsFailure()) return rc.Miss(); - using var saveFileSystem = new SharedRef(); - using var extraDataAccessor = new SharedRef(); + using var saveFileSystem = new SharedRef(); bool isJournalingSupported = SaveDataProperties.IsJournalingSupported(attribute.Type); + bool isReconstructible = SaveDataProperties.IsReconstructible(attribute.Type, creationInfo.SpaceId); - rc = _config.SaveFsCreator.Create(ref saveFileSystem.Ref(), ref extraDataAccessor.Ref(), - _saveDataFsCacheManager, ref fileSystem.Ref(), creationInfo.SpaceId, saveDataId, - allowDirectorySaveData: true, useDeviceUniqueMac: false, isJournalingSupported, - isMultiCommitSupported: false, openReadOnly: false, openShared: false, _timeStampGetter); + rc = _config.SaveFsCreator.Create(ref saveFileSystem.Ref(), ref fileSystem.Ref(), creationInfo.SpaceId, + saveDataId, allowDirectorySaveData: true, isDeviceUniqueMac: false, isJournalingSupported, + isMultiCommitSupported: false, openReadOnly: false, openShared: false, _timeStampGetter, + isReconstructible); if (rc.IsFailure()) return rc.Miss(); var extraData = new SaveDataExtraData(); @@ -365,10 +365,10 @@ public class SaveDataFileSystemServiceImpl extraData.DataSize = creationInfo.Size; extraData.JournalSize = creationInfo.JournalSize; - rc = extraDataAccessor.Get.WriteExtraData(in extraData); + rc = saveFileSystem.Get.WriteExtraData(in extraData); if (rc.IsFailure()) return rc.Miss(); - rc = extraDataAccessor.Get.CommitExtraData(true); + rc = saveFileSystem.Get.CommitExtraData(true); if (rc.IsFailure()) return rc.Miss(); } else @@ -552,8 +552,8 @@ public class SaveDataFileSystemServiceImpl using (var tmFileSystem = new SharedRef()) { // Ensure the target save data directory exists - rc = _config.TargetManagerFsCreator.Create(ref tmFileSystem.Ref(), in saveDataRootPath, false, true, - ResultFs.SaveDataRootPathUnavailable.Value); + rc = _config.TargetManagerFsCreator.Create(ref tmFileSystem.Ref(), in saveDataRootPath, + openCaseSensitive: false, ensureRootPathExists: true, ResultFs.SaveDataRootPathUnavailable.Value); if (rc.IsFailure()) return rc.Miss(); } @@ -564,8 +564,8 @@ public class SaveDataFileSystemServiceImpl rc = _config.TargetManagerFsCreator.NormalizeCaseOfPath(out bool isTargetFsCaseSensitive, ref path.Ref()); if (rc.IsFailure()) return rc.Miss(); - rc = _config.TargetManagerFsCreator.Create(ref outFileSystem, in path, isTargetFsCaseSensitive, false, - ResultFs.SaveDataRootPathUnavailable.Value); + rc = _config.TargetManagerFsCreator.Create(ref outFileSystem, in path, isTargetFsCaseSensitive, + ensureRootPathExists: false, ResultFs.SaveDataRootPathUnavailable.Value); if (rc.IsFailure()) return rc.Miss(); return Result.Success; @@ -696,20 +696,14 @@ public class SaveDataFileSystemServiceImpl throw new NotImplementedException(); } + /// + /// Checks if a save is to be stored on a host device. + /// public bool IsAllowedDirectorySaveData(SaveDataSpaceId spaceId, in Path saveDataRootPath) { return spaceId == SaveDataSpaceId.User && IsSaveEmulated(in saveDataRootPath); } - // Todo: remove once file save data is supported - // Used to always allow directory save data in OpenSaveDataFileSystem - public bool IsAllowedDirectorySaveData2(SaveDataSpaceId spaceId, in Path saveDataRootPath) - { - // Todo: remove "|| true" once file save data is supported - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - return spaceId == SaveDataSpaceId.User && IsSaveEmulated(in saveDataRootPath) || true; - } - public bool IsDeviceUniqueMac(SaveDataSpaceId spaceId) { return spaceId == SaveDataSpaceId.System || diff --git a/src/LibHac/FsSrv/Impl/IResultConvertFileSystem.cs b/src/LibHac/FsSystem/IResultConvertFileSystem.cs similarity index 54% rename from src/LibHac/FsSrv/Impl/IResultConvertFileSystem.cs rename to src/LibHac/FsSystem/IResultConvertFileSystem.cs index 2f361d21..f65d3525 100644 --- a/src/LibHac/FsSrv/Impl/IResultConvertFileSystem.cs +++ b/src/LibHac/FsSystem/IResultConvertFileSystem.cs @@ -3,61 +3,62 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -namespace LibHac.FsSrv.Impl; +namespace LibHac.FsSystem; // ReSharper disable once InconsistentNaming /// /// Wraps an , converting its returned s to different /// s based on the function. /// -/// Based on FS 13.1.0 (nnSdk 13.4.0) +/// Based on FS 14.1.0 (nnSdk 14.3.0) public abstract class IResultConvertFile : IFile { - protected UniqueRef BaseFile; + private UniqueRef _baseFile; protected IResultConvertFile(ref UniqueRef baseFile) { - BaseFile = new UniqueRef(ref baseFile); + _baseFile = new UniqueRef(ref baseFile); } public override void Dispose() { - BaseFile.Destroy(); + _baseFile.Destroy(); + base.Dispose(); } + protected abstract Result ConvertResult(Result result); + protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) { - return ConvertResult(BaseFile.Get.Read(out bytesRead, offset, destination, option)); + return ConvertResult(_baseFile.Get.Read(out bytesRead, offset, destination, in option)).Ret(); } protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) { - return ConvertResult(BaseFile.Get.Write(offset, source, option)); + return ConvertResult(_baseFile.Get.Write(offset, source, in option)).Ret(); } protected override Result DoFlush() { - return ConvertResult(BaseFile.Get.Flush()); + return ConvertResult(_baseFile.Get.Flush()).Ret(); } protected override Result DoSetSize(long size) { - return ConvertResult(BaseFile.Get.SetSize(size)); + return ConvertResult(_baseFile.Get.SetSize(size)).Ret(); } protected override Result DoGetSize(out long size) { - return ConvertResult(BaseFile.Get.GetSize(out size)); + return ConvertResult(_baseFile.Get.GetSize(out size)).Ret(); } protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) { - return ConvertResult(BaseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer)); + return ConvertResult(_baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer)).Ret(); } - - protected abstract Result ConvertResult(Result result); } // ReSharper disable once InconsistentNaming @@ -65,33 +66,34 @@ public abstract class IResultConvertFile : IFile /// Wraps an , converting its returned s to different /// s based on the function. /// -/// Based on FS 13.1.0 (nnSdk 13.4.0) +/// Based on FS 14.1.0 (nnSdk 14.3.0) public abstract class IResultConvertDirectory : IDirectory { - protected UniqueRef BaseDirectory; + private UniqueRef _baseDirectory; protected IResultConvertDirectory(ref UniqueRef baseDirectory) { - BaseDirectory = new UniqueRef(ref baseDirectory); + _baseDirectory = new UniqueRef(ref baseDirectory); } public override void Dispose() { - BaseDirectory.Destroy(); + _baseDirectory.Destroy(); + base.Dispose(); } + protected abstract Result ConvertResult(Result result); + protected override Result DoRead(out long entriesRead, Span entryBuffer) { - return ConvertResult(BaseDirectory.Get.Read(out entriesRead, entryBuffer)); + return ConvertResult(_baseDirectory.Get.Read(out entriesRead, entryBuffer)).Ret(); } protected override Result DoGetEntryCount(out long entryCount) { - return ConvertResult(BaseDirectory.Get.GetEntryCount(out entryCount)); + return ConvertResult(_baseDirectory.Get.GetEntryCount(out entryCount)).Ret(); } - - protected abstract Result ConvertResult(Result result); } // ReSharper disable once InconsistentNaming @@ -99,114 +101,110 @@ public abstract class IResultConvertDirectory : IDirectory /// Wraps an , converting its returned s to different /// s based on the function. /// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public abstract class IResultConvertFileSystem : IFileSystem +/// Based on FS 14.1.0 (nnSdk 14.3.0) +public abstract class IResultConvertFileSystem : ISaveDataFileSystem where T : IFileSystem { - protected SharedRef BaseFileSystem; + private SharedRef _baseFileSystem; - protected IResultConvertFileSystem(ref SharedRef baseFileSystem) + protected IResultConvertFileSystem(ref SharedRef baseFileSystem) { - BaseFileSystem = SharedRef.CreateMove(ref baseFileSystem); + _baseFileSystem = SharedRef.CreateMove(ref baseFileSystem); } public override void Dispose() { - BaseFileSystem.Destroy(); + _baseFileSystem.Destroy(); + base.Dispose(); } + protected T GetFileSystem() => _baseFileSystem.Get; + + protected abstract Result ConvertResult(Result result); + protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) { - return ConvertResult(BaseFileSystem.Get.CreateFile(path, size, option)); + return ConvertResult(_baseFileSystem.Get.CreateFile(in path, size)).Ret(); } protected override Result DoDeleteFile(in Path path) { - return ConvertResult(BaseFileSystem.Get.DeleteFile(path)); + return ConvertResult(_baseFileSystem.Get.DeleteFile(in path)).Ret(); } protected override Result DoCreateDirectory(in Path path) { - return ConvertResult(BaseFileSystem.Get.CreateDirectory(path)); + return ConvertResult(_baseFileSystem.Get.CreateDirectory(in path)).Ret(); } protected override Result DoDeleteDirectory(in Path path) { - return ConvertResult(BaseFileSystem.Get.DeleteDirectory(path)); + return ConvertResult(_baseFileSystem.Get.DeleteDirectory(in path)).Ret(); } protected override Result DoDeleteDirectoryRecursively(in Path path) { - return ConvertResult(BaseFileSystem.Get.DeleteDirectoryRecursively(path)); + return ConvertResult(_baseFileSystem.Get.DeleteDirectoryRecursively(in path)).Ret(); } protected override Result DoCleanDirectoryRecursively(in Path path) { - return ConvertResult(BaseFileSystem.Get.CleanDirectoryRecursively(path)); + return ConvertResult(_baseFileSystem.Get.CleanDirectoryRecursively(in path)).Ret(); } protected override Result DoRenameFile(in Path currentPath, in Path newPath) { - return ConvertResult(BaseFileSystem.Get.RenameFile(currentPath, newPath)); + return ConvertResult(_baseFileSystem.Get.RenameFile(in currentPath, in newPath)).Ret(); } protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) { - return ConvertResult(BaseFileSystem.Get.RenameDirectory(currentPath, newPath)); + return ConvertResult(_baseFileSystem.Get.RenameDirectory(in currentPath, in newPath)).Ret(); } protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) { - return ConvertResult(BaseFileSystem.Get.GetEntryType(out entryType, path)); + return ConvertResult(_baseFileSystem.Get.GetEntryType(out entryType, in path)).Ret(); } - // Note: The original code uses templates to determine which type of IFile/IDirectory to return. To make things - // easier in C# these two functions have been made abstract functions. - protected abstract override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode); - - protected abstract override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, - OpenDirectoryMode mode); - protected override Result DoCommit() { - return ConvertResult(BaseFileSystem.Get.Commit()); + return ConvertResult(_baseFileSystem.Get.Commit()).Ret(); } protected override Result DoCommitProvisionally(long counter) { - return ConvertResult(BaseFileSystem.Get.CommitProvisionally(counter)); + return ConvertResult(_baseFileSystem.Get.CommitProvisionally(counter)).Ret(); } protected override Result DoRollback() { - return ConvertResult(BaseFileSystem.Get.Rollback()); + return ConvertResult(_baseFileSystem.Get.Rollback()).Ret(); } protected override Result DoFlush() { - return ConvertResult(BaseFileSystem.Get.Flush()); + return ConvertResult(_baseFileSystem.Get.Flush()).Ret(); } protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path) { - return ConvertResult(BaseFileSystem.Get.GetFileTimeStampRaw(out timeStamp, path)); + return ConvertResult(_baseFileSystem.Get.GetFileTimeStampRaw(out timeStamp, in path)).Ret(); } protected override Result DoQueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, in Path path) { - return ConvertResult(BaseFileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, path)); + return ConvertResult(_baseFileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, in path)).Ret(); } protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) { - return ConvertResult(BaseFileSystem.Get.GetFreeSpaceSize(out freeSpace, path)); + return ConvertResult(_baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path)).Ret(); } protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) { - return ConvertResult(BaseFileSystem.Get.GetTotalSpaceSize(out totalSpace, path)); + return ConvertResult(_baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, in path)).Ret(); } - - protected abstract Result ConvertResult(Result result); } \ No newline at end of file diff --git a/src/LibHac/FsSystem/ISaveDataFileSystemCacheManager.cs b/src/LibHac/FsSystem/ISaveDataFileSystemCacheManager.cs deleted file mode 100644 index 5f053e83..00000000 --- a/src/LibHac/FsSystem/ISaveDataFileSystemCacheManager.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using LibHac.Common; -using LibHac.Fs; - -namespace LibHac.FsSystem; - -/// -/// Provides a mechanism for caching save data file systems. -/// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public interface ISaveDataFileSystemCacheManager : IDisposable -{ - bool GetCache(ref SharedRef outFileSystem, SaveDataSpaceId spaceId, ulong saveDataId); - void Register(ref SharedRef fileSystem); - void Register(ref SharedRef fileSystem); - void Unregister(SaveDataSpaceId spaceId, ulong saveDataId); -} \ No newline at end of file diff --git a/src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs b/src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs deleted file mode 100644 index 1c19a119..00000000 --- a/src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs +++ /dev/null @@ -1,171 +0,0 @@ -using LibHac.Common; -using LibHac.Diag; -using LibHac.Fs; -using LibHac.Os; - -namespace LibHac.FsSystem; - -/// -/// Manages a list of cached save data file systems. Each file system is registered and retrieved -/// based on its save data ID and save data space ID. -/// -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public class SaveDataFileSystemCacheManager : ISaveDataFileSystemCacheManager -{ - /// - /// Holds a single cached file system identified by its save data ID and save data space ID. - /// - /// Based on FS 13.1.0 (nnSdk 13.4.0) - [NonCopyable] - private struct Cache - { - // Note: Nintendo only supports caching SaveDataFileSystem. We support DirectorySaveDataFileSystem too, - // so we use a wrapper class to simplify the logic here. - private SharedRef _fileSystem; - private ulong _saveDataId; - private SaveDataSpaceId _spaceId; - - public void Dispose() - { - _fileSystem.Destroy(); - } - - public bool IsCached(SaveDataSpaceId spaceId, ulong saveDataId) - { - return _fileSystem.HasValue && _spaceId == spaceId && _saveDataId == saveDataId; - } - - public SharedRef Move() - { - return SharedRef.CreateMove(ref _fileSystem); - } - - public void Register(ref SharedRef fileSystem) - { - _spaceId = fileSystem.Get.GetSaveDataSpaceId(); - _saveDataId = fileSystem.Get.GetSaveDataId(); - - _fileSystem.SetByMove(ref fileSystem); - } - - public void Unregister() - { - _fileSystem.Reset(); - } - } - - private SdkRecursiveMutexType _mutex; - private Cache[] _cachedFileSystems; - private int _maxCachedFileSystemCount; - private int _nextCacheIndex; - - public SaveDataFileSystemCacheManager() - { - _mutex = new SdkRecursiveMutexType(); - } - - public void Dispose() - { - Cache[] caches = Shared.Move(ref _cachedFileSystems); - - if (caches is not null) - { - for (int i = 0; i < caches.Length; i++) - { - caches[i].Dispose(); - } - } - } - - public Result Initialize(int maxCacheCount) - { - Assert.SdkRequiresGreaterEqual(maxCacheCount, 0); - - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - - Assert.SdkAssert(_cachedFileSystems is null); - - _maxCachedFileSystemCount = maxCacheCount; - if (maxCacheCount > 0) - { - // Note: The original checks for overflow here - _cachedFileSystems = new Cache[maxCacheCount]; - } - - return Result.Success; - } - - public bool GetCache(ref SharedRef outFileSystem, SaveDataSpaceId spaceId, - ulong saveDataId) - { - Assert.SdkRequiresGreaterEqual(_maxCachedFileSystemCount, 0); - - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - - for (int i = 0; i < _maxCachedFileSystemCount; i++) - { - if (_cachedFileSystems[i].IsCached(spaceId, saveDataId)) - { - using SharedRef cachedFs = _cachedFileSystems[i].Move(); - outFileSystem.SetByMove(ref cachedFs.Ref()); - - return true; - } - } - - return false; - } - - public void Register(ref SharedRef fileSystem) - { - // Don't cache temporary save data - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - fileSystem.Reset(); - } - - public void Register(ref SharedRef fileSystem) - { - if (_maxCachedFileSystemCount <= 0) - return; - - Assert.SdkRequiresGreaterEqual(_nextCacheIndex, 0); - Assert.SdkRequiresGreater(_maxCachedFileSystemCount, _nextCacheIndex); - - if (fileSystem.Get.GetSaveDataSpaceId() == SaveDataSpaceId.SdSystem) - { - // Don't cache system save data - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - fileSystem.Reset(); - } - else - { - Result rc = fileSystem.Get.RollbackOnlyModified(); - if (rc.IsFailure()) return; - - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - - _cachedFileSystems[_nextCacheIndex].Register(ref fileSystem); - _nextCacheIndex = (_nextCacheIndex + 1) % _maxCachedFileSystemCount; - } - } - - public void Unregister(SaveDataSpaceId spaceId, ulong saveDataId) - { - Assert.SdkRequiresGreaterEqual(_maxCachedFileSystemCount, 0); - - using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); - - for (int i = 0; i < _maxCachedFileSystemCount; i++) - { - if (_cachedFileSystems[i].IsCached(spaceId, saveDataId)) - { - _cachedFileSystems[i].Unregister(); - } - } - } - - public UniqueLockRef GetScopedLock() - { - return new UniqueLockRef(ref _mutex); - } -} \ No newline at end of file diff --git a/src/LibHac/FsSystem/SaveDataFileSystemCacheRegisterBase.cs b/src/LibHac/FsSystem/SaveDataFileSystemCacheRegisterBase.cs deleted file mode 100644 index 459ada71..00000000 --- a/src/LibHac/FsSystem/SaveDataFileSystemCacheRegisterBase.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using LibHac.Common; -using LibHac.Diag; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.Tools.FsSystem.Save; - -namespace LibHac.FsSystem; - -/// -/// Wraps a save data . -/// Upon disposal the base file system is returned to the provided . -/// -/// The type of the base file system. Must be one of , -/// or . -/// Based on FS 13.1.0 (nnSdk 13.4.0) -public class SaveDataFileSystemCacheRegisterBase : IFileSystem where T : IFileSystem -{ - private SharedRef _baseFileSystem; - private ISaveDataFileSystemCacheManager _cacheManager; - - public SaveDataFileSystemCacheRegisterBase(ref SharedRef baseFileSystem, - ISaveDataFileSystemCacheManager cacheManager) - { - if (typeof(T) != typeof(SaveDataFileSystemHolder) && typeof(T) != typeof(ApplicationTemporaryFileSystem)) - { - throw new NotSupportedException( - $"The file system type of a {nameof(SaveDataFileSystemCacheRegisterBase)} must be {nameof(SaveDataFileSystemHolder)} or {nameof(ApplicationTemporaryFileSystem)}."); - } - - _baseFileSystem = SharedRef.CreateMove(ref baseFileSystem); - _cacheManager = cacheManager; - } - - public override void Dispose() - { - if (typeof(T) == typeof(SaveDataFileSystemHolder)) - { - _cacheManager.Register(ref Unsafe.As, SharedRef>(ref _baseFileSystem)); - } - else if (typeof(T) == typeof(ApplicationTemporaryFileSystem)) - { - _cacheManager.Register(ref Unsafe.As, SharedRef>(ref _baseFileSystem)); - } - else - { - Assert.SdkAssert(false, "Invalid save data file system type."); - } - } - - protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) - { - return _baseFileSystem.Get.OpenFile(ref outFile, path, mode); - } - - protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, - OpenDirectoryMode mode) - { - return _baseFileSystem.Get.OpenDirectory(ref outDirectory, path, mode); - } - - protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) - { - return _baseFileSystem.Get.GetEntryType(out entryType, path); - } - - protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) - { - return _baseFileSystem.Get.CreateFile(path, size, option); - } - - protected override Result DoDeleteFile(in Path path) - { - return _baseFileSystem.Get.DeleteFile(path); - } - - protected override Result DoCreateDirectory(in Path path) - { - return _baseFileSystem.Get.CreateDirectory(path); - } - - protected override Result DoDeleteDirectory(in Path path) - { - return _baseFileSystem.Get.DeleteDirectory(path); - } - - protected override Result DoDeleteDirectoryRecursively(in Path path) - { - return _baseFileSystem.Get.DeleteDirectoryRecursively(path); - } - - protected override Result DoCleanDirectoryRecursively(in Path path) - { - return _baseFileSystem.Get.CleanDirectoryRecursively(path); - } - - protected override Result DoRenameFile(in Path currentPath, in Path newPath) - { - return _baseFileSystem.Get.RenameFile(currentPath, newPath); - } - - protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) - { - return _baseFileSystem.Get.RenameDirectory(currentPath, newPath); - } - - protected override Result DoCommit() - { - return _baseFileSystem.Get.Commit(); - } - - protected override Result DoCommitProvisionally(long counter) - { - return _baseFileSystem.Get.CommitProvisionally(counter); - } - - protected override Result DoRollback() - { - return _baseFileSystem.Get.Rollback(); - } - - protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) - { - return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, path); - } - - protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) - { - return _baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, path); - } -} \ No newline at end of file diff --git a/src/LibHac/FsSystem/SaveDataFileSystemHolder.cs b/src/LibHac/FsSystem/SaveDataFileSystemHolder.cs deleted file mode 100644 index 5b5d35ff..00000000 --- a/src/LibHac/FsSystem/SaveDataFileSystemHolder.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using LibHac.Common; -using LibHac.Diag; -using LibHac.Fs; -using LibHac.Fs.Fsa; - -namespace LibHac.FsSystem; - -/// -/// Holds a file system for adding to the save data file system cache. -/// -/// Nintendo uses concrete types in instead of an interface. -/// This class allows to be cached in a way that changes the original -/// design as little as possible. -/// -public class SaveDataFileSystemHolder : ForwardingFileSystem -{ - public SaveDataFileSystemHolder(ref SharedRef baseFileSystem) : base(ref baseFileSystem) - { - Assert.SdkRequires(BaseFileSystem.Get.GetType() == typeof(SaveDataFileSystemHolder) || - BaseFileSystem.Get.GetType() == typeof(ApplicationTemporaryFileSystem)); - } - - public SaveDataSpaceId GetSaveDataSpaceId() - { - IFileSystem baseFs = BaseFileSystem.Get; - - if (baseFs.GetType() == typeof(DirectorySaveDataFileSystem)) - { - return ((DirectorySaveDataFileSystem)baseFs).GetSaveDataSpaceId(); - } - - throw new NotImplementedException(); - } - - public ulong GetSaveDataId() - { - IFileSystem baseFs = BaseFileSystem.Get; - - if (baseFs.GetType() == typeof(DirectorySaveDataFileSystem)) - { - return ((DirectorySaveDataFileSystem)baseFs).GetSaveDataId(); - } - - throw new NotImplementedException(); - } - - public Result RollbackOnlyModified() - { - IFileSystem baseFs = BaseFileSystem.Get; - - if (baseFs.GetType() == typeof(DirectorySaveDataFileSystem)) - { - return ((DirectorySaveDataFileSystem)baseFs).Rollback(); - } - - throw new NotImplementedException(); - } -} \ No newline at end of file