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;
}
}
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 LH0001 // DoNotCopyValue
}

View file

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

View file

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

View file

@ -65,7 +65,7 @@ public class FileSystemProxyCoreImpl
if (res.IsFailure()) return res.Miss();
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);
if (res.IsFailure()) return res.Miss();
}

View file

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

View file

@ -16,7 +16,7 @@ public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
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)
{
@ -26,7 +26,7 @@ public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
// todo: "proper" key generation instead of a lazy hack
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));
outEncryptedFileSystem.SetByMove(ref encryptedFileSystem.Ref);

View file

@ -13,6 +13,6 @@ public interface IEncryptedFileSystemCreator
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);
}

View file

@ -7,4 +7,9 @@ namespace LibHac.FsSrv.FsCreator;
public interface ILocalFileSystemCreator
{
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
{
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
{
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
{
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);
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,
int fsIndex);

View file

@ -7,7 +7,7 @@ namespace LibHac.FsSrv.FsCreator;
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());

View file

@ -8,9 +8,9 @@ namespace LibHac.FsSrv.FsCreator;
public class RomFileSystemCreator : IRomFileSystemCreator
{
// 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;
}
}

View file

@ -28,7 +28,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
}
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)
{
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 storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>();
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();
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,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out NcaFsHeaderReader outHeaderReader,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader,
ref readonly SharedRef<NcaReader> originalNcaReader, ref readonly SharedRef<NcaReader> currentNcaReader,
int fsIndex)
{
@ -58,7 +58,7 @@ public class StorageOnNcaCreator : IStorageOnNcaCreator
using var storage = new SharedRef<IStorage>();
using var storageAccessSplitter = new SharedRef<IAsynchronousAccessSplitter>();
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();
using var resultConvertStorage = new SharedRef<RomResultConvertStorage>(new RomResultConvertStorage(in storage));

View file

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

View file

@ -12,14 +12,14 @@ namespace LibHac.FsSrv.Impl;
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);
if (!globals.IsLrInitialized)
{
fsSrv.Hos.Lr.Initialize();
fsServer.Hos.Lr.Initialize();
globals.IsLrInitialized = true;
}
}
@ -39,8 +39,8 @@ internal struct LocationResolverSetGlobals
/// <summary>
/// Manages resolving the location of NCAs via the <c>lr</c> service.
/// </summary>
/// <remarks>Based on nnSdk 13.4.0 (FS 13.1.0)</remarks>
internal class LocationResolverSet : IDisposable
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
public class LocationResolverSet : IDisposable
{
private Array5<Optional<LocationResolver>> _resolvers;
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)
{
var pathFlags = new PathFlags();
pathFlags.AllowMountName();
var flags = new PathFlags();
flags.AllowMountName();
if (Utility.IsHostFsMountName(lrPath.Value))
pathFlags.AllowWindowsPath();
flags.AllowWindowsPath();
Result res = outPath.InitializeWithReplaceUnc(lrPath.Value);
if (res.IsFailure()) return res.Miss();
res = outPath.Normalize(pathFlags);
res = outPath.Normalize(flags);
if (res.IsFailure()) return res.Miss();
return Result.Success;
@ -124,7 +124,7 @@ internal class LocationResolverSet : IDisposable
{
_fsServer.InitializeLocationResolverSet();
return Hos.Lr.OpenRegisteredLocationResolver(out resolver);
return Hos.Lr.OpenRegisteredLocationResolver(out resolver).Ret();
}
private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
@ -147,75 +147,109 @@ internal class LocationResolverSet : IDisposable
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);
if (res.IsFailure()) return res.Miss();
res = resolver.ResolveApplicationControlPath(out Lr.Path path, applicationId);
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);
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();
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);
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();
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);
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();
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);
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();
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)
return ResultFs.InvalidAlignment.Log();
@ -225,11 +259,14 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveDataPath(out Lr.Path path, dataId);
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;
try
{
@ -239,7 +276,8 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveProgramPath(out Lr.Path path, new ProgramId(id));
if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path);
outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
}
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;
try
{
@ -258,7 +298,8 @@ internal class LocationResolverSet : IDisposable
res = resolver.ResolveHtmlDocumentPath(out Lr.Path path, new ProgramId(id));
if (res.IsFailure()) return res.Miss();
return SetUpFsPath(ref outPath, in path);
outContentAttributes = ContentAttributes.None;
return SetUpFsPath(ref outPath, in path).Ret();
}
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>
/// Keeps track of the program IDs and program indexes of each program in a multi-program application.
/// </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
{
// Changed: The original uses an intrusive list for the entries
private LinkedList<ProgramIndexMapInfo> _mapEntries;
private SdkMutexType _mutex;
@ -38,21 +39,29 @@ public class ProgramIndexMapInfoManager : IDisposable
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,
MainProgramId = programIndexMapInfo[i].MainProgramId,
ProgramIndex = programIndexMapInfo[i].ProgramIndex
};
var entry = new ProgramIndexMapInfo
{
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>
@ -116,6 +125,19 @@ public class ProgramIndexMapInfoManager : IDisposable
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 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,
/// storage location and file system permissions. This allows FS to resolve the program ID and
/// 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
{
private ulong _processId;
@ -55,8 +55,9 @@ public class ProgramRegistryImpl : IProgramRegistry
if (accessControlDescriptorSize > accessControlDescriptor.Size)
return ResultFs.InvalidSize.Log();
return Globals.ServiceImpl.RegisterProgramInfo(processId, programId, storageId, accessControlData.Buffer,
accessControlDescriptor.Buffer);
return Globals.ServiceImpl.RegisterProgramInfo(processId, programId, storageId,
accessControlData.Buffer.Slice(0, (int)accessControlDataSize),
accessControlDescriptor.Buffer.Slice(0, (int)accessControlDescriptorSize)).Ret();
}
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
@ -70,7 +71,7 @@ public class ProgramRegistryImpl : IProgramRegistry
if (!_fsServer.IsInitialProgram(_processId))
return ResultFs.PermissionDenied.Log();
return Globals.ServiceImpl.UnregisterProgramInfo(processId);
return Globals.ServiceImpl.UnregisterProgramInfo(processId).Ret();
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
@ -78,7 +79,7 @@ public class ProgramRegistryImpl : IProgramRegistry
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfo(out programInfo, processId);
return Globals.ServiceImpl.GetProgramInfo(out programInfo, processId).Ret();
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
@ -86,7 +87,7 @@ public class ProgramRegistryImpl : IProgramRegistry
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfoByProgramId(out programInfo, programId);
return Globals.ServiceImpl.GetProgramInfoByProgramId(out programInfo, programId).Ret();
}
/// <summary>

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Impl;
@ -14,7 +13,7 @@ namespace LibHac.FsSrv;
/// </summary>
/// <remarks>Appropriate methods calls on IFileSystemProxy are forwarded to this class
/// 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
{
private readonly ProgramRegistryServiceImpl _serviceImpl;
@ -53,11 +52,14 @@ internal readonly struct ProgramIndexRegistryService
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
if (programCount == 0)
return Result.Success;
if (programIndexMapInfo.IsNull)
return ResultFs.NullptrArgument.Log();
// Verify that the provided buffer is large enough to hold "programCount" entries
ReadOnlySpan<ProgramIndexMapInfo> mapInfo = programIndexMapInfo.AsSpan<ProgramIndexMapInfo>();
@ -65,7 +67,7 @@ internal readonly struct ProgramIndexRegistryService
return ResultFs.InvalidSize.Log();
// Register the map info
return _serviceImpl.ResetProgramIndexMapInfo(mapInfo.Slice(0, programCount));
return _serviceImpl.ResetProgramIndexMapInfo(mapInfo.Slice(0, programCount)).Ret();
}
/// <summary>
@ -88,10 +90,10 @@ internal readonly struct ProgramIndexRegistryService
if (res.IsFailure()) return res.Miss();
// 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
programIndex = mapInfo.HasValue ? mapInfo.ValueRo.ProgramIndex : 0;
programIndex = programMapInfo.HasValue ? programMapInfo.ValueRo.ProgramIndex : 0;
// Set the number of programs in the current application
programCount = _serviceImpl.GetProgramIndexMapInfoCount();
@ -110,7 +112,7 @@ internal readonly struct ProgramIndexRegistryService
/// <summary>
/// Manages the main program registry and the multi-program registry.
/// </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
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
@ -142,37 +144,31 @@ public class ProgramRegistryServiceImpl : IDisposable
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{
return _registryManager.RegisterProgram(processId, programId, storageId, accessControlData,
accessControlDescriptor);
accessControlDescriptor).Ret();
}
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgramInfo(ulong processId)
{
return _registryManager.UnregisterProgram(processId);
return _registryManager.UnregisterProgram(processId).Ret();
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
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"/>
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"/>
public Result ResetProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
return _programIndexManager.Reset(programIndexMapInfo);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
return _programIndexManager.Reset(programIndexMapInfo).Ret();
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/>
@ -181,6 +177,12 @@ public class ProgramRegistryServiceImpl : IDisposable
return _programIndexManager.Get(programId);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
}
/// <summary>
/// Gets the number of programs in the currently registered application.
/// </summary>
@ -189,4 +191,14 @@ public class ProgramRegistryServiceImpl : IDisposable
{
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);
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);
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 long _internalFileSize;

View file

@ -204,13 +204,13 @@ public class NcaFileSystemDriver : IDisposable
}
public Result OpenStorage(ref SharedRef<IStorage> outStorage,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, out NcaFsHeaderReader outHeaderReader,
ref SharedRef<IAsynchronousAccessSplitter> outStorageAccessSplitter, ref NcaFsHeaderReader outHeaderReader,
int fsIndex)
{
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)
{
throw new NotImplementedException();

View file

@ -33,4 +33,13 @@ public class AddOnContentLocationResolver : IDisposable
public Result UnregisterApplicationAddOnContent(Ncm.ApplicationId 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
{
Result ResolveAddOnContentPath(out Path path, DataId id);
Result ResolveAddOnContentPath(out Path outPath, DataId id);
Result RegisterAddOnContentStorage(DataId id, Ncm.ApplicationId applicationId, StorageId storageId);
Result UnregisterAllAddOnContentPath();
Result RefreshApplicationAddOnContent(InArray<Ncm.ApplicationId> ids);
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[] _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;
_kekSource = keys.AsSpan(0, 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);
}
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()

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">
<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>