From b5158764b982df1c4e1492356f2210f2c0baf005 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 3 Aug 2024 17:31:04 -0700 Subject: [PATCH] Update the NCA filesystem service for FS 18 --- src/LibHac/Fs/FsEnums.cs | 1 + src/LibHac/FsSrv/Delegates.cs | 3 + src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs | 5 +- src/LibHac/FsSrv/FileSystemProxyImpl.cs | 8 +- src/LibHac/FsSrv/FileSystemServer.cs | 1 + .../FsSrv/FileSystemServerInitializer.cs | 12 +- .../FsCreator/EncryptedFileSystemCreator.cs | 57 ++++++- .../FsCreator/IEncryptedFileSystemCreator.cs | 4 +- .../FsSrv/FsCreator/IStorageOnNcaCreator.cs | 6 +- .../FsSrv/FsCreator/StorageOnNcaCreator.cs | 18 +-- src/LibHac/FsSrv/Impl/DeepRetryStorage.cs | 18 +-- .../IRomFileSystemAccessFailureManager.cs | 2 +- .../FsSrv/Impl/StorageAccessSpeedControl.cs | 44 ++++++ src/LibHac/FsSrv/NcaFileSystemService.cs | 149 ++++++++---------- src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs | 108 +++++++------ .../FsSrv/SaveDataFileSystemServiceImpl.cs | 2 +- src/LibHac/FsSystem/AsynchronousAccess.cs | 65 ++++---- .../FsSystem/BlockCacheBufferedStorage.cs | 8 +- src/LibHac/FsSystem/CompressedStorage.cs | 24 ++- src/LibHac/FsSystem/CompressionCommon.cs | 29 ++-- src/LibHac/FsSystem/NcaFileSystemDriver.cs | 16 +- src/LibHac/FsSystem/NcaReader.cs | 10 +- .../FsSystem/StorageLayoutTypeSetter.cs | 2 + .../Tools/FsSystem/CompressedStorage.cs | 2 +- 24 files changed, 323 insertions(+), 271 deletions(-) create mode 100644 src/LibHac/FsSrv/Impl/StorageAccessSpeedControl.cs diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index c98d5a2b..a9ce3a03 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -124,6 +124,7 @@ public enum OperationId QueryUnpreparedRange = 4, QueryLazyLoadCompletionRate = 5, SetLazyLoadPriority = 6, + GetAsynchronousAccessSplitter = 7, ReadyLazyLoadFile = 10001 } diff --git a/src/LibHac/FsSrv/Delegates.cs b/src/LibHac/FsSrv/Delegates.cs index b20d67b5..c7ae25a0 100644 --- a/src/LibHac/FsSrv/Delegates.cs +++ b/src/LibHac/FsSrv/Delegates.cs @@ -1,5 +1,6 @@ using System; using LibHac.Common; +using LibHac.Fs; using LibHac.FsSrv.FsCreator; namespace LibHac.FsSrv; @@ -7,6 +8,8 @@ namespace LibHac.FsSrv; public delegate Result GenerateSeedUniqueMac(Span outMacBuffer, ReadOnlySpan data, ReadOnlySpan seed); public delegate Result GenerateDeviceUniqueMac(Span outMacBuffer, ReadOnlySpan data, DeviceUniqueMacType macType); +public delegate void GenerateSdEncryptionKey(Span outKey, IEncryptedFileSystemCreator.KeyId keyId, in EncryptionSeed seed); + public delegate Result SaveTransferAesKeyGenerator(Span outKeyBuffer, SaveDataTransferCryptoConfiguration.KeyIndex index, ReadOnlySpan keySource, int keyGeneration); diff --git a/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs b/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs index 1347724b..d9e870d8 100644 --- a/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs +++ b/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs @@ -66,7 +66,7 @@ public class FileSystemProxyCoreImpl tempFs.SetByMove(ref fileSystem.Ref); res = _fsCreators.EncryptedFileSystemCreator.Create(ref fileSystem.Ref, in tempFs, - IEncryptedFileSystemCreator.KeyId.CustomStorage, in _sdEncryptionSeed); + IEncryptedFileSystemCreator.KeyId.CustomStorage); if (res.IsFailure()) return res.Miss(); } else @@ -114,7 +114,6 @@ public class FileSystemProxyCoreImpl public Result SetSdCardEncryptionSeed(in EncryptionSeed seed) { - _sdEncryptionSeed = seed; - return Result.Success; + return _fsCreators.EncryptedFileSystemCreator.SetEncryptionSeed(IEncryptedFileSystemCreator.KeyId.Save, in seed).Ret(); } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/FileSystemProxyImpl.cs b/src/LibHac/FsSrv/FileSystemProxyImpl.cs index fbad74a4..6c46aed6 100644 --- a/src/LibHac/FsSrv/FileSystemProxyImpl.cs +++ b/src/LibHac/FsSrv/FileSystemProxyImpl.cs @@ -957,13 +957,7 @@ public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader res = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService); if (res.IsFailure()) return res.Miss(); - res = saveFsService.SetSdCardEncryptionSeed(in seed); - if (res.IsFailure()) return res.Miss(); - - res = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); - if (res.IsFailure()) return res.Miss(); - - return ncaFsService.SetSdCardEncryptionSeed(in seed).Ret(); + return saveFsService.SetSdCardEncryptionSeed(in seed).Ret(); } public Result GetAndClearErrorInfo(out FileSystemProxyErrorInfo errorInfo) diff --git a/src/LibHac/FsSrv/FileSystemServer.cs b/src/LibHac/FsSrv/FileSystemServer.cs index b2080640..3f5690b2 100644 --- a/src/LibHac/FsSrv/FileSystemServer.cs +++ b/src/LibHac/FsSrv/FileSystemServer.cs @@ -47,6 +47,7 @@ internal struct FileSystemServerGlobals : IDisposable public GameCardServiceGlobals GameCardService; public HierarchicalIntegrityVerificationStorageGlobals HierarchicalIntegrityVerificationStorage; public SpeedEmulationConfigurationGlobals SpeedEmulationConfiguration; + public StorageAccessSpeedControlGlobals StorageAccessSpeedControl; public void Initialize(HorizonClient horizonClient, FileSystemServer fsServer) { diff --git a/src/LibHac/FsSrv/FileSystemServerInitializer.cs b/src/LibHac/FsSrv/FileSystemServerInitializer.cs index 4f5f77ef..2ab2e27d 100644 --- a/src/LibHac/FsSrv/FileSystemServerInitializer.cs +++ b/src/LibHac/FsSrv/FileSystemServerInitializer.cs @@ -15,6 +15,9 @@ public static class FileSystemServerInitializer { private const ulong SpeedEmulationProgramIdWithoutPlatformIdMinimum = 0; private const ulong SpeedEmulationProgramIdWithoutPlatformIdMaximum = 0x1FFF; + + private const ulong StorageAccessSpeedControlProgramIdWithoutPlatformIdMinimum = 0x3000; + private const ulong StorageAccessSpeedControlProgramIdWithoutPlatformIdMaximum = 0x_00FF_FFFF_FFFF_FFFF; private const uint ContentDivisionSize = ConcatenationFileSystem.DefaultInternalFileSize; @@ -109,9 +112,11 @@ public static class FileSystemServerInitializer var accessFailureManagementService = new AccessFailureManagementServiceImpl(in accessFailureManagementServiceConfig); - var speedEmulationRange = - new InternalProgramIdRangeForSpeedEmulation(SpeedEmulationProgramIdWithoutPlatformIdMinimum, - SpeedEmulationProgramIdWithoutPlatformIdMaximum); + var speedEmulationRange = new InternalProgramIdRangeForSpeedEmulation( + SpeedEmulationProgramIdWithoutPlatformIdMinimum, SpeedEmulationProgramIdWithoutPlatformIdMaximum); + + var storageAccessSpeedControlRange = new InternalProgramIdRangeForStorageAccessSpeedControl( + StorageAccessSpeedControlProgramIdWithoutPlatformIdMinimum, StorageAccessSpeedControlProgramIdWithoutPlatformIdMaximum); var ncaFsServiceConfig = new NcaFileSystemServiceImpl.Configuration(); ncaFsServiceConfig.BaseFsService = baseFsService; @@ -127,6 +132,7 @@ public static class FileSystemServerInitializer ncaFsServiceConfig.SpeedEmulationRange = speedEmulationRange; ncaFsServiceConfig.AddOnContentDivisionSize = ContentDivisionSize; ncaFsServiceConfig.RomDivisionSize = ContentDivisionSize; + ncaFsServiceConfig.StorageAccessSpeedControlRange = storageAccessSpeedControlRange; ncaFsServiceConfig.FsServer = server; var ncaFsService = new NcaFileSystemServiceImpl(in ncaFsServiceConfig); diff --git a/src/LibHac/FsSrv/FsCreator/EncryptedFileSystemCreator.cs b/src/LibHac/FsSrv/FsCreator/EncryptedFileSystemCreator.cs index 94650694..dd3f2f1f 100644 --- a/src/LibHac/FsSrv/FsCreator/EncryptedFileSystemCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/EncryptedFileSystemCreator.cs @@ -1,7 +1,11 @@ -using LibHac.Common; +#pragma warning disable CS0169 // Field is never used +using System.Runtime.CompilerServices; +using LibHac.Common; using LibHac.Common.Keys; +using LibHac.Diag; using LibHac.Fs; using LibHac.Fs.Fsa; +using LibHac.FsSystem; using LibHac.Tools.FsSystem; using static LibHac.FsSrv.FsCreator.IEncryptedFileSystemCreator; @@ -9,28 +13,67 @@ namespace LibHac.FsSrv.FsCreator; public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator { - private KeySet KeySet { get; } + private readonly KeySet _keySet; + private Configuration _configuration; + private EncryptionSeed _seed; + + public struct Configuration + { + public RandomDataGenerator GenerateRandomData; + public GenerateSdEncryptionKey GenerateSdEncryptionKey; + } public EncryptedFileSystemCreator(KeySet keySet) { - KeySet = keySet; + _keySet = keySet; } - public Result Create(ref SharedRef outEncryptedFileSystem, ref readonly SharedRef baseFileSystem, KeyId idIndex, in EncryptionSeed encryptionSeed) + private ref readonly EncryptionSeed GetSeed(KeyId keyId) { - if (idIndex < KeyId.Save || idIndex > KeyId.CustomStorage) + switch (keyId) + { + case KeyId.Save: + case KeyId.Content: + case KeyId.CustomStorage: + return ref _seed; + default: + Abort.UnexpectedDefault(); + return ref Unsafe.NullRef(); + } + } + + public Result Create(ref SharedRef outEncryptedFileSystem, ref readonly SharedRef baseFileSystem, KeyId keyId) + { + if (keyId < KeyId.Save || keyId > KeyId.CustomStorage) { return ResultFs.InvalidArgument.Log(); } // todo: "proper" key generation instead of a lazy hack - KeySet.SetSdSeed(encryptionSeed.Value); + _keySet.SetSdSeed(GetSeed(keyId).Value); using var encryptedFileSystem = new SharedRef(new AesXtsFileSystem(in baseFileSystem, - KeySet.SdCardEncryptionKeys[(int)idIndex].DataRo.ToArray(), 0x4000)); + _keySet.SdCardEncryptionKeys[(int)keyId].DataRo.ToArray(), 0x4000)); outEncryptedFileSystem.SetByMove(ref encryptedFileSystem.Ref); return Result.Success; } + + public Result SetEncryptionSeed(KeyId keyId, in EncryptionSeed encryptionSeed) + { + switch (keyId) + { + case KeyId.Save: + case KeyId.Content: + case KeyId.CustomStorage: + _seed = encryptionSeed; + break; + default: + Abort.UnexpectedDefault(); + break; + } + + return Result.Success; + } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/FsCreator/IEncryptedFileSystemCreator.cs b/src/LibHac/FsSrv/FsCreator/IEncryptedFileSystemCreator.cs index dcb182eb..291ea302 100644 --- a/src/LibHac/FsSrv/FsCreator/IEncryptedFileSystemCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/IEncryptedFileSystemCreator.cs @@ -14,5 +14,7 @@ public interface IEncryptedFileSystemCreator } Result Create(ref SharedRef outEncryptedFileSystem, ref readonly SharedRef baseFileSystem, - KeyId idIndex, in EncryptionSeed encryptionSeed); + KeyId keyId); + + Result SetEncryptionSeed(KeyId keyId, in EncryptionSeed encryptionSeed); } \ No newline at end of file diff --git a/src/LibHac/FsSrv/FsCreator/IStorageOnNcaCreator.cs b/src/LibHac/FsSrv/FsCreator/IStorageOnNcaCreator.cs index d8589fd6..ecfabbe7 100644 --- a/src/LibHac/FsSrv/FsCreator/IStorageOnNcaCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/IStorageOnNcaCreator.cs @@ -6,12 +6,10 @@ namespace LibHac.FsSrv.FsCreator; public interface IStorageOnNcaCreator { - Result Create(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader, + Result Create(ref SharedRef outStorage, ref NcaFsHeaderReader outHeaderReader, ref readonly SharedRef ncaReader, int fsIndex); - Result CreateWithPatch(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader, + Result CreateWithPatch(ref SharedRef outStorage, ref NcaFsHeaderReader outHeaderReader, ref readonly SharedRef originalNcaReader, ref readonly SharedRef currentNcaReader, int fsIndex); diff --git a/src/LibHac/FsSrv/FsCreator/StorageOnNcaCreator.cs b/src/LibHac/FsSrv/FsCreator/StorageOnNcaCreator.cs index 7c833309..35e61ac4 100644 --- a/src/LibHac/FsSrv/FsCreator/StorageOnNcaCreator.cs +++ b/src/LibHac/FsSrv/FsCreator/StorageOnNcaCreator.cs @@ -27,28 +27,22 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator _hashGeneratorFactorySelector = hashGeneratorFactorySelector; } - public Result Create(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader, - ref readonly SharedRef ncaReader, int fsIndex) + public Result Create(ref SharedRef outStorage, ref NcaFsHeaderReader outHeaderReader, ref readonly SharedRef ncaReader, int fsIndex) { var ncaFsDriver = new NcaFileSystemDriver(in ncaReader, _memoryResource, _bufferManager, _hashGeneratorFactorySelector); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, - ref storageAccessSplitter.Ref, ref outHeaderReader, fsIndex)); + Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, ref outHeaderReader, fsIndex)); if (res.IsFailure()) return res.Miss(); using var resultConvertStorage = new SharedRef(new RomResultConvertStorage(in storage)); - outStorage.SetByMove(ref resultConvertStorage.Ref); - outStorageAccessSplitter.SetByMove(ref storageAccessSplitter.Ref); return Result.Success; } public Result CreateWithPatch(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader, + ref NcaFsHeaderReader outHeaderReader, ref readonly SharedRef originalNcaReader, ref readonly SharedRef currentNcaReader, int fsIndex) { @@ -56,15 +50,11 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator _bufferManager, _hashGeneratorFactorySelector); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, - ref storageAccessSplitter.Ref, ref outHeaderReader, fsIndex)); + Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, ref outHeaderReader, fsIndex)); if (res.IsFailure()) return res.Miss(); using var resultConvertStorage = new SharedRef(new RomResultConvertStorage(in storage)); - outStorage.SetByMove(ref resultConvertStorage.Ref); - outStorageAccessSplitter.SetByMove(ref storageAccessSplitter.Ref); return Result.Success; } diff --git a/src/LibHac/FsSrv/Impl/DeepRetryStorage.cs b/src/LibHac/FsSrv/Impl/DeepRetryStorage.cs index e6a803e9..fbbd1256 100644 --- a/src/LibHac/FsSrv/Impl/DeepRetryStorage.cs +++ b/src/LibHac/FsSrv/Impl/DeepRetryStorage.cs @@ -12,7 +12,6 @@ namespace LibHac.FsSrv.Impl; public class DeepRetryStorage : IStorage { private AsynchronousAccessStorage _asyncStorage; - private SharedRef _accessSplitter; private SharedRef _parent; private UniqueRef _mountCountLock; private DataStorageContext _dataStorageContext; @@ -52,14 +51,12 @@ public class DeepRetryStorage : IStorage } public DeepRetryStorage(ref readonly SharedRef baseStorage, - ref readonly SharedRef accessSplitter, ref readonly SharedRef parent, ref UniqueRef mountCountSemaphore, bool deepRetryEnabled, FileSystemServer fsServer) { // Missing: Getting the thread pool via GetRegisteredThreadPool() - _asyncStorage = new AsynchronousAccessStorage(in baseStorage, accessSplitter.Get); - _accessSplitter = SharedRef.CreateCopy(in accessSplitter); + _asyncStorage = new AsynchronousAccessStorage(in baseStorage); _parent = SharedRef.CreateCopy(in parent); _mountCountLock = UniqueRef.Create(ref mountCountSemaphore); _dataStorageContext = new DataStorageContext(); @@ -70,14 +67,12 @@ public class DeepRetryStorage : IStorage } public DeepRetryStorage(ref readonly SharedRef baseStorage, - ref readonly SharedRef accessSplitter, ref readonly SharedRef parent, ref UniqueRef mountCountSemaphore, in Hash hash, ulong programId, StorageId storageId, FileSystemServer fsServer) { // Missing: Getting the thread pool via GetRegisteredThreadPool() - _asyncStorage = new AsynchronousAccessStorage(in baseStorage, accessSplitter.Get); - _accessSplitter = SharedRef.CreateCopy(in accessSplitter); + _asyncStorage = new AsynchronousAccessStorage(in baseStorage); _parent = SharedRef.CreateCopy(in parent); _mountCountLock = UniqueRef.Create(ref mountCountSemaphore); _dataStorageContext = new DataStorageContext(in hash, programId, storageId); @@ -92,7 +87,6 @@ public class DeepRetryStorage : IStorage _readWriteLock.Dispose(); _mountCountLock.Destroy(); _parent.Destroy(); - _accessSplitter.Destroy(); _asyncStorage.Dispose(); base.Dispose(); @@ -143,7 +137,6 @@ public class DeepRetryStorage : IStorage Assert.SdkNotNull(_parent); using var remountStorage = new SharedRef(); - using var remountStorageAccessSplitter = new SharedRef(); const int maxRetryCount = 2; @@ -151,8 +144,8 @@ public class DeepRetryStorage : IStorage Hash digest = default; for (int i = 0; i < maxRetryCount; i++) { - retryResult = _parent.Get.OpenDataStorageCore(ref remountStorage.Ref, ref remountStorageAccessSplitter.Ref, - ref digest, _dataStorageContext.GetProgramIdValue(), _dataStorageContext.GetStorageId()); + retryResult = _parent.Get.OpenDataStorageCore(ref remountStorage.Ref, ref digest, + _dataStorageContext.GetProgramIdValue(), _dataStorageContext.GetStorageId()); if (!ResultFs.DataCorrupted.Includes(retryResult)) break; @@ -170,8 +163,7 @@ public class DeepRetryStorage : IStorage return ResultFs.NcaDigestInconsistent.Log(); } - _accessSplitter.SetByMove(ref remountStorageAccessSplitter.Ref); - _asyncStorage.SetBaseStorage(in remountStorage, _accessSplitter.Get); + _asyncStorage.SetBaseStorage(in remountStorage); return Result.Success; } diff --git a/src/LibHac/FsSrv/Impl/IRomFileSystemAccessFailureManager.cs b/src/LibHac/FsSrv/Impl/IRomFileSystemAccessFailureManager.cs index efe76eed..103d3b34 100644 --- a/src/LibHac/FsSrv/Impl/IRomFileSystemAccessFailureManager.cs +++ b/src/LibHac/FsSrv/Impl/IRomFileSystemAccessFailureManager.cs @@ -8,7 +8,7 @@ namespace LibHac.FsSrv.Impl; public interface IRomFileSystemAccessFailureManager : IDisposable { - Result OpenDataStorageCore(ref SharedRef outStorage, ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, ulong id, StorageId storageId); + Result OpenDataStorageCore(ref SharedRef outStorage, ref Hash outNcaDigest, ulong id, StorageId storageId); Result HandleResolubleAccessFailure(out bool wasDeferred, Result nonDeferredResult); void IncrementRomFsDeepRetryStartCount(); void IncrementRomFsRemountForDataCorruptionCount(); diff --git a/src/LibHac/FsSrv/Impl/StorageAccessSpeedControl.cs b/src/LibHac/FsSrv/Impl/StorageAccessSpeedControl.cs new file mode 100644 index 00000000..97c61ae3 --- /dev/null +++ b/src/LibHac/FsSrv/Impl/StorageAccessSpeedControl.cs @@ -0,0 +1,44 @@ +namespace LibHac.FsSrv +{ + public readonly struct InternalProgramIdRangeForStorageAccessSpeedControl + { + public readonly ulong ProgramIdWithoutPlatformIdMin; + public readonly ulong ProgramIdWithoutPlatformIdMax; + + public InternalProgramIdRangeForStorageAccessSpeedControl(ulong min, ulong max) + { + ProgramIdWithoutPlatformIdMin = min; + ProgramIdWithoutPlatformIdMax = max; + } + } +} + +namespace LibHac.FsSrv.Impl +{ + internal struct StorageAccessSpeedControlGlobals + { + public InternalProgramIdRangeForStorageAccessSpeedControl TargetProgramIdRange; + } + + /// + /// Handles getting and setting the configuration for storage access speed control. + /// + /// Based on nnSdk 18.3.0 (FS 18.0.0) + public static class StorageAccessSpeedControl + { + public static void SetTargetProgramIdRange(FileSystemServer fsServer, + InternalProgramIdRangeForStorageAccessSpeedControl range) + { + fsServer.Globals.StorageAccessSpeedControl.TargetProgramIdRange = range; + } + + public static bool IsTargetProgramId(FileSystemServer fsServer, ulong programId) + { + var range = fsServer.Globals.StorageAccessSpeedControl.TargetProgramIdRange; + ulong programIdWithoutPlatformId = Utility.ClearPlatformIdInProgramId(programId); + + return programIdWithoutPlatformId >= range.ProgramIdWithoutPlatformIdMin && + programIdWithoutPlatformId <= range.ProgramIdWithoutPlatformIdMax; + } + } +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/NcaFileSystemService.cs b/src/LibHac/FsSrv/NcaFileSystemService.cs index c96b4d3f..730251d7 100644 --- a/src/LibHac/FsSrv/NcaFileSystemService.cs +++ b/src/LibHac/FsSrv/NcaFileSystemService.cs @@ -24,7 +24,7 @@ namespace LibHac.FsSrv; /// /// FS will have one instance of this class for every connected process. /// The FS permissions of the calling process are checked on every function call. -///
Based on nnSdk 17.5.0 (FS 17.0.0)
+///
Based on nnSdk 18.3.0 (FS 18.0.0) internal class NcaFileSystemService : IRomFileSystemAccessFailureManager { private const int AocSemaphoreCount = 128; @@ -95,18 +95,18 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenFileSystemWithPatch(ref SharedRef outFileSystem, ProgramId programId, FileSystemProxyType type) { - const StorageLayoutType storageFlag = StorageLayoutType.All; - using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); - // Get the program info for the caller and verify permissions - Result res = GetProgramInfo(out ProgramInfo callerProgramInfo); + Result res = GetProgramInfo(out ProgramInfo programInfo); if (res.IsFailure()) return res.Miss(); + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(programInfo.ProgramIdValue); + using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); + switch (type) { case FileSystemProxyType.Manual: Accessibility accessibility = - callerProgramInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentManual); + programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentManual); if (!accessibility.CanRead) return ResultFs.PermissionDenied.Log(); @@ -123,14 +123,14 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager } // Get the program info for the owner of the file system being opened - res = GetProgramInfoByProgramId(out ProgramInfo ownerProgramInfo, programId.Value); + res = GetProgramInfoByProgramId(out ProgramInfo applicationProgramInfo, programId.Value); if (res.IsFailure()) return res.Miss(); // Try to find the path to the original version of the file system using var originalPath = new Path(); Result originalResult = _serviceImpl.ResolveApplicationHtmlDocumentPath(out bool isDirectory, ref originalPath.Ref(), out ContentAttributes contentAttributes, out ulong originalProgramId, - programId.Value, ownerProgramInfo.StorageId); + programId.Value, applicationProgramInfo.StorageId); // The file system might have a patch version with no original version, so continue if not found if (originalResult.IsFailure() && !ResultLr.HtmlDocumentNotFound.Includes(originalResult)) @@ -334,8 +334,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager _serviceImpl.IncrementRomFsUnrecoverableByGameCardAccessFailedCount(); } - private Result OpenDataStorageCore(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, ulong id, + private Result OpenDataStorageCore(ref SharedRef outStorage, ref Hash outNcaDigest, ulong id, StorageId storageId) { using var programPath = new Path(); @@ -347,7 +346,6 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager out ContentAttributes patchContentAttributes, id); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); if (ResultLr.ProgramNotFound.Includes(patchResult)) { @@ -360,8 +358,8 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (originalResult.IsFailure()) return originalResult.Miss(); - Result res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref storageAccessSplitter.Ref, - ref outNcaDigest, in programPath, contentAttributes, FileSystemProxyType.Rom, id); + Result res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref outNcaDigest, in programPath, + contentAttributes, FileSystemProxyType.Rom, id); if (res.IsFailure()) return res.Miss(); } else @@ -373,14 +371,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager ? ref programPath : ref PathExtensions.GetNullRef(); - Result res = _serviceImpl.OpenStorageWithPatch(ref storage.Ref, ref storageAccessSplitter.Ref, - ref outNcaDigest, in originalNcaPath, contentAttributes, in patchPath, patchContentAttributes, - FileSystemProxyType.Rom, originalProgramId, id); + Result res = _serviceImpl.OpenStorageWithPatch(ref storage.Ref, ref outNcaDigest, in originalNcaPath, + contentAttributes, in patchPath, patchContentAttributes, FileSystemProxyType.Rom, originalProgramId, id); if (res.IsFailure()) return res.Miss(); } outStorage.SetByMove(ref storage.Ref); - outStorageAccessSplitter.SetByMove(ref storageAccessSplitter.Ref); return Result.Success; } @@ -401,8 +397,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager StorageId storageId = programInfo.StorageId; using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - res = OpenDataStorageCore(ref storage.Ref, ref storageAccessSplitter.Ref, ref digest, programInfo.ProgramIdValue, storageId); + res = OpenDataStorageCore(ref storage.Ref, ref digest, programInfo.ProgramIdValue, storageId); if (res.IsFailure()) return res.Miss(); using var romDivisionSizeUnitCountSemaphore = new UniqueRef(); @@ -412,9 +407,9 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using SharedRef accessFailureManager = GetSharedAccessFailureManagerFromThis(); - using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in storageAccessSplitter, - in accessFailureManager, ref romDivisionSizeUnitCountSemaphore.Ref, in digest, programInfo.ProgramIdValue, - storageId, _serviceImpl.FsServer)); + using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in accessFailureManager, + ref romDivisionSizeUnitCountSemaphore.Ref, in digest, programInfo.ProgramIdValue, storageId, + _serviceImpl.FsServer)); using var typeSetStorage = new SharedRef(new StorageLayoutTypeSetStorage(in retryStorage, storageFlag)); using var storageAdapter = new SharedRef(new StorageInterfaceAdapter(in typeSetStorage)); @@ -452,9 +447,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager res = ncaPath.Normalize(flags); if (res.IsFailure()) return res.Miss(); - using var storageAccessSplitter = new SharedRef(); - res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref storageAccessSplitter.Ref, ref digest, in ncaPath, - attributes, type, ulong.MaxValue); + res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref digest, in ncaPath, attributes, type, ulong.MaxValue); if (res.IsFailure()) return res.Miss(); using var romDivisionSizeUnitCountSemaphore = new UniqueRef(); @@ -464,9 +457,9 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using SharedRef accessFailureManager = GetSharedAccessFailureManagerFromThis(); - using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in storageAccessSplitter, - in accessFailureManager, ref romDivisionSizeUnitCountSemaphore.Ref, in digest, ProgramId.InvalidId.Value, - StorageId.None, _serviceImpl.FsServer)); + using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in accessFailureManager, + ref romDivisionSizeUnitCountSemaphore.Ref, in digest, ProgramId.InvalidId.Value, StorageId.None, + _serviceImpl.FsServer)); using var typeSetStorage = new SharedRef(new StorageLayoutTypeSetStorage(in retryStorage, storageFlag)); using var storageAdapter = new SharedRef(new StorageInterfaceAdapter(in typeSetStorage)); @@ -478,12 +471,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenDataStorageByProgramId(ref SharedRef outStorage, ProgramId programId) { - StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(programId.Value); - using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); - Result res = GetProgramInfoByProgramId(out ProgramInfo programInfo, programId.Value); if (res.IsFailure()) return res.Miss(); + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(programId.Value, programInfo.ProgramIdValue); + using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); + Hash digest = default; using var romMountCountSemaphore = new UniqueRef(); @@ -491,8 +484,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (res.IsFailure()) return res.Miss(); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - res = OpenDataStorageCore(ref storage.Ref, ref storageAccessSplitter.Ref, ref digest, programId.Value, programInfo.StorageId); + res = OpenDataStorageCore(ref storage.Ref, ref digest, programId.Value, programInfo.StorageId); if (res.IsFailure()) return res.Miss(); res = GetProgramInfo(out ProgramInfo properProgramInfo); @@ -508,9 +500,9 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using SharedRef accessFailureManager = GetSharedAccessFailureManagerFromThis(); - using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in storageAccessSplitter, - in accessFailureManager, ref romDivisionSizeUnitCountSemaphore.Ref, in digest, programId.Value, - programInfo.StorageId, _serviceImpl.FsServer)); + using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in accessFailureManager, + ref romDivisionSizeUnitCountSemaphore.Ref, in digest, programId.Value, programInfo.StorageId, + _serviceImpl.FsServer)); using var typeSetStorage = new SharedRef(new StorageLayoutTypeSetStorage(in retryStorage, storageFlag)); using var storageAdapter = new SharedRef(new StorageInterfaceAdapter(in typeSetStorage)); @@ -523,12 +515,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenFileSystemWithId(ref SharedRef outFileSystem, in FspPath path, ContentAttributes attributes, ulong id, FileSystemProxyType type) { - const StorageLayoutType storageFlag = StorageLayoutType.All; - using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); - Result res = GetProgramInfo(out ProgramInfo programInfo); if (res.IsFailure()) return res.Miss(); + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(id, programInfo.ProgramIdValue); + using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); + AccessControl ac = programInfo.AccessControl; switch (type) @@ -626,12 +618,14 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenDataStorageByDataId(ref SharedRef outStorage, DataId dataId, StorageId storageId) { - Result res; - - StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(dataId.Value); - using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); + Result res = GetProgramInfo(out ProgramInfo programInfo); + if (res.IsFailure()) return res.Miss(); bool isAoc = storageId == StorageId.None; + DataId targetDataId = _serviceImpl.RedirectDataId(dataId, storageId); + + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(targetDataId.Value, programInfo.ProgramIdValue); + using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); using var systemDataPath = new Path(); using var systemDataPatchPath = new Path(); @@ -642,38 +636,33 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (isAoc) { res = _serviceImpl.ResolveAddOnContentPath(ref systemDataPath.Ref(), out contentAttributes, - ref systemDataPatchPath.Ref(), out patchContentAttributes, dataId); + ref systemDataPatchPath.Ref(), out patchContentAttributes, targetDataId); if (res.IsFailure()) return res.Miss(); } else { - res = _serviceImpl.ResolveDataPath(ref systemDataPath.Ref(), out contentAttributes, dataId, storageId); + res = _serviceImpl.ResolveDataPath(ref systemDataPath.Ref(), out contentAttributes, targetDataId, storageId); if (res.IsFailure()) return res.Miss(); Assert.SdkAssert(systemDataPatchPath.IsEmpty()); } - res = GetProgramInfo(out ProgramInfo programInfo); - if (res.IsFailure()) return res.Miss(); - var accessibility = programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountSystemDataPrivate); bool canMountSystemDataPrivate = accessibility.CanRead; using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); if (systemDataPatchPath.IsEmpty()) { - res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref storageAccessSplitter.Ref, - ref Unsafe.NullRef(), in systemDataPath, contentAttributes, FileSystemProxyType.Data, - dataId.Value, canMountSystemDataPrivate); + res = _serviceImpl.OpenDataStorage(ref storage.Ref, ref Unsafe.NullRef(), in systemDataPath, + contentAttributes, FileSystemProxyType.Data, targetDataId.Value, canMountSystemDataPrivate); if (res.IsFailure()) return res.Miss(); } else { - res = _serviceImpl.OpenStorageWithPatch(ref storage.Ref, ref storageAccessSplitter.Ref, - ref Unsafe.NullRef(), in systemDataPath, contentAttributes, in systemDataPatchPath, - patchContentAttributes, FileSystemProxyType.Data, dataId.Value, dataId.Value, canMountSystemDataPrivate); + res = _serviceImpl.OpenStorageWithPatch(ref storage.Ref, ref Unsafe.NullRef(), in systemDataPath, + contentAttributes, in systemDataPatchPath, patchContentAttributes, FileSystemProxyType.Data, + targetDataId.Value, targetDataId.Value, canMountSystemDataPrivate); if (res.IsFailure()) return res.Miss(); } @@ -687,8 +676,8 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using SharedRef accessFailureManager = GetSharedAccessFailureManagerFromThis(); - using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in storageAccessSplitter, - in accessFailureManager, ref mountCountSemaphore.Ref, deepRetryEnabled: isAoc, _serviceImpl.FsServer)); + using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in accessFailureManager, + ref mountCountSemaphore.Ref, deepRetryEnabled: isAoc, _serviceImpl.FsServer)); using var typeSetStorage = new SharedRef(new StorageLayoutTypeSetStorage(in retryStorage, storageFlag)); using var storageAdapter = new SharedRef(new StorageInterfaceAdapter(in typeSetStorage)); @@ -701,12 +690,13 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenDataFileSystemByDataId(ref SharedRef outFileSystem, DataId dataId, StorageId storageId) { Result res; + + bool isAoc = storageId == StorageId.None; + DataId targetDataId = _serviceImpl.RedirectDataId(dataId, storageId); StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(dataId.Value); using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); - bool isAoc = storageId == StorageId.None; - using var dataPath = new Path(); using var dataPatchPathUnused = new Path(); @@ -715,12 +705,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (isAoc) { res = _serviceImpl.ResolveAddOnContentPath(ref dataPath.Ref(), out contentAttributes, - ref dataPatchPathUnused.Ref(), out _, dataId); + ref dataPatchPathUnused.Ref(), out _, targetDataId); if (res.IsFailure()) return res.Miss(); } else { - res = _serviceImpl.ResolveDataPath(ref dataPath.Ref(), out contentAttributes, dataId, storageId); + res = _serviceImpl.ResolveDataPath(ref dataPath.Ref(), out contentAttributes, targetDataId, storageId); if (res.IsFailure()) return res.Miss(); Assert.SdkAssert(dataPatchPathUnused.IsEmpty()); @@ -728,7 +718,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using var fileSystem = new SharedRef(); res = _serviceImpl.OpenDataFileSystem(ref fileSystem.Ref, in dataPath, contentAttributes, - FileSystemProxyType.Data, dataId.Value, isDirectory: true); + FileSystemProxyType.Data, targetDataId.Value, isDirectory: true); if (!res.IsSuccess()) { @@ -766,7 +756,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (res.IsFailure()) return res.Miss(); // Verify the caller has access to the file system - if (targetProgramId != programInfo.ProgramId && + if (programInfo.ProgramId != targetProgramId && !programInfo.AccessControl.HasContentOwnerId(targetProgramId.Value)) { return ResultFs.PermissionDenied.Log(); @@ -790,7 +780,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager res = _serviceImpl.ResolveRomReferenceProgramId(out ProgramId targetProgramId, programInfo.ProgramId, programIndex); if (res.IsFailure()) return res.Miss(); - StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(targetProgramId.Value); + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlag(targetProgramId.Value, programInfo.ProgramIdValue); using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); Hash digest = default; @@ -800,8 +790,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager if (res.IsFailure()) return res.Miss(); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - res = OpenDataStorageCore(ref storage.Ref, ref storageAccessSplitter.Ref, ref digest, targetProgramId.Value, programInfo.StorageId); + res = OpenDataStorageCore(ref storage.Ref, ref digest, targetProgramId.Value, programInfo.StorageId); if (res.IsFailure()) return res.Miss(); if (programInfo.ProgramId != targetProgramId && !programInfo.AccessControl.HasContentOwnerId(targetProgramId.Value)) @@ -814,9 +803,9 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager using SharedRef accessFailureManager = GetSharedAccessFailureManagerFromThis(); - using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in storageAccessSplitter, - in accessFailureManager, ref romDivisionSizeUnitCountSemaphore.Ref, in digest, targetProgramId.Value, - programInfo.StorageId, _serviceImpl.FsServer)); + using var retryStorage = new SharedRef(new DeepRetryStorage(in storage, in accessFailureManager, + ref romDivisionSizeUnitCountSemaphore.Ref, in digest, targetProgramId.Value, programInfo.StorageId, + _serviceImpl.FsServer)); using var typeSetStorage = new SharedRef(new StorageLayoutTypeSetStorage(in retryStorage, storageFlag)); using var storageAdapter = new SharedRef(new StorageInterfaceAdapter(in typeSetStorage)); @@ -955,12 +944,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager public Result OpenContentStorageFileSystem(ref SharedRef outFileSystem, ContentStorageId contentStorageId) { - StorageLayoutType storageFlag = contentStorageId == ContentStorageId.System ? StorageLayoutType.Bis : StorageLayoutType.All; - using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); - Result res = GetProgramInfo(out ProgramInfo programInfo); if (res.IsFailure()) return res.Miss(); + StorageLayoutType storageFlag = _serviceImpl.GetStorageFlagByContentStorageId(contentStorageId, programInfo.ProgramIdValue); + using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag); + Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentStorage); if (!accessibility.CanRead || !accessibility.CanWrite) @@ -1088,17 +1077,6 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager return Result.Success; } - public Result SetSdCardEncryptionSeed(in EncryptionSeed encryptionSeed) - { - Result res = GetProgramInfo(out ProgramInfo programInfo); - if (res.IsFailure()) return res.Miss(); - - if (!programInfo.AccessControl.CanCall(OperationType.SetEncryptionSeed)) - return ResultFs.PermissionDenied.Log(); - - return _serviceImpl.SetSdCardEncryptionSeed(in encryptionSeed).Ret(); - } - public Result OpenHostFileSystem(ref SharedRef outFileSystem, ref readonly FspPath path) { Result res = GetProgramInfo(out ProgramInfo programInfo); @@ -1163,9 +1141,8 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager } Result IRomFileSystemAccessFailureManager.OpenDataStorageCore(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, ulong id, - StorageId storageId) + ref Hash outNcaDigest, ulong id, StorageId storageId) { - return OpenDataStorageCore(ref outStorage, ref outStorageAccessSplitter, ref outNcaDigest, id, storageId).Ret(); + return OpenDataStorageCore(ref outStorage, ref outNcaDigest, id, storageId).Ret(); } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs index c9eca081..6fa35a34 100644 --- a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs @@ -166,14 +166,13 @@ file static class Anonymous /// /// Handles locating and opening NCA content files. /// -/// Based on nnSdk 17.5.0 (FS 17.0.0) +/// Based on nnSdk 18.3.0 (FS 18.0.0) public class NcaFileSystemServiceImpl : IDisposable { private readonly Configuration _config; private readonly UpdatePartitionPath _updatePartitionPath; private readonly ExternalKeyManager _externalKeyManager; private readonly SystemDataUpdateEventManager _systemDataUpdateEventManager; - private EncryptionSeed _encryptionSeed; private uint _romFsDeepRetryStartCount; private uint _romFsRemountForDataCorruptionCount; private uint _romfsUnrecoverableDataCorruptionByRemountCount; @@ -193,11 +192,13 @@ public class NcaFileSystemServiceImpl : IDisposable public IEncryptedFileSystemCreator EncryptedFsCreator; public INspRootFileSystemCreator NspRootFileSystemCreator; public LocationResolverSet LocationResolverSet; + public Func RedirectDataId; public ProgramRegistryServiceImpl ProgramRegistryService; public AccessFailureManagementServiceImpl AccessFailureManagementService; public InternalProgramIdRangeForSpeedEmulation SpeedEmulationRange; public long AddOnContentDivisionSize; public long RomDivisionSize; + public InternalProgramIdRangeForStorageAccessSpeedControl StorageAccessSpeedControlRange; // LibHac additions public FileSystemServer FsServer; @@ -244,6 +245,8 @@ public class NcaFileSystemServiceImpl : IDisposable _romFsUnrecoverableByGameCardAccessFailedCount = 0; _romfsCountMutex = new SdkMutexType(); + + StorageAccessSpeedControl.SetTargetProgramIdRange(_config.FsServer, _config.StorageAccessSpeedControlRange); } public void Dispose() @@ -386,9 +389,8 @@ public class NcaFileSystemServiceImpl : IDisposable if (res.IsFailure()) return res.Miss(); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - res = OpenStorageByContentType(ref storage.Ref, ref storageAccessSplitter.Ref, in ncaReader, - out NcaFsHeader.FsType fsType, type, mountInfo.IsGameCard(), canMountSystemDataPrivate); + res = OpenStorageByContentType(ref storage.Ref, in ncaReader, out NcaFsHeader.FsType fsType, type, + mountInfo.IsGameCard(), canMountSystemDataPrivate); if (res.IsFailure()) return res.Miss(); switch (fsType) @@ -475,9 +477,8 @@ public class NcaFileSystemServiceImpl : IDisposable if (res.IsFailure()) return res.Miss(); using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); - res = OpenStorageByContentType(ref storage.Ref, ref storageAccessSplitter.Ref, in ncaReader, - out NcaFsHeader.FsType fsType, type, mountInfo.IsGameCard(), canMountSystemDataPrivate: false); + res = OpenStorageByContentType(ref storage.Ref, in ncaReader, out NcaFsHeader.FsType fsType, type, + mountInfo.IsGameCard(), canMountSystemDataPrivate: false); if (res.IsFailure()) return res.Miss(); if (fsType != NcaFsHeader.FsType.RomFs) @@ -486,18 +487,15 @@ public class NcaFileSystemServiceImpl : IDisposable return _config.RomFsCreator.Create(ref outFileSystem, in storage).Ret(); } - public Result OpenDataStorage(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, - ref readonly Path path, ContentAttributes attributes, FileSystemProxyType type, ulong id) + public Result OpenDataStorage(ref SharedRef outStorage, ref Hash outNcaDigest, ref readonly Path path, + ContentAttributes attributes, FileSystemProxyType type, ulong id) { - return OpenDataStorage(ref outStorage, ref outStorageAccessSplitter, ref outNcaDigest, in path, attributes, - type, id, canMountSystemDataPrivate: false).Ret(); + return OpenDataStorage(ref outStorage, ref outNcaDigest, in path, attributes, type, id, + canMountSystemDataPrivate: false).Ret(); } - public Result OpenDataStorage(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, - ref readonly Path path, ContentAttributes attributes, FileSystemProxyType type, ulong id, - bool canMountSystemDataPrivate) + public Result OpenDataStorage(ref SharedRef outStorage, ref Hash outNcaDigest, ref readonly Path path, + ContentAttributes attributes, FileSystemProxyType type, ulong id, bool canMountSystemDataPrivate) { using var ncaReader = new SharedRef(); Result res = ParseNca(ref ncaReader.Ref, out bool isGameCard, path.GetString(), attributes, id); @@ -508,8 +506,8 @@ public class NcaFileSystemServiceImpl : IDisposable GenerateNcaDigest(out outNcaDigest, ncaReader.Get, null); } - res = OpenStorageByContentType(ref outStorage, ref outStorageAccessSplitter, in ncaReader, - out NcaFsHeader.FsType fsType, type, isGameCard, canMountSystemDataPrivate); + res = OpenStorageByContentType(ref outStorage, in ncaReader, out NcaFsHeader.FsType fsType, type, isGameCard, + canMountSystemDataPrivate); if (res.IsFailure()) return res.Miss(); if (fsType != NcaFsHeader.FsType.RomFs) @@ -518,18 +516,15 @@ public class NcaFileSystemServiceImpl : IDisposable return Result.Success; } - public Result OpenStorageWithPatch(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, + public Result OpenStorageWithPatch(ref SharedRef outStorage, ref Hash outNcaDigest, ref readonly Path originalNcaPath, ContentAttributes originalAttributes, ref readonly Path currentNcaPath, ContentAttributes currentAttributes, FileSystemProxyType type, ulong originalId, ulong currentId) { - return OpenStorageWithPatch(ref outStorage, ref outStorageAccessSplitter, ref outNcaDigest, - in originalNcaPath, originalAttributes, in currentNcaPath, currentAttributes, type, originalId, currentId, - false).Ret(); + return OpenStorageWithPatch(ref outStorage, ref outNcaDigest, in originalNcaPath, originalAttributes, + in currentNcaPath, currentAttributes, type, originalId, currentId, false).Ret(); } - public Result OpenStorageWithPatch(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref Hash outNcaDigest, + public Result OpenStorageWithPatch(ref SharedRef outStorage, ref Hash outNcaDigest, ref readonly Path originalNcaPath, ContentAttributes originalAttributes, ref readonly Path currentNcaPath, ContentAttributes currentAttributes, FileSystemProxyType type, ulong originalId, ulong currentId, bool canMountSystemDataPrivate) @@ -567,8 +562,8 @@ public class NcaFileSystemServiceImpl : IDisposable GenerateNcaDigest(out outNcaDigest, originalNcaReader.Get, currentNcaReader.Get); } - res = OpenStorageWithPatchByContentType(ref outStorage, ref outStorageAccessSplitter, in originalNcaReader, - in currentNcaReader, out NcaFsHeader.FsType fsType, type, canMountSystemDataPrivate); + res = OpenStorageWithPatchByContentType(ref outStorage, in originalNcaReader, in currentNcaReader, + out NcaFsHeader.FsType fsType, type, canMountSystemDataPrivate); if (res.IsFailure()) return res.Miss(); if (fsType != NcaFsHeader.FsType.RomFs) @@ -582,11 +577,10 @@ public class NcaFileSystemServiceImpl : IDisposable FileSystemProxyType type, ulong originalId, ulong currentId) { using var storage = new SharedRef(); - using var storageAccessSplitter = new SharedRef(); using var fileSystem = new SharedRef(); - Result res = OpenStorageWithPatch(ref storage.Ref, ref storageAccessSplitter.Ref, ref Unsafe.NullRef(), - in originalNcaPath, originalAttributes, in currentNcaPath, currentAttributes, type, originalId, currentId, + Result res = OpenStorageWithPatch(ref storage.Ref, ref Unsafe.NullRef(), in originalNcaPath, + originalAttributes, in currentNcaPath, currentAttributes, type, originalId, currentId, canMountSystemDataPrivate: false); if (res.IsFailure()) return res.Miss(); @@ -658,7 +652,7 @@ public class NcaFileSystemServiceImpl : IDisposable { using SharedRef tempFileSystem = SharedRef.CreateMove(ref subDirFs.Ref); res = _config.EncryptedFsCreator.Create(ref subDirFs.Ref, in tempFileSystem, - IEncryptedFileSystemCreator.KeyId.Content, in _encryptionSeed); + IEncryptedFileSystemCreator.KeyId.Content); if (res.IsFailure()) return res.Miss(); } @@ -933,7 +927,7 @@ public class NcaFileSystemServiceImpl : IDisposable res = OpenHostFileSystem(ref outFileSystem, in pathRoot, openCaseSensitive: true); if (res.IsFailure()) return res.Miss(); break; - + case MountInfo.FileSystemType.LocalFs: res = _config.LocalFsCreator.Create(ref outFileSystem, in pathRoot, openCaseSensitive: true); if (res.IsFailure()) return res.Miss(); @@ -1148,7 +1142,6 @@ public class NcaFileSystemServiceImpl : IDisposable } public Result OpenStorageByContentType(ref SharedRef outNcaStorage, - ref SharedRef outStorageAccessSplitter, ref readonly SharedRef ncaReader, out NcaFsHeader.FsType outFsType, FileSystemProxyType fsProxyType, bool isGameCard, bool canMountSystemDataPrivate) { @@ -1221,8 +1214,7 @@ public class NcaFileSystemServiceImpl : IDisposable var ncaFsHeaderReader = new NcaFsHeaderReader(); - res = _config.StorageOnNcaCreator.Create(ref outNcaStorage, ref outStorageAccessSplitter, ref ncaFsHeaderReader, - in ncaReader, partitionIndex); + res = _config.StorageOnNcaCreator.Create(ref outNcaStorage, ref ncaFsHeaderReader, in ncaReader, partitionIndex); if (res.IsFailure()) return res.Miss(); outFsType = ncaFsHeaderReader.GetFsType(); @@ -1230,7 +1222,6 @@ public class NcaFileSystemServiceImpl : IDisposable } public Result OpenStorageWithPatchByContentType(ref SharedRef outNcaStorage, - ref SharedRef outStorageAccessSplitter, ref readonly SharedRef originalNcaReader, ref readonly SharedRef currentNcaReader, out NcaFsHeader.FsType outFsType, FileSystemProxyType fsProxyType, bool canMountSystemDataPrivate) { @@ -1279,21 +1270,14 @@ public class NcaFileSystemServiceImpl : IDisposable var ncaFsHeaderReader = new NcaFsHeaderReader(); - res = _config.StorageOnNcaCreator.CreateWithPatch(ref outNcaStorage, ref outStorageAccessSplitter, - ref ncaFsHeaderReader, in originalNcaReader, in currentNcaReader, partitionIndex); + res = _config.StorageOnNcaCreator.CreateWithPatch(ref outNcaStorage, ref ncaFsHeaderReader, + in originalNcaReader, in currentNcaReader, partitionIndex); if (res.IsFailure()) return res.Miss(); outFsType = ncaFsHeaderReader.GetFsType(); return Result.Success; } - public Result SetSdCardEncryptionSeed(in EncryptionSeed encryptionSeed) - { - _encryptionSeed = encryptionSeed; - - return Result.Success; - } - public Result ResolveRomReferenceProgramId(out ProgramId outTargetProgramId, ProgramId programId, byte programIndex) { @@ -1393,6 +1377,11 @@ public class NcaFileSystemServiceImpl : IDisposable return Result.Success; } + public DataId RedirectDataId(DataId dataId, StorageId storageId) + { + return _config.RedirectDataId?.Invoke(dataId, storageId) ?? dataId; + } + public Result ResolveDataPath(ref Path outPath, out ContentAttributes outContentAttributes, DataId dataId, StorageId storageId) { @@ -1418,17 +1407,38 @@ public class NcaFileSystemServiceImpl : IDisposable return _config.LocationResolverSet.ResolveRegisteredHtmlDocumentPath(ref outPath, out outContentAttributes, programId).Ret(); } - internal StorageLayoutType GetStorageFlag(ulong programId) + internal StorageLayoutType GetStorageFlag(ulong contentProgramId, ulong callerProgramId) { Assert.SdkRequiresNotEqual(_config.SpeedEmulationRange.ProgramIdWithoutPlatformIdMax, 0ul); - ulong programIdWithoutPlatformId = Impl.Utility.ClearPlatformIdInProgramId(programId); + StorageLayoutType storageFlag = 0; + + if (StorageAccessSpeedControl.IsTargetProgramId(_config.FsServer, callerProgramId)) + { + storageFlag |= StorageLayoutType.IsApp; + } + + ulong programIdWithoutPlatformId = Impl.Utility.ClearPlatformIdInProgramId(contentProgramId); if (programIdWithoutPlatformId >= _config.SpeedEmulationRange.ProgramIdWithoutPlatformIdMin && programIdWithoutPlatformId <= _config.SpeedEmulationRange.ProgramIdWithoutPlatformIdMax) return StorageLayoutType.Bis; else - return StorageLayoutType.All; + return storageFlag | StorageLayoutType.All; + } + + internal StorageLayoutType GetStorageFlag(ulong programId) + { + return GetStorageFlag(programId, programId); + } + + internal StorageLayoutType GetStorageFlagByContentStorageId(ContentStorageId storageId, ulong programId) + { + if (storageId == ContentStorageId.System) + return StorageLayoutType.Bis; + + StorageLayoutType flag = StorageAccessSpeedControl.IsTargetProgramId(_config.FsServer, programId) ? StorageLayoutType.IsApp : 0; + return flag | StorageLayoutType.All; } public Result HandleResolubleAccessFailure(out bool wasDeferred, Result nonDeferredResult, diff --git a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs index 42541ef7..7a22334b 100644 --- a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs @@ -1192,7 +1192,7 @@ public class SaveDataFileSystemServiceImpl : IDisposable if (res.IsFailure()) return res.Miss(); res = _config.EncryptedFsCreator.Create(ref outFileSystem, in baseFileSystem, - IEncryptedFileSystemCreator.KeyId.Save, in _encryptionSeed); + IEncryptedFileSystemCreator.KeyId.Save); if (res.IsFailure()) return res.Miss(); break; diff --git a/src/LibHac/FsSystem/AsynchronousAccess.cs b/src/LibHac/FsSystem/AsynchronousAccess.cs index af007268..496e21e7 100644 --- a/src/LibHac/FsSystem/AsynchronousAccess.cs +++ b/src/LibHac/FsSystem/AsynchronousAccess.cs @@ -7,13 +7,36 @@ using LibHac.Util; namespace LibHac.FsSystem; +/// +/// The default that is used when an +/// or doesn't need any special logic to split a request into multiple chunks. +/// +/// Based on nnSdk 18.3.0 (FS 18.0.0) +public class DefaultAsynchronousAccessSplitter : IAsynchronousAccessSplitter +{ + public void Dispose() { } + + public Result QueryAppropriateOffset(out long offsetAppropriate, long startOffset, long accessSize, long alignmentSize) + { + offsetAppropriate = Alignment.AlignDown(startOffset + accessSize, alignmentSize); + return Result.Success; + } + + public Result QueryInvocationCount(out long count, long startOffset, long endOffset, long accessSize, long alignmentSize) + { + long alignedStartOffset = Alignment.AlignDown(startOffset, alignmentSize); + count = BitUtil.DivideUp(endOffset - alignedStartOffset, accessSize); + return Result.Success; + } +} + /// /// Splits read and write requests on an or into smaller chunks /// so the request can be processed by multiple threads simultaneously. /// This interface exists because of where it will split requests into /// chunks that start and end on the boundaries of the compressed blocks. /// -/// Based on nnSdk 13.4.0 (FS 13.1.0) +/// Based on nnSdk 18.3.0 (FS 18.0.0) public interface IAsynchronousAccessSplitter : IDisposable { private static readonly DefaultAsynchronousAccessSplitter DefaultAccessSplitter = new(); @@ -40,7 +63,7 @@ public interface IAsynchronousAccessSplitter : IDisposable if (res.IsFailure()) return res.Miss(); Assert.SdkNotEqual(startOffset, offsetAppropriate); - nextOffset = Math.Min(startOffset, offsetAppropriate); + nextOffset = Math.Min(offsetAppropriate, endOffset); return Result.Success; } @@ -66,47 +89,18 @@ public interface IAsynchronousAccessSplitter : IDisposable Result QueryAppropriateOffset(out long offsetAppropriate, long startOffset, long accessSize, long alignmentSize); } -/// -/// The default that is used when an -/// or doesn't need any special logic to split a request into multiple chunks. -/// -/// Based on nnSdk 13.4.0 (FS 13.1.0) -public class DefaultAsynchronousAccessSplitter : IAsynchronousAccessSplitter -{ - public void Dispose() { } - - public Result QueryAppropriateOffset(out long offsetAppropriate, long startOffset, long accessSize, long alignmentSize) - { - offsetAppropriate = Alignment.AlignDown(startOffset + accessSize, alignmentSize); - return Result.Success; - } - - public Result QueryInvocationCount(out long count, long startOffset, long endOffset, long accessSize, long alignmentSize) - { - long alignedStartOffset = Alignment.AlignDown(startOffset, alignmentSize); - count = BitUtil.DivideUp(endOffset - alignedStartOffset, accessSize); - return Result.Success; - } -} - public class AsynchronousAccessStorage : IStorage { private SharedRef _baseStorage; // private ThreadPool _threadPool; - private IAsynchronousAccessSplitter _baseStorageAccessSplitter; + private bool _baseStorageHasAccessSplitter; - public AsynchronousAccessStorage(ref readonly SharedRef baseStorage) : this(in baseStorage, - IAsynchronousAccessSplitter.GetDefaultAsynchronousAccessSplitter()) - { - } - - public AsynchronousAccessStorage(ref readonly SharedRef baseStorage, IAsynchronousAccessSplitter baseStorageAccessSplitter) + public AsynchronousAccessStorage(ref readonly SharedRef baseStorage) { _baseStorage = SharedRef.CreateCopy(in baseStorage); - _baseStorageAccessSplitter = baseStorageAccessSplitter; + _baseStorageHasAccessSplitter = true; Assert.SdkRequiresNotNull(in _baseStorage); - Assert.SdkRequiresNotNull(_baseStorageAccessSplitter); } public override void Dispose() @@ -115,10 +109,9 @@ public class AsynchronousAccessStorage : IStorage base.Dispose(); } - public void SetBaseStorage(ref readonly SharedRef baseStorage, IAsynchronousAccessSplitter baseStorageAccessSplitter) + public void SetBaseStorage(ref readonly SharedRef baseStorage) { _baseStorage.SetByCopy(in baseStorage); - _baseStorageAccessSplitter = baseStorageAccessSplitter; } // Todo: Implement diff --git a/src/LibHac/FsSystem/BlockCacheBufferedStorage.cs b/src/LibHac/FsSystem/BlockCacheBufferedStorage.cs index 9c5af0ec..79e44913 100644 --- a/src/LibHac/FsSystem/BlockCacheBufferedStorage.cs +++ b/src/LibHac/FsSystem/BlockCacheBufferedStorage.cs @@ -188,8 +188,7 @@ public class BlockCacheBufferedStorage : IStorage throw new NotImplementedException(); } - private Result GetAssociateBuffer(out Buffer outRange, out CacheEntry outEntry, long offset, int idealSize, - bool isAllocateForWrite) + private Result GetAssociateBuffer(out Buffer outRange, out CacheEntry outEntry, long offset, bool isAllocateForWrite) { throw new NotImplementedException(); } @@ -241,8 +240,9 @@ public class BlockCacheBufferedStorage : IStorage throw new NotImplementedException(); } - private Result BulkRead(long offset, Span buffer, ref Buffer memoryRangeHead, ref Buffer memoryRangeTail, - ref CacheEntry entryHead, ref CacheEntry entryTail, bool isHeadCacheNeeded, bool isTailCacheNeeded) + private Result BulkRead(out bool outIsHeadCacheStored, out bool outIsTailCacheStored, long offset, + Span buffer, ref Buffer memoryRangeHead, ref Buffer memoryRangeTail, ref CacheEntry entryHead, + ref CacheEntry entryTail) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsSystem/CompressedStorage.cs b/src/LibHac/FsSystem/CompressedStorage.cs index bd47c61d..f0d6176f 100644 --- a/src/LibHac/FsSystem/CompressedStorage.cs +++ b/src/LibHac/FsSystem/CompressedStorage.cs @@ -18,7 +18,8 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter private long _continuousReadingSizeMax; private readonly BucketTree _bucketTree; private ValueSubStorage _dataStorage; - private GetDecompressorFunction _getDecompressorFunction; + private IDecompressorFactory _decompressorFactory; + private ulong _alignment; public CompressedStorageCore() { @@ -67,12 +68,12 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter public Result Initialize(MemoryResource allocatorForBucketTree, ref readonly ValueSubStorage dataStorage, ref readonly ValueSubStorage nodeStorage, ref readonly ValueSubStorage entryStorage, int bucketTreeEntryCount, long blockSizeMax, long continuousReadingSizeMax, - GetDecompressorFunction getDecompressorFunc) + IDecompressorFactory decompressorFactory, ulong alignment) { Assert.SdkRequiresNotNull(allocatorForBucketTree); Assert.SdkRequiresLess(0, blockSizeMax); Assert.SdkRequiresLessEqual(blockSizeMax, continuousReadingSizeMax); - Assert.SdkRequiresNotNull(getDecompressorFunc); + Assert.SdkRequiresNotNull(decompressorFactory); Result res = _bucketTree.Initialize(allocatorForBucketTree, in nodeStorage, in entryStorage, NodeSize, Unsafe.SizeOf(), bucketTreeEntryCount); @@ -81,7 +82,8 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter _blockSizeMax = blockSizeMax; _continuousReadingSizeMax = continuousReadingSizeMax; _dataStorage.Set(in dataStorage); - _getDecompressorFunction = getDecompressorFunc; + _decompressorFactory = decompressorFactory; + _alignment = alignment; return Result.Success; } @@ -120,14 +122,6 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter { throw new NotImplementedException(); } - - private DecompressorFunction GetDecompressor(CompressionType type) - { - if (CompressionTypeUtility.IsUnknownType(type)) - return null; - - return _getDecompressorFunction(type); - } } public class CacheManager : IDisposable @@ -299,11 +293,11 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter public Result Initialize(MemoryResource allocatorForBucketTree, IBufferManager allocatorForCacheManager, ref readonly ValueSubStorage dataStorage, ref readonly ValueSubStorage nodeStorage, ref readonly ValueSubStorage entryStorage, int bucketTreeEntryCount, long blockSizeMax, - long continuousReadingSizeMax, GetDecompressorFunction getDecompressorFunc, long cacheSize0, long cacheSize1, - int maxCacheEntries) + long continuousReadingSizeMax, IDecompressorFactory decompressorFactory, ulong alignment, long cacheSize0, + long cacheSize1, int maxCacheEntries) { Result res = _core.Initialize(allocatorForBucketTree, in dataStorage, in nodeStorage, in entryStorage, - bucketTreeEntryCount, blockSizeMax, continuousReadingSizeMax, getDecompressorFunc); + bucketTreeEntryCount, blockSizeMax, continuousReadingSizeMax, decompressorFactory, alignment); if (res.IsFailure()) return res.Miss(); res = _core.GetSize(out long size); diff --git a/src/LibHac/FsSystem/CompressionCommon.cs b/src/LibHac/FsSystem/CompressionCommon.cs index 8ed4b7ef..ef6ac902 100644 --- a/src/LibHac/FsSystem/CompressionCommon.cs +++ b/src/LibHac/FsSystem/CompressionCommon.cs @@ -1,35 +1,29 @@ using System; +using LibHac.Common; namespace LibHac.FsSystem; public enum CompressionType : byte { None = 0, - Zeroed = 1, + FillZero = 1, Lz4 = 3, Unknown = 4 } -public ref struct DecompressionTask -{ - public Span Destination; - public ReadOnlySpan Source; -} - -public delegate Result DecompressorFunction(DecompressionTask task); - -public delegate DecompressorFunction GetDecompressorFunction(CompressionType compressionType); +public delegate Result CompressionGetData(Span buffer); +public delegate Result CompressionProcessData(Span workBuffer, int sizeBufferRequired, CompressionGetData getDataFunc); public static class CompressionTypeUtility { public static bool IsBlockAlignmentRequired(CompressionType type) { - return type != CompressionType.None && type != CompressionType.Zeroed; + return type != CompressionType.None && type != CompressionType.FillZero; } public static bool IsDataStorageAccessRequired(CompressionType type) { - return type != CompressionType.Zeroed; + return type != CompressionType.FillZero; } public static bool IsRandomAccessible(CompressionType type) @@ -41,4 +35,15 @@ public static class CompressionTypeUtility { return type >= CompressionType.Unknown; } +} + +public interface IDecompressorFactory +{ + public Result GetDecompressor(ref UniqueRef outDecompressor, CompressionProcessData processDataFunc, Span buffer); +} + +public interface IDecompressor : IDisposable +{ + Result Decompress(CompressionType type, int compressedSize, Span buffer, int decompressedSize); + Result Unk(); } \ No newline at end of file diff --git a/src/LibHac/FsSystem/NcaFileSystemDriver.cs b/src/LibHac/FsSystem/NcaFileSystemDriver.cs index c6389d20..506ceadd 100644 --- a/src/LibHac/FsSystem/NcaFileSystemDriver.cs +++ b/src/LibHac/FsSystem/NcaFileSystemDriver.cs @@ -31,7 +31,7 @@ public struct NcaCryptoConfiguration public struct NcaCompressionConfiguration { - public GetDecompressorFunction GetDecompressorFunc; + public IDecompressorFactory DecompressorFactory; } public static class NcaKeyFunctions @@ -203,9 +203,7 @@ public class NcaFileSystemDriver : IDisposable throw new NotImplementedException(); } - public Result OpenStorage(ref SharedRef outStorage, - ref SharedRef outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader, - int fsIndex) + public Result OpenStorage(ref SharedRef outStorage, ref NcaFsHeaderReader outHeaderReader, int fsIndex) { throw new NotImplementedException(); } @@ -323,7 +321,7 @@ public class NcaFileSystemDriver : IDisposable private Result CreateIntegrityVerificationStorage(ref SharedRef outStorage, ref readonly SharedRef baseStorage, in NcaFsHeader.HashData.IntegrityMetaInfo metaInfo, - IHash256GeneratorFactory hashGeneratorFactory) + bool alwaysCreateCacheEntries, IHash256GeneratorFactory hashGeneratorFactory) { throw new NotImplementedException(); } @@ -338,22 +336,22 @@ public class NcaFileSystemDriver : IDisposable private Result CreateIntegrityVerificationStorageImpl(ref SharedRef outStorage, ref readonly SharedRef baseStorage, in NcaFsHeader.HashData.IntegrityMetaInfo metaInfo, long layerInfoOffset, int maxDataCacheEntries, int maxHashCacheEntries, sbyte bufferLevel, - IHash256GeneratorFactory hashGeneratorFactory) + bool alwaysCreateCacheEntries, IHash256GeneratorFactory hashGeneratorFactory) { throw new NotImplementedException(); } public static Result CreateCompressedStorage(ref SharedRef outStorage, ref SharedRef outCompressedStorage, ref SharedRef outMetaStorage, - ref readonly SharedRef baseStorage, in NcaCompressionInfo compressionInfo, - GetDecompressorFunction getDecompressor, MemoryResource allocator, IBufferManager bufferManager) + ref readonly SharedRef baseStorage, in NcaCompressionInfo compressionInfo, uint alignment, + IDecompressorFactory decompressorFactory, MemoryResource allocator, IBufferManager bufferManager) { throw new NotImplementedException(); } private Result CreateCompressedStorage(ref SharedRef outStorage, ref SharedRef outCompressedStorage, ref SharedRef outMetaStorage, - ref readonly SharedRef baseStorage, in NcaCompressionInfo compressionInfo) + ref readonly SharedRef baseStorage, in NcaCompressionInfo compressionInfo, uint alignment) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsSystem/NcaReader.cs b/src/LibHac/FsSystem/NcaReader.cs index de6dbe6f..99fc5d72 100644 --- a/src/LibHac/FsSystem/NcaReader.cs +++ b/src/LibHac/FsSystem/NcaReader.cs @@ -22,7 +22,7 @@ public class NcaReader : IDisposable private SharedRef _bodyStorage; private SharedRef _headerStorage; private SharedRef _aesCtrDecryptor; - private GetDecompressorFunction _getDecompressorFunc; + private IDecompressorFactory _decompressorFactory; private IHash256GeneratorFactorySelector _hashGeneratorFactorySelector; public NcaReader(in RuntimeNcaHeader runtimeNcaHeader, ref readonly SharedRef notVerifiedHeaderStorage, @@ -39,7 +39,7 @@ public class NcaReader : IDisposable _bodyStorage = SharedRef.CreateCopy(in bodyStorage); _aesCtrDecryptor = SharedRef.CreateCopy(in aesCtrDecryptor); - _getDecompressorFunc = compressionConfig.GetDecompressorFunc; + _decompressorFactory = compressionConfig.DecompressorFactory; _hashGeneratorFactorySelector = hashGeneratorFactorySelector; } @@ -181,10 +181,10 @@ public class NcaReader : IDisposable return SharedRef.CreateCopy(in _aesCtrDecryptor); } - public GetDecompressorFunction GetDecompressor() + public IDecompressorFactory GetDecompressorFactory() { - Assert.SdkRequiresNotNull(_getDecompressorFunc); - return _getDecompressorFunc; + Assert.SdkRequiresNotNull(_decompressorFactory); + return _decompressorFactory; } public IHash256GeneratorFactorySelector GetHashGeneratorFactorySelector() diff --git a/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs b/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs index cfa22b77..0737324f 100644 --- a/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs +++ b/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs @@ -13,6 +13,8 @@ internal enum StorageLayoutType SdCard = 1 << 1, GameCard = 1 << 2, Usb = 1 << 3, + + IsApp = 1 << 24, NonGameCard = Bis | SdCard | Usb, All = Bis | SdCard | GameCard | Usb diff --git a/src/LibHac/Tools/FsSystem/CompressedStorage.cs b/src/LibHac/Tools/FsSystem/CompressedStorage.cs index 78877345..693f65ae 100644 --- a/src/LibHac/Tools/FsSystem/CompressedStorage.cs +++ b/src/LibHac/Tools/FsSystem/CompressedStorage.cs @@ -141,7 +141,7 @@ internal class CompressedStorage : IStorage res = _dataStorage.Read(currentEntry.PhysicalOffset + dataOffsetInEntry, entryDestination); if (res.IsFailure()) return res.Miss(); } - else if (currentEntry.CompressionType == CompressionType.Zeroed) + else if (currentEntry.CompressionType == CompressionType.FillZero) { entryDestination.Clear(); }