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