Update NcaFileSystemServiceImpl

This commit is contained in:
Alex Barney 2024-04-27 14:07:24 -07:00
parent 492716af74
commit dc6acacf45
29 changed files with 1474 additions and 199 deletions

View file

@ -84,14 +84,6 @@ public static class PathExtensions
return p == null; return p == null;
} }
} }
public static unsafe bool IsNullRef(ref readonly int path)
{
fixed (int* p = &path)
{
return p == null;
}
}
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type #pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
#pragma warning restore LH0001 // DoNotCopyValue #pragma warning restore LH0001 // DoNotCopyValue
} }

View file

@ -21,7 +21,9 @@ public enum BisPartitionId
System = 31, System = 31,
SystemProperEncryption = 32, SystemProperEncryption = 32,
SystemProperPartition = 33, SystemProperPartition = 33,
SignedSystemPartitionOnSafeMode = 34 SignedSystemPartitionOnSafeMode = 34,
DeviceTreeBlob = 35,
System0 = 36
} }
public enum ContentStorageId public enum ContentStorageId

View file

@ -10,6 +10,9 @@ public static class CommonMountNames
/// <summary>"<c>@Host</c>"</summary> /// <summary>"<c>@Host</c>"</summary>
public static ReadOnlySpan<byte> HostRootFileSystemMountName => "@Host"u8; public static ReadOnlySpan<byte> HostRootFileSystemMountName => "@Host"u8;
/// <summary>"<c>@Local</c>"</summary>
public static ReadOnlySpan<byte> LocalRootFileSystemMountName => "@Local"u8;
/// <summary>"<c>@Sdcard</c>"</summary> /// <summary>"<c>@Sdcard</c>"</summary>
public static ReadOnlySpan<byte> SdCardFileSystemMountName => "@Sdcard"u8; public static ReadOnlySpan<byte> SdCardFileSystemMountName => "@Sdcard"u8;
@ -38,6 +41,9 @@ public static class CommonMountNames
/// <summary>"<c>@System</c>"</summary> /// <summary>"<c>@System</c>"</summary>
public static ReadOnlySpan<byte> BisSystemPartitionMountName => "@System"u8; public static ReadOnlySpan<byte> BisSystemPartitionMountName => "@System"u8;
/// <summary>"<c>@System0</c>"</summary>
public static ReadOnlySpan<byte> BisSystemPartition0MountName => "@System0"u8;
//Content storage names. //Content storage names.
/// <summary>"<c>@SystemContent</c>"</summary> /// <summary>"<c>@SystemContent</c>"</summary>
public static ReadOnlySpan<byte> ContentStorageSystemMountName => "@SystemContent"u8; public static ReadOnlySpan<byte> ContentStorageSystemMountName => "@SystemContent"u8;

View file

@ -65,7 +65,7 @@ public class FileSystemProxyCoreImpl
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
tempFs.SetByMove(ref fileSystem.Ref); tempFs.SetByMove(ref fileSystem.Ref);
res = _fsCreators.EncryptedFileSystemCreator.Create(ref fileSystem.Ref, ref tempFs.Ref, res = _fsCreators.EncryptedFileSystemCreator.Create(ref fileSystem.Ref, in tempFs,
IEncryptedFileSystemCreator.KeyId.CustomStorage, in _sdEncryptionSeed); IEncryptedFileSystemCreator.KeyId.CustomStorage, in _sdEncryptionSeed);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
} }

View file

@ -13,8 +13,10 @@ namespace LibHac.FsSrv;
public static class FileSystemServerInitializer public static class FileSystemServerInitializer
{ {
private const ulong SpeedEmulationProgramIdMinimum = 0x100000000000000; private const ulong SpeedEmulationProgramIdWithoutPlatformIdMinimum = 0;
private const ulong SpeedEmulationProgramIdMaximum = 0x100000000001FFF; private const ulong SpeedEmulationProgramIdWithoutPlatformIdMaximum = 0x1FFF;
private const uint ContentDivisionSize = ConcatenationFileSystem.DefaultInternalFileSize;
private const int BufferManagerHeapSize = 1024 * 1024 * 14; private const int BufferManagerHeapSize = 1024 * 1024 * 14;
private const int BufferManagerCacheSize = 1024; private const int BufferManagerCacheSize = 1024;
@ -108,8 +110,8 @@ public static class FileSystemServerInitializer
new AccessFailureManagementServiceImpl(in accessFailureManagementServiceConfig); new AccessFailureManagementServiceImpl(in accessFailureManagementServiceConfig);
var speedEmulationRange = var speedEmulationRange =
new InternalProgramIdRangeForSpeedEmulation(SpeedEmulationProgramIdMinimum, new InternalProgramIdRangeForSpeedEmulation(SpeedEmulationProgramIdWithoutPlatformIdMinimum,
SpeedEmulationProgramIdMaximum); SpeedEmulationProgramIdWithoutPlatformIdMaximum);
var ncaFsServiceConfig = new NcaFileSystemServiceImpl.Configuration(); var ncaFsServiceConfig = new NcaFileSystemServiceImpl.Configuration();
ncaFsServiceConfig.BaseFsService = baseFsService; ncaFsServiceConfig.BaseFsService = baseFsService;
@ -123,6 +125,8 @@ public static class FileSystemServerInitializer
ncaFsServiceConfig.ProgramRegistryService = programRegistryService; ncaFsServiceConfig.ProgramRegistryService = programRegistryService;
ncaFsServiceConfig.AccessFailureManagementService = accessFailureManagementService; ncaFsServiceConfig.AccessFailureManagementService = accessFailureManagementService;
ncaFsServiceConfig.SpeedEmulationRange = speedEmulationRange; ncaFsServiceConfig.SpeedEmulationRange = speedEmulationRange;
ncaFsServiceConfig.AddOnContentDivisionSize = ContentDivisionSize;
ncaFsServiceConfig.RomDivisionSize = ContentDivisionSize;
ncaFsServiceConfig.FsServer = server; ncaFsServiceConfig.FsServer = server;
var ncaFsService = new NcaFileSystemServiceImpl(in ncaFsServiceConfig); var ncaFsService = new NcaFileSystemServiceImpl(in ncaFsServiceConfig);
@ -141,6 +145,12 @@ public static class FileSystemServerInitializer
saveFsServiceConfig.SaveDataFileSystemCacheCount = 1; saveFsServiceConfig.SaveDataFileSystemCacheCount = 1;
saveFsServiceConfig.SaveIndexerManager = saveDataIndexerManager; saveFsServiceConfig.SaveIndexerManager = saveDataIndexerManager;
saveFsServiceConfig.DebugConfigService = debugConfigurationService; saveFsServiceConfig.DebugConfigService = debugConfigurationService;
saveFsServiceConfig.JournalIntegritySaveDataVersion = 0x50000;
saveFsServiceConfig.JournalIntegritySupportedVersionMin = 0x40000;
saveFsServiceConfig.JournalIntegritySupportedVersionMax = 0x50000;
saveFsServiceConfig.IntegritySaveDataVersion = 0x10000;
saveFsServiceConfig.IntegritySupportedVersionMin = 0x10000;
saveFsServiceConfig.IntegritySupportedVersionMax = 0x10000;
saveFsServiceConfig.FsServer = server; saveFsServiceConfig.FsServer = server;
var saveFsService = new SaveDataFileSystemServiceImpl(in saveFsServiceConfig); var saveFsService = new SaveDataFileSystemServiceImpl(in saveFsServiceConfig);

View file

@ -16,7 +16,7 @@ public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
KeySet = keySet; KeySet = keySet;
} }
public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref SharedRef<IFileSystem> baseFileSystem, KeyId idIndex, in EncryptionSeed encryptionSeed) public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref readonly SharedRef<IFileSystem> baseFileSystem, KeyId idIndex, in EncryptionSeed encryptionSeed)
{ {
if (idIndex < KeyId.Save || idIndex > KeyId.CustomStorage) if (idIndex < KeyId.Save || idIndex > KeyId.CustomStorage)
{ {
@ -26,7 +26,7 @@ public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
// todo: "proper" key generation instead of a lazy hack // todo: "proper" key generation instead of a lazy hack
KeySet.SetSdSeed(encryptionSeed.Value); KeySet.SetSdSeed(encryptionSeed.Value);
using var encryptedFileSystem = new SharedRef<AesXtsFileSystem>(new AesXtsFileSystem(ref baseFileSystem, using var encryptedFileSystem = new SharedRef<AesXtsFileSystem>(new AesXtsFileSystem(in baseFileSystem,
KeySet.SdCardEncryptionKeys[(int)idIndex].DataRo.ToArray(), 0x4000)); KeySet.SdCardEncryptionKeys[(int)idIndex].DataRo.ToArray(), 0x4000));
outEncryptedFileSystem.SetByMove(ref encryptedFileSystem.Ref); outEncryptedFileSystem.SetByMove(ref encryptedFileSystem.Ref);

View file

@ -13,6 +13,6 @@ public interface IEncryptedFileSystemCreator
CustomStorage = 2 CustomStorage = 2
} }
Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref SharedRef<IFileSystem> baseFileSystem, Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref readonly SharedRef<IFileSystem> baseFileSystem,
KeyId idIndex, in EncryptionSeed encryptionSeed); KeyId idIndex, in EncryptionSeed encryptionSeed);
} }

View file

@ -7,4 +7,9 @@ namespace LibHac.FsSrv.FsCreator;
public interface ILocalFileSystemCreator public interface ILocalFileSystemCreator
{ {
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly Path rootPath, bool openCaseSensitive, bool ensureRootPathExists, Result pathNotFoundResult); Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly Path rootPath, bool openCaseSensitive, bool ensureRootPathExists, Result pathNotFoundResult);
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly Path rootPath, bool openCaseSensitive)
{
return Create(ref outFileSystem, in rootPath, openCaseSensitive, false, Result.Success).Ret();
}
} }

View file

@ -6,5 +6,5 @@ namespace LibHac.FsSrv.FsCreator;
public interface IPartitionFileSystemCreator public interface IPartitionFileSystemCreator
{ {
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> baseStorage); Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> baseStorage);
} }

View file

@ -6,5 +6,5 @@ namespace LibHac.FsSrv.FsCreator;
public interface IRomFileSystemCreator public interface IRomFileSystemCreator
{ {
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> romFsStorage); Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> romFsStorage);
} }

View file

@ -7,11 +7,11 @@ namespace LibHac.FsSrv.FsCreator;
public interface IStorageOnNcaCreator public interface IStorageOnNcaCreator
{ {
Result Create(ref SharedRef<IStorage> outStorage, Result Create(ref SharedRef<IStorage> outStorage,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out 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 SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out 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);

View file

@ -7,7 +7,7 @@ namespace LibHac.FsSrv.FsCreator;
public class PartitionFileSystemCreator : IPartitionFileSystemCreator public class PartitionFileSystemCreator : IPartitionFileSystemCreator
{ {
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> baseStorage) public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> baseStorage)
{ {
using var partitionFs = new SharedRef<PartitionFileSystem>(new PartitionFileSystem()); using var partitionFs = new SharedRef<PartitionFileSystem>(new PartitionFileSystem());

View file

@ -8,9 +8,9 @@ namespace LibHac.FsSrv.FsCreator;
public class RomFileSystemCreator : IRomFileSystemCreator public class RomFileSystemCreator : IRomFileSystemCreator
{ {
// todo: Implement properly // todo: Implement properly
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> romFsStorage) public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> romFsStorage)
{ {
outFileSystem.Reset(new RomFsFileSystem(ref romFsStorage)); outFileSystem.Reset(new RomFsFileSystem(in romFsStorage));
return Result.Success; return Result.Success;
} }
} }

View file

@ -28,7 +28,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
} }
public Result Create(ref SharedRef<IStorage> outStorage, public Result Create(ref SharedRef<IStorage> outStorage,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out NcaFsHeaderReader outHeaderReader, ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader,
ref readonly SharedRef<NcaReader> ncaReader, int fsIndex) 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);
@ -36,7 +36,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
using var storage = new SharedRef<IStorage>(); using var storage = new SharedRef<IStorage>();
using var storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>(); using var storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>();
Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref,
ref storageAccessSplitter.Ref, out outHeaderReader, fsIndex)); 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));
@ -48,7 +48,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
} }
public Result CreateWithPatch(ref SharedRef<IStorage> outStorage, public Result CreateWithPatch(ref SharedRef<IStorage> outStorage,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out 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)
{ {
@ -58,7 +58,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
using var storage = new SharedRef<IStorage>(); using var storage = new SharedRef<IStorage>();
using var storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>(); using var storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>();
Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref, Result res = RomResultConverter.ConvertRomResult(ncaFsDriver.OpenStorage(ref storage.Ref,
ref storageAccessSplitter.Ref, out outHeaderReader, fsIndex)); 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));

View file

@ -34,12 +34,12 @@ public class ExternalKeyManager
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result Find(out AccessKey outAccessKey, in RightsId rightsId) public Result Find(out AccessKey outAccessKey, RightsId rightsId)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
private Result FindCore(out AccessKey outAccessKey, in RightsId rightsId) private Result FindCore(out AccessKey outAccessKey, RightsId rightsId)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View file

@ -12,14 +12,14 @@ namespace LibHac.FsSrv.Impl;
public static class LocationResolverSetGlobalMethods public static class LocationResolverSetGlobalMethods
{ {
public static void InitializeLocationResolverSet(this FileSystemServer fsSrv) public static void InitializeLocationResolverSet(this FileSystemServer fsServer)
{ {
ref LocationResolverSetGlobals globals = ref fsSrv.Globals.LocationResolverSet; ref LocationResolverSetGlobals globals = ref fsServer.Globals.LocationResolverSet;
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref globals.Mutex); using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref globals.Mutex);
if (!globals.IsLrInitialized) if (!globals.IsLrInitialized)
{ {
fsSrv.Hos.Lr.Initialize(); fsServer.Hos.Lr.Initialize();
globals.IsLrInitialized = true; globals.IsLrInitialized = true;
} }
} }
@ -39,8 +39,8 @@ internal struct LocationResolverSetGlobals
/// <summary> /// <summary>
/// Manages resolving the location of NCAs via the <c>lr</c> service. /// Manages resolving the location of NCAs via the <c>lr</c> service.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0 (FS 13.1.0)</remarks> /// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
internal class LocationResolverSet : IDisposable public class LocationResolverSet : IDisposable
{ {
private Array5<Optional<LocationResolver>> _resolvers; private Array5<Optional<LocationResolver>> _resolvers;
private Optional<AddOnContentLocationResolver> _aocResolver; private Optional<AddOnContentLocationResolver> _aocResolver;
@ -76,16 +76,16 @@ internal class LocationResolverSet : IDisposable
private static Result SetUpFsPath(ref Fs.Path outPath, ref readonly Lr.Path lrPath) private static Result SetUpFsPath(ref Fs.Path outPath, ref readonly Lr.Path lrPath)
{ {
var pathFlags = new PathFlags(); var flags = new PathFlags();
pathFlags.AllowMountName(); flags.AllowMountName();
if (Utility.IsHostFsMountName(lrPath.Value)) if (Utility.IsHostFsMountName(lrPath.Value))
pathFlags.AllowWindowsPath(); flags.AllowWindowsPath();
Result res = outPath.InitializeWithReplaceUnc(lrPath.Value); Result res = outPath.InitializeWithReplaceUnc(lrPath.Value);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = outPath.Normalize(pathFlags); res = outPath.Normalize(flags);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return Result.Success; return Result.Success;
@ -124,7 +124,7 @@ internal class LocationResolverSet : IDisposable
{ {
_fsServer.InitializeLocationResolverSet(); _fsServer.InitializeLocationResolverSet();
return Hos.Lr.OpenRegisteredLocationResolver(out resolver); return Hos.Lr.OpenRegisteredLocationResolver(out resolver).Ret();
} }
private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver) private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
@ -147,75 +147,109 @@ internal class LocationResolverSet : IDisposable
return Result.Success; return Result.Success;
} }
public Result ResolveApplicationControlPath(ref Fs.Path outPath, Ncm.ApplicationId applicationId, StorageId storageId) public Result ResolveApplicationControlPath(ref Fs.Path outPath, out ContentAttributes outContentAttributes,
Ncm.ApplicationId applicationId, StorageId storageId)
{ {
UnsafeHelpers.SkipParamInit(out outContentAttributes);
Result res = GetLocationResolver(out LocationResolver resolver, storageId); Result res = GetLocationResolver(out LocationResolver resolver, storageId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = resolver.ResolveApplicationControlPath(out Lr.Path path, applicationId); res = resolver.ResolveApplicationControlPath(out Lr.Path path, applicationId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path); outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
} }
public Result ResolveApplicationHtmlDocumentPath(out bool isDirectory, ref Fs.Path outPath, Ncm.ApplicationId applicationId, StorageId storageId) public Result ResolveApplicationHtmlDocumentPath(out bool outIsDirectory, ref Fs.Path outPath,
out ContentAttributes outContentAttributes, ulong applicationId, StorageId storageId)
{ {
UnsafeHelpers.SkipParamInit(out isDirectory); UnsafeHelpers.SkipParamInit(out outIsDirectory, out outContentAttributes);
Result res = GetLocationResolver(out LocationResolver resolver, storageId); Result res = GetLocationResolver(out LocationResolver resolver, storageId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = resolver.ResolveApplicationHtmlDocumentPath(out Lr.Path path, applicationId); res = resolver.ResolveApplicationHtmlDocumentPath(out Lr.Path path, new ProgramId(applicationId));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
isDirectory = PathUtility.IsDirectoryPath(path.Value); outContentAttributes = ContentAttributes.None;
outIsDirectory = PathUtility.IsDirectoryPath(path.Value);
return SetUpFsPath(ref outPath, in path); return SetUpFsPath(ref outPath, in path).Ret();
} }
public Result ResolveProgramPath(out bool isDirectory, ref Fs.Path outPath, ProgramId programId, StorageId storageId) public Result ResolveProgramPath(out bool outIsDirectory, ref Fs.Path outPath,
out ContentAttributes outContentAttributes, ulong programId, StorageId storageId)
{ {
UnsafeHelpers.SkipParamInit(out isDirectory); UnsafeHelpers.SkipParamInit(out outIsDirectory, out outContentAttributes);
Result res = GetLocationResolver(out LocationResolver resolver, storageId); Result res = GetLocationResolver(out LocationResolver resolver, storageId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = resolver.ResolveProgramPath(out Lr.Path path, programId); res = resolver.ResolveProgramPath(out Lr.Path path, new ProgramId(programId));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
isDirectory = PathUtility.IsDirectoryPath(path.Value); outContentAttributes = ContentAttributes.None;
outIsDirectory = PathUtility.IsDirectoryPath(path.Value);
return SetUpFsPath(ref outPath, in path); return SetUpFsPath(ref outPath, in path).Ret();
} }
public Result ResolveRomPath(out bool isDirectory, ref Fs.Path outPath, ProgramId programId, StorageId storageId) public Result ResolveRomPath(out bool outIsDirectory, ref Fs.Path outPath,
out ContentAttributes outContentAttributes, ulong programId, StorageId storageId)
{ {
UnsafeHelpers.SkipParamInit(out isDirectory); UnsafeHelpers.SkipParamInit(out outIsDirectory, out outContentAttributes);
Result res = GetLocationResolver(out LocationResolver resolver, storageId); Result res = GetLocationResolver(out LocationResolver resolver, storageId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = resolver.ResolveProgramPathForDebug(out Lr.Path path, programId); res = resolver.ResolveProgramPathForDebug(out Lr.Path path, new ProgramId(programId));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
isDirectory = PathUtility.IsDirectoryPath(path.Value); outContentAttributes = ContentAttributes.None;
outIsDirectory = PathUtility.IsDirectoryPath(path.Value);
return SetUpFsPath(ref outPath, in path); return SetUpFsPath(ref outPath, in path).Ret();
} }
public Result ResolveAddOnContentPath(ref Fs.Path outPath, DataId dataId) public Result ResolveAddOnContentPath(ref Fs.Path outPath, out ContentAttributes outContentAttributes,
ref Fs.Path outPatchPath, out ContentAttributes outPatchContentAttributes, DataId dataId)
{ {
UnsafeHelpers.SkipParamInit(out outContentAttributes, out outPatchContentAttributes);
Result res = GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver); Result res = GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = resolver.ResolveAddOnContentPath(out Lr.Path path, dataId); res = resolver.GetRegisteredAddOnContentPaths(out Lr.Path path, out Lr.Path patchPath, dataId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path); outContentAttributes = ContentAttributes.None;
if (patchPath.Value[0] != 0)
{
// Note: FS appears to assign the paths to the wrong outputs here
res = SetUpFsPath(ref outPath, in patchPath);
if (res.IsFailure()) return res.Miss();
res = SetUpFsPath(ref outPatchPath, in path);
if (res.IsFailure()) return res.Miss();
outPatchContentAttributes = ContentAttributes.None;
}
else
{
res = SetUpFsPath(ref outPath, in path);
if (res.IsFailure()) return res.Miss();
}
return Result.Success;
} }
public Result ResolveDataPath(ref Fs.Path outPath, DataId dataId, StorageId storageId) public Result ResolveDataPath(ref Fs.Path outPath, out ContentAttributes outContentAttributes, DataId dataId, StorageId storageId)
{ {
UnsafeHelpers.SkipParamInit(out outContentAttributes);
if (storageId == StorageId.None) if (storageId == StorageId.None)
return ResultFs.InvalidAlignment.Log(); return ResultFs.InvalidAlignment.Log();
@ -225,11 +259,14 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveDataPath(out Lr.Path path, dataId); res = resolver.ResolveDataPath(out Lr.Path path, dataId);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path); outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
} }
public Result ResolveRegisteredProgramPath(ref Fs.Path outPath, ulong id) public Result ResolveRegisteredProgramPath(ref Fs.Path outPath, out ContentAttributes outContentAttributes, ulong id)
{ {
UnsafeHelpers.SkipParamInit(out outContentAttributes);
RegisteredLocationResolver resolver = null; RegisteredLocationResolver resolver = null;
try try
{ {
@ -239,7 +276,8 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveProgramPath(out Lr.Path path, new ProgramId(id)); res = resolver.ResolveProgramPath(out Lr.Path path, new ProgramId(id));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path); outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
} }
finally finally
{ {
@ -247,8 +285,10 @@ internal class LocationResolverSet : IDisposable
} }
} }
public Result ResolveRegisteredHtmlDocumentPath(ref Fs.Path outPath, ulong id) public Result ResolveRegisteredHtmlDocumentPath(ref Fs.Path outPath, out ContentAttributes outContentAttributes, ulong id)
{ {
UnsafeHelpers.SkipParamInit(out outContentAttributes);
RegisteredLocationResolver resolver = null; RegisteredLocationResolver resolver = null;
try try
{ {
@ -258,7 +298,8 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveHtmlDocumentPath(out Lr.Path path, new ProgramId(id)); res = resolver.ResolveHtmlDocumentPath(out Lr.Path path, new ProgramId(id));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path); outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
} }
finally finally
{ {

View file

@ -0,0 +1,172 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.Impl;
[InlineArray(0x20)]
public struct NpdmHash
{
private byte _data;
}
public class NpdmVerificationFile : IFile
{
private NpdmHash _hash;
private UniqueRef<IFile> _baseFile;
public NpdmVerificationFile(ref UniqueRef<IFile> baseFile, NpdmHash hash)
{
throw new NotImplementedException();
}
public override void Dispose()
{
_baseFile.Destroy();
base.Dispose();
}
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
{
throw new NotImplementedException();
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
{
throw new NotImplementedException();
}
protected override Result DoFlush()
{
throw new NotImplementedException();
}
protected override Result DoSetSize(long size)
{
throw new NotImplementedException();
}
protected override Result DoGetSize(out long size)
{
throw new NotImplementedException();
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
throw new NotImplementedException();
}
}
public class NpdmVerificationFileSystem : IFileSystem
{
private NpdmHash _hash;
private ReadOnlyFileSystem _baseFileSystem;
public NpdmVerificationFileSystem(in SharedRef<IFileSystem> baseFileSystem, NpdmHash hash)
{
}
public override void Dispose()
{
_baseFileSystem.Dispose();
base.Dispose();
}
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, ref readonly Path path, OpenMode mode)
{
throw new NotImplementedException();
}
protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option)
{
throw new NotImplementedException();
}
protected override Result DoDeleteFile(ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoCreateDirectory(ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoDeleteDirectory(ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoCleanDirectoryRecursively(ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath)
{
throw new NotImplementedException();
}
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath)
{
throw new NotImplementedException();
}
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path, OpenDirectoryMode mode)
{
throw new NotImplementedException();
}
protected override Result DoCommit()
{
throw new NotImplementedException();
}
protected override Result DoCommitProvisionally(long counter)
{
throw new NotImplementedException();
}
protected override Result DoRollback()
{
throw new NotImplementedException();
}
protected override Result DoFlush()
{
throw new NotImplementedException();
}
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, ref readonly Path path)
{
throw new NotImplementedException();
}
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, ref readonly Path path)
{
throw new NotImplementedException();
}
}

View file

@ -10,9 +10,10 @@ namespace LibHac.FsSrv.Impl;
/// <summary> /// <summary>
/// Keeps track of the program IDs and program indexes of each program in a multi-program application. /// Keeps track of the program IDs and program indexes of each program in a multi-program application.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0 (FS 13.1.0)</remarks> /// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
public class ProgramIndexMapInfoManager : IDisposable public class ProgramIndexMapInfoManager : IDisposable
{ {
// Changed: The original uses an intrusive list for the entries
private LinkedList<ProgramIndexMapInfo> _mapEntries; private LinkedList<ProgramIndexMapInfo> _mapEntries;
private SdkMutexType _mutex; private SdkMutexType _mutex;
@ -38,21 +39,29 @@ public class ProgramIndexMapInfoManager : IDisposable
ClearImpl(); ClearImpl();
for (int i = 0; i < programIndexMapInfo.Length; i++) bool isSuccess = false;
try
{ {
var entry = new ProgramIndexMapInfo for (int i = 0; i < programIndexMapInfo.Length; i++)
{ {
ProgramId = programIndexMapInfo[i].ProgramId, var entry = new ProgramIndexMapInfo
MainProgramId = programIndexMapInfo[i].MainProgramId, {
ProgramIndex = programIndexMapInfo[i].ProgramIndex ProgramId = programIndexMapInfo[i].ProgramId,
}; MainProgramId = programIndexMapInfo[i].MainProgramId,
ProgramIndex = programIndexMapInfo[i].ProgramIndex
};
_mapEntries.AddLast(entry); _mapEntries.AddLast(entry);
}
isSuccess = true;
return Result.Success;
}
finally
{
if (!isSuccess)
ClearImpl();
} }
// We skip running ClearImpl() if the allocation failed because we don't need to worry about that in C#
return Result.Success;
} }
/// <summary> /// <summary>
@ -116,6 +125,19 @@ public class ProgramIndexMapInfoManager : IDisposable
return _mapEntries.Count; return _mapEntries.Count;
} }
public ProgramId GetApplicationProgramId(ProgramId programId)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
Optional<ProgramIndexMapInfo> programIndexMapInfo =
GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId);
if (!programIndexMapInfo.HasValue)
return ProgramId.InvalidId;
return new ProgramId(programIndexMapInfo.Value.MainProgramId.Value + programIndexMapInfo.Value.ProgramIndex);
}
private delegate bool EntrySelector(in ProgramIndexMapInfo candidate); private delegate bool EntrySelector(in ProgramIndexMapInfo candidate);
private Optional<ProgramIndexMapInfo> GetImpl(EntrySelector selector) private Optional<ProgramIndexMapInfo> GetImpl(EntrySelector selector)

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@ internal struct ProgramRegistryImplGlobals
/// is stored in a <see cref="ProgramInfo"/> and includes the process' process ID, program ID, /// is stored in a <see cref="ProgramInfo"/> and includes the process' process ID, program ID,
/// storage location and file system permissions. This allows FS to resolve the program ID and /// storage location and file system permissions. This allows FS to resolve the program ID and
/// verify the permissions of any process calling it. /// verify the permissions of any process calling it.
/// <para>Based on nnSdk 13.4.0 (FS 13.1.0)</para></remarks> /// <para>Based on nnSdk 17.5.0 (FS 17.0.0)</para></remarks>
public class ProgramRegistryImpl : IProgramRegistry public class ProgramRegistryImpl : IProgramRegistry
{ {
private ulong _processId; private ulong _processId;
@ -55,8 +55,9 @@ public class ProgramRegistryImpl : IProgramRegistry
if (accessControlDescriptorSize > accessControlDescriptor.Size) if (accessControlDescriptorSize > accessControlDescriptor.Size)
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
return Globals.ServiceImpl.RegisterProgramInfo(processId, programId, storageId, accessControlData.Buffer, return Globals.ServiceImpl.RegisterProgramInfo(processId, programId, storageId,
accessControlDescriptor.Buffer); accessControlData.Buffer.Slice(0, (int)accessControlDataSize),
accessControlDescriptor.Buffer.Slice(0, (int)accessControlDescriptorSize)).Ret();
} }
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/> /// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
@ -70,7 +71,7 @@ public class ProgramRegistryImpl : IProgramRegistry
if (!_fsServer.IsInitialProgram(_processId)) if (!_fsServer.IsInitialProgram(_processId))
return ResultFs.PermissionDenied.Log(); return ResultFs.PermissionDenied.Log();
return Globals.ServiceImpl.UnregisterProgramInfo(processId); return Globals.ServiceImpl.UnregisterProgramInfo(processId).Ret();
} }
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
@ -78,7 +79,7 @@ public class ProgramRegistryImpl : IProgramRegistry
{ {
Assert.SdkRequiresNotNull(Globals.ServiceImpl); Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfo(out programInfo, processId); return Globals.ServiceImpl.GetProgramInfo(out programInfo, processId).Ret();
} }
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
@ -86,7 +87,7 @@ public class ProgramRegistryImpl : IProgramRegistry
{ {
Assert.SdkRequiresNotNull(Globals.ServiceImpl); Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfoByProgramId(out programInfo, programId); return Globals.ServiceImpl.GetProgramInfoByProgramId(out programInfo, programId).Ret();
} }
/// <summary> /// <summary>

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Runtime.InteropServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
@ -14,7 +13,7 @@ namespace LibHac.FsSrv;
/// </summary> /// </summary>
/// <remarks>Appropriate methods calls on IFileSystemProxy are forwarded to this class /// <remarks>Appropriate methods calls on IFileSystemProxy are forwarded to this class
/// which then checks the calling process' permissions and performs the requested operation. /// which then checks the calling process' permissions and performs the requested operation.
/// <para>Based on nnSdk 13.4.0 (FS 13.1.0)</para></remarks> /// <para>Based on nnSdk 17.5.0 (FS 17.0.0)</para></remarks>
internal readonly struct ProgramIndexRegistryService internal readonly struct ProgramIndexRegistryService
{ {
private readonly ProgramRegistryServiceImpl _serviceImpl; private readonly ProgramRegistryServiceImpl _serviceImpl;
@ -53,11 +52,14 @@ internal readonly struct ProgramIndexRegistryService
return ResultFs.PermissionDenied.Log(); return ResultFs.PermissionDenied.Log();
} }
// Return early if the program count is 0 so we leave any previously // Return early if the program count is 0, so we leave any previously
// registered entries as they were // registered entries as they were
if (programCount == 0) if (programCount == 0)
return Result.Success; return Result.Success;
if (programIndexMapInfo.IsNull)
return ResultFs.NullptrArgument.Log();
// Verify that the provided buffer is large enough to hold "programCount" entries // Verify that the provided buffer is large enough to hold "programCount" entries
ReadOnlySpan<ProgramIndexMapInfo> mapInfo = programIndexMapInfo.AsSpan<ProgramIndexMapInfo>(); ReadOnlySpan<ProgramIndexMapInfo> mapInfo = programIndexMapInfo.AsSpan<ProgramIndexMapInfo>();
@ -65,7 +67,7 @@ internal readonly struct ProgramIndexRegistryService
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
// Register the map info // Register the map info
return _serviceImpl.ResetProgramIndexMapInfo(mapInfo.Slice(0, programCount)); return _serviceImpl.ResetProgramIndexMapInfo(mapInfo.Slice(0, programCount)).Ret();
} }
/// <summary> /// <summary>
@ -88,10 +90,10 @@ internal readonly struct ProgramIndexRegistryService
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
// Try to get map info for this process // Try to get map info for this process
Optional<ProgramIndexMapInfo> mapInfo = _serviceImpl.GetProgramIndexMapInfo(programInfo.ProgramId); Optional<ProgramIndexMapInfo> programMapInfo = _serviceImpl.GetProgramIndexMapInfo(programInfo.ProgramId);
// Set the output program index if map info was found // Set the output program index if map info was found
programIndex = mapInfo.HasValue ? mapInfo.ValueRo.ProgramIndex : 0; programIndex = programMapInfo.HasValue ? programMapInfo.ValueRo.ProgramIndex : 0;
// Set the number of programs in the current application // Set the number of programs in the current application
programCount = _serviceImpl.GetProgramIndexMapInfoCount(); programCount = _serviceImpl.GetProgramIndexMapInfoCount();
@ -110,7 +112,7 @@ internal readonly struct ProgramIndexRegistryService
/// <summary> /// <summary>
/// Manages the main program registry and the multi-program registry. /// Manages the main program registry and the multi-program registry.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0 (FS 13.1.0)</remarks> /// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
public class ProgramRegistryServiceImpl : IDisposable public class ProgramRegistryServiceImpl : IDisposable
{ {
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
@ -142,37 +144,31 @@ public class ProgramRegistryServiceImpl : IDisposable
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor) ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{ {
return _registryManager.RegisterProgram(processId, programId, storageId, accessControlData, return _registryManager.RegisterProgram(processId, programId, storageId, accessControlData,
accessControlDescriptor); accessControlDescriptor).Ret();
} }
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" /> /// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgramInfo(ulong processId) public Result UnregisterProgramInfo(ulong processId)
{ {
return _registryManager.UnregisterProgram(processId); return _registryManager.UnregisterProgram(processId).Ret();
} }
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{ {
return _registryManager.GetProgramInfo(out programInfo, processId); return _registryManager.GetProgramInfo(out programInfo, processId).Ret();
} }
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId) public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId)
{ {
return _registryManager.GetProgramInfoByProgramId(out programInfo, programId); return _registryManager.GetProgramInfoByProgramId(out programInfo, programId).Ret();
} }
/// <inheritdoc cref="ProgramIndexMapInfoManager.Reset"/> /// <inheritdoc cref="ProgramIndexMapInfoManager.Reset"/>
public Result ResetProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo) public Result ResetProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{ {
return _programIndexManager.Reset(programIndexMapInfo); return _programIndexManager.Reset(programIndexMapInfo).Ret();
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
} }
/// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/> /// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/>
@ -181,6 +177,12 @@ public class ProgramRegistryServiceImpl : IDisposable
return _programIndexManager.Get(programId); return _programIndexManager.Get(programId);
} }
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
}
/// <summary> /// <summary>
/// Gets the number of programs in the currently registered application. /// Gets the number of programs in the currently registered application.
/// </summary> /// </summary>
@ -189,4 +191,14 @@ public class ProgramRegistryServiceImpl : IDisposable
{ {
return _programIndexManager.GetProgramCount(); return _programIndexManager.GetProgramCount();
} }
public ProgramId GetApplicationProgramProgramIdByPatchProgramProgramId(ProgramId programId)
{
return _programIndexManager.GetApplicationProgramId(programId);
}
public ProgramId GetApplicationHtmlDocumentProgramIdByPatchProgramProgramId(ProgramId programId)
{
return GetApplicationProgramProgramIdByPatchProgramProgramId(programId);
}
} }

View file

@ -1191,7 +1191,7 @@ public class SaveDataFileSystemServiceImpl : IDisposable
res = Utility.WrapSubDirectory(ref baseFileSystem.Ref, ref tempFileSystem.Ref, in pathSdRoot, createIfMissing); res = Utility.WrapSubDirectory(ref baseFileSystem.Ref, ref tempFileSystem.Ref, in pathSdRoot, createIfMissing);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
res = _config.EncryptedFsCreator.Create(ref outFileSystem, ref baseFileSystem.Ref, res = _config.EncryptedFsCreator.Create(ref outFileSystem, in baseFileSystem,
IEncryptedFileSystemCreator.KeyId.Save, in _encryptionSeed); IEncryptedFileSystemCreator.KeyId.Save, in _encryptionSeed);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();

View file

@ -490,7 +490,7 @@ public class ConcatenationFileSystem : IFileSystem
} }
} }
public static readonly long DefaultInternalFileSize = 0xFFFF0000; // Hard-coded value used by FS public const uint DefaultInternalFileSize = 0xFFFF0000; // Hard-coded value used by FS
private UniqueRef<IAttributeFileSystem> _baseFileSystem; private UniqueRef<IAttributeFileSystem> _baseFileSystem;
private long _internalFileSize; private long _internalFileSize;

View file

@ -204,13 +204,13 @@ public class NcaFileSystemDriver : IDisposable
} }
public Result OpenStorage(ref SharedRef<IStorage> outStorage, public Result OpenStorage(ref SharedRef<IStorage> outStorage,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out NcaFsHeaderReader outHeaderReader, ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader,
int fsIndex) int fsIndex)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
private Result OpenStorageImpl(ref SharedRef<IStorage> outStorage, out NcaFsHeaderReader outHeaderReader, private Result OpenStorageImpl(ref SharedRef<IStorage> outStorage, ref NcaFsHeaderReader outHeaderReader,
int fsIndex, ref StorageContext storageContext) int fsIndex, ref StorageContext storageContext)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View file

@ -33,4 +33,13 @@ public class AddOnContentLocationResolver : IDisposable
public Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id) => public Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id) =>
_interface.Get.UnregisterApplicationAddOnContent(id); _interface.Get.UnregisterApplicationAddOnContent(id);
public Result GetRegisteredAddOnContentPaths(out Path outPath, out Path outPatchPath, DataId id) =>
_interface.Get.GetRegisteredAddOnContentPaths(out outPath, out outPatchPath, id);
public Result RegisterAddOnContentPath(DataId id, ApplicationId applicationId, in Path path) =>
_interface.Get.RegisterAddOnContentPath(id, applicationId, in path);
public Result RegisterAddOnContentPaths(DataId id, ApplicationId applicationId, in Path path, in Path patchPath) =>
_interface.Get.RegisterAddOnContentPaths(id, applicationId, in path, in patchPath);
} }

View file

@ -6,9 +6,12 @@ namespace LibHac.Lr;
public interface IAddOnContentLocationResolver : IDisposable public interface IAddOnContentLocationResolver : IDisposable
{ {
Result ResolveAddOnContentPath(out Path path, DataId id); Result ResolveAddOnContentPath(out Path outPath, DataId id);
Result RegisterAddOnContentStorage(DataId id, Ncm.ApplicationId applicationId, StorageId storageId); Result RegisterAddOnContentStorage(DataId id, Ncm.ApplicationId applicationId, StorageId storageId);
Result UnregisterAllAddOnContentPath(); Result UnregisterAllAddOnContentPath();
Result RefreshApplicationAddOnContent(InArray<Ncm.ApplicationId> ids); Result RefreshApplicationAddOnContent(InArray<Ncm.ApplicationId> ids);
Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id); Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id);
Result GetRegisteredAddOnContentPaths(out Path outPath, out Path outPatchPath, DataId id);
Result RegisterAddOnContentPath(DataId id, ApplicationId applicationId, in Path path);
Result RegisterAddOnContentPaths(DataId id, ApplicationId applicationId, in Path path, in Path patchPath);
} }

View file

@ -17,9 +17,9 @@ public class AesXtsFileSystem : IFileSystem
private byte[] _kekSource; private byte[] _kekSource;
private byte[] _validationKey; private byte[] _validationKey;
public AesXtsFileSystem(ref SharedRef<IFileSystem> fs, byte[] keys, int blockSize) public AesXtsFileSystem(ref readonly SharedRef<IFileSystem> fs, byte[] keys, int blockSize)
{ {
_sharedBaseFileSystem = SharedRef<IFileSystem>.CreateMove(ref fs); _sharedBaseFileSystem = SharedRef<IFileSystem>.CreateCopy(in fs);
_baseFileSystem = _sharedBaseFileSystem.Get; _baseFileSystem = _sharedBaseFileSystem.Get;
_kekSource = keys.AsSpan(0, 0x10).ToArray(); _kekSource = keys.AsSpan(0, 0x10).ToArray();
_validationKey = keys.AsSpan(0x10, 0x10).ToArray(); _validationKey = keys.AsSpan(0x10, 0x10).ToArray();

View file

@ -26,9 +26,9 @@ public class RomFsFileSystem : IFileSystem
FileTable = new HierarchicalRomFileTable<RomFileInfo>(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); FileTable = new HierarchicalRomFileTable<RomFileInfo>(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable);
} }
public RomFsFileSystem(ref SharedRef<IStorage> storage) : this(storage.Get) public RomFsFileSystem(ref readonly SharedRef<IStorage> storage) : this(storage.Get)
{ {
_baseStorageShared = SharedRef<IStorage>.CreateMove(ref storage); _baseStorageShared = SharedRef<IStorage>.CreateCopy(in storage);
} }
public override void Dispose() public override void Dispose()

View file

@ -1,2 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>