diff --git a/src/LibHac/FsSrv/FileSystemProxy.cs b/src/LibHac/FsSrv/FileSystemProxy.cs index 3d2b26fb..ede552e8 100644 --- a/src/LibHac/FsSrv/FileSystemProxy.cs +++ b/src/LibHac/FsSrv/FileSystemProxy.cs @@ -37,7 +37,7 @@ namespace LibHac.FsSrv private ProgramRegistryService GetProgramRegistryService() { - return new ProgramRegistryService(FsProxyCore.Config.ProgramRegistryService, CurrentProcess); + return new ProgramRegistryService(FsProxyCore.Config.ProgramRegistryServiceImpl, CurrentProcess); } public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, ulong id, FileSystemProxyType type) @@ -649,6 +649,11 @@ namespace LibHac.FsSrv throw new NotImplementedException(); } + public Result RegisterProgramIndexMapInfo(ReadOnlySpan programIndexMapInfoBuffer, int programCount) + { + return GetProgramRegistryService().RegisterProgramIndexMapInfo(programIndexMapInfoBuffer, programCount); + } + public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path) { throw new NotImplementedException(); @@ -1087,7 +1092,7 @@ namespace LibHac.FsSrv public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount) { - throw new NotImplementedException(); + return GetProgramRegistryService().GetProgramIndexForAccessLog(out programIndex, out programCount); } public Result OutputAccessLogToSdCard(U8Span logString) @@ -1188,6 +1193,11 @@ namespace LibHac.FsSrv } } + private Result GetProgramInfo(out ProgramInfo programInfo) + { + return FsProxyCore.ProgramRegistry.GetProgramInfo(out programInfo, CurrentProcess); + } + private static bool IsSystemSaveDataId(ulong id) { return (long)id < 0; diff --git a/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs b/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs index 3b57e3c6..ed15e0fd 100644 --- a/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs +++ b/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs @@ -5,6 +5,6 @@ namespace LibHac.FsSrv public class FileSystemProxyConfiguration { public FileSystemCreators FsCreatorInterfaces { get; set; } - public ProgramRegistryServiceImpl ProgramRegistryService { get; set; } + public ProgramRegistryServiceImpl ProgramRegistryServiceImpl { get; set; } } } diff --git a/src/LibHac/FsSrv/FileSystemProxyCore.cs b/src/LibHac/FsSrv/FileSystemProxyCore.cs index 69a6b4c3..e677bde6 100644 --- a/src/LibHac/FsSrv/FileSystemProxyCore.cs +++ b/src/LibHac/FsSrv/FileSystemProxyCore.cs @@ -35,7 +35,7 @@ namespace LibHac.FsSrv public FileSystemProxyCore(FileSystemProxyConfiguration config, ExternalKeySet externalKeys, IDeviceOperator deviceOperator) { Config = config; - ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryService); + ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryServiceImpl); ExternalKeys = externalKeys ?? new ExternalKeySet(); DeviceOperator = deviceOperator; } diff --git a/src/LibHac/FsSrv/FileSystemServer.cs b/src/LibHac/FsSrv/FileSystemServer.cs index a42c172b..0a54e754 100644 --- a/src/LibHac/FsSrv/FileSystemServer.cs +++ b/src/LibHac/FsSrv/FileSystemServer.cs @@ -37,7 +37,7 @@ namespace LibHac.FsSrv var fspConfig = new FileSystemProxyConfiguration { FsCreatorInterfaces = config.FsCreators, - ProgramRegistryService = new ProgramRegistryServiceImpl(this) + ProgramRegistryServiceImpl = new ProgramRegistryServiceImpl(this) }; FsProxyCore = new FileSystemProxyCore(fspConfig, externalKeySet, config.DeviceOperator); diff --git a/src/LibHac/FsSrv/IFileSystemProxy.cs b/src/LibHac/FsSrv/IFileSystemProxy.cs index 94a63766..fe466db5 100644 --- a/src/LibHac/FsSrv/IFileSystemProxy.cs +++ b/src/LibHac/FsSrv/IFileSystemProxy.cs @@ -88,6 +88,7 @@ namespace LibHac.FsSrv Result SetSdCardAccessibility(bool isAccessible); Result IsSdCardAccessible(out bool isAccessible); + Result RegisterProgramIndexMapInfo(ReadOnlySpan programIndexMapInfoBuffer, int programCount); Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(ref FsPath path); diff --git a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs index e7b37c78..df866f7e 100644 --- a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs +++ b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs @@ -37,7 +37,7 @@ namespace LibHac.FsSrv.Impl } /// - /// Registers a program with information about the program in the program registry. + /// Registers a program with information about that program in the program registry. /// /// The process ID of the program. /// The of the program. diff --git a/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs b/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs index 2adb6a76..11f553a1 100644 --- a/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs +++ b/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs @@ -5,30 +5,36 @@ using LibHac.Ncm; namespace LibHac.FsSrv { + /// + /// Keeps track of the program IDs and program indexes of each program in a multi-program application. + /// public class ProgramIndexMapInfoManager { private LinkedList MapEntries { get; } = new LinkedList(); /// - /// Clears any existing + /// Unregisters any previously registered program index map info and registers the provided map info. /// - /// The entries + /// The program map info entries to register. /// : The operation was successful. - public Result Reset(ReadOnlySpan entries) + public Result Reset(ReadOnlySpan programIndexMapInfo) { lock (MapEntries) { ClearImpl(); - for (int i = 0; i < entries.Length; i++) + for (int i = 0; i < programIndexMapInfo.Length; i++) { - MapEntries.AddLast(entries[i]); + MapEntries.AddLast(programIndexMapInfo[i]); } return Result.Success; } } + /// + /// Unregisters all currently registered program index map info. + /// public void Clear() { lock (MapEntries) @@ -37,6 +43,12 @@ namespace LibHac.FsSrv } } + /// + /// Gets the associated with the specified program ID. + /// + /// The program ID of the map info to get. + /// If the program ID was found, the associated + /// with that ID; otherwise, . public ProgramIndexMapInfo? Get(ProgramId programId) { lock (MapEntries) @@ -72,6 +84,10 @@ namespace LibHac.FsSrv } } + /// + /// Gets the number of currently registered programs, + /// + /// The number of registered programs. public int GetProgramCount() { lock (MapEntries) diff --git a/src/LibHac/FsSrv/ProgramRegistryImpl.cs b/src/LibHac/FsSrv/ProgramRegistryImpl.cs index d58eeb0e..649e6299 100644 --- a/src/LibHac/FsSrv/ProgramRegistryImpl.cs +++ b/src/LibHac/FsSrv/ProgramRegistryImpl.cs @@ -8,6 +8,8 @@ namespace LibHac.FsSrv internal class ProgramRegistryImpl { private ulong _processId; + + // Note: FS keeps this object as a global variable private readonly ProgramRegistryServiceImpl _registryService; public ProgramRegistryImpl(ProgramRegistryServiceImpl registryService) @@ -22,17 +24,10 @@ namespace LibHac.FsSrv _registryService = registryService; } - /// - /// Registers a program with information about the program in the program registry. - /// - /// The process ID of the program. - /// The of the program. - /// The where the program is located. - /// The FS access control data header located in the program's ACI. - /// The FS access control descriptor located in the program's ACID. /// : The operation was successful.
/// : The process ID is already registered.
/// : Insufficient permissions.
+ /// public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, ReadOnlySpan accessControlData, ReadOnlySpan accessControlDescriptor) { @@ -43,13 +38,10 @@ namespace LibHac.FsSrv accessControlDescriptor); } - /// - /// Unregisters the program with the specified process ID. - /// - /// The process ID of the program to unregister. /// : The operation was successful.
/// : The process ID is not registered.
/// : Insufficient permissions.
+ /// public Result UnregisterProgram(ulong processId) { if (!ProgramInfo.IsInitialProgram(_processId)) @@ -58,27 +50,13 @@ namespace LibHac.FsSrv return _registryService.UnregisterProgram(processId); } - /// - /// Gets the associated with the specified process ID. - /// - /// If the method returns successfully, contains the - /// associated with the specified process ID. - /// The process ID of the to get. - /// : The operation was successful.
- /// : The was not found.
+ /// public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) { return _registryService.GetProgramInfo(out programInfo, processId); } - /// - /// Gets the associated with the specified program ID. - /// - /// If the method returns successfully, contains the - /// associated with the specified program ID. - /// The program ID of the to get. - /// : The operation was successful.
- /// : The was not found.
+ /// public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId) { return _registryService.GetProgramInfoByProgramId(out programInfo, programId); diff --git a/src/LibHac/FsSrv/ProgramRegistryService.cs b/src/LibHac/FsSrv/ProgramRegistryService.cs index 03825f4e..3cc9460b 100644 --- a/src/LibHac/FsSrv/ProgramRegistryService.cs +++ b/src/LibHac/FsSrv/ProgramRegistryService.cs @@ -1,4 +1,10 @@ -namespace LibHac.FsSrv +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LibHac.Fs; +using LibHac.FsSrv.Impl; + +namespace LibHac.FsSrv { internal readonly struct ProgramRegistryService { @@ -10,5 +16,78 @@ ServiceImpl = serviceImpl; ProcessId = processId; } + + /// + /// Unregisters any previously registered program index map info and registers the provided map info. + /// + /// A buffer containing the program map info to register. + /// The number of programs to register. The provided buffer must be + /// large enough to hold this many entries. + /// : The operation was successful.
+ /// : Insufficient permissions.
+ /// : The buffer was too small to hold the specified + /// number of entries.
+ public Result RegisterProgramIndexMapInfo(ReadOnlySpan programIndexMapInfo, int programCount) + { + // Verify the caller's permissions + Result rc = GetProgramInfo(out ProgramInfo programInfo, ProcessId); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.RegisterProgramIndexMapInfo)) + return ResultFs.PermissionDenied.Log(); + + // Return early if the program count is 0 so we leave any previously + // registered entries as they were + if (programCount == 0) + return Result.Success; + + // Verify that the provided buffer is large enough to hold "programCount" entries + ReadOnlySpan + mapInfo = MemoryMarshal.Cast(programIndexMapInfo); + + if (mapInfo.Length < programCount) + return ResultFs.InvalidSize.Log(); + + // Register the map info + return ServiceImpl.RegisterProgramIndexMapInfo(mapInfo.Slice(0, programCount)); + } + + /// + /// Gets the multi-program index of the calling process and the number of programs + /// in the current application. + /// + /// When this method returns successfully, contains the + /// program index of the calling process. + /// When this method returns successfully, contains the + /// number of programs in the current application. + /// : The operation was successful.
+ /// : The calling program was not found + /// in the program registry. Something's wrong with Loader if this happens.
+ public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount) + { + Unsafe.SkipInit(out programIndex); + Unsafe.SkipInit(out programCount); + + // No permissions are needed to call this method + Result rc = GetProgramInfo(out ProgramInfo programInfo, ProcessId); + if (rc.IsFailure()) return rc; + + // Try to get map info for this process + ProgramIndexMapInfo? mapInfo = ServiceImpl.GetProgramIndexMapInfo(programInfo.ProgramId); + + // Set the output program index if map info was found + programIndex = mapInfo?.ProgramIndex ?? 0; + + // Set the number of programs in the current application + programCount = ServiceImpl.GetProgramIndexMapInfoCount(); + + return Result.Success; + } + + /// + private Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) + { + return ServiceImpl.GetProgramInfo(out programInfo, processId); + } } } diff --git a/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs b/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs index 90f5cfb2..04ac011e 100644 --- a/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs +++ b/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs @@ -5,6 +5,9 @@ using LibHac.Ncm; namespace LibHac.FsSrv { + /// + /// Manages the main program registry and the multi-program registry. + /// public class ProgramRegistryServiceImpl { private ProgramRegistryManager RegistryManager { get; } @@ -16,16 +19,7 @@ namespace LibHac.FsSrv ProgramIndexManager = new ProgramIndexMapInfoManager(); } - /// - /// Registers a program with information about the program in the program registry. - /// - /// The process ID of the program. - /// The of the program. - /// The where the program is located. - /// The FS access control data header located in the program's ACI. - /// The FS access control descriptor located in the program's ACID. - /// : The operation was successful.
- /// : The process ID is already registered.
+ /// public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, ReadOnlySpan accessControlData, ReadOnlySpan accessControlDescriptor) { @@ -33,54 +27,49 @@ namespace LibHac.FsSrv accessControlDescriptor); } - /// - /// Unregisters the program with the specified process ID. - /// - /// The process ID of the program to unregister. - /// : The operation was successful.
- /// : The process ID is not registered.
+ /// public Result UnregisterProgram(ulong processId) { return RegistryManager.UnregisterProgram(processId); } - /// - /// Gets the associated with the specified process ID. - /// - /// If the method returns successfully, contains the - /// associated with the specified process ID. - /// The process ID of the to get. - /// : The operation was successful.
- /// : The was not found.
+ /// public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) { return RegistryManager.GetProgramInfo(out programInfo, processId); } - /// - /// Gets the associated with the specified program ID. - /// - /// If the method returns successfully, contains the - /// associated with the specified program ID. - /// The program ID of the to get. - /// : The operation was successful.
- /// : The was not found.
+ /// public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId) { return RegistryManager.GetProgramInfoByProgramId(out programInfo, programId); } - /// - /// Gets the of the program with index in the - /// multi-program app is part of. - /// - /// A program ID in the multi-program app to query. - /// The index of the program to get. - /// If the program exists, the ID of the program with the specified index, - /// otherwise + /// public ProgramId GetProgramId(ProgramId programId, byte programIndex) { return ProgramIndexManager.GetProgramId(programId, programIndex); } + + /// + public ProgramIndexMapInfo? GetProgramIndexMapInfo(ProgramId programId) + { + return ProgramIndexManager.Get(programId); + } + + /// + /// Gets the number of programs in the currently registered application. + /// + /// The number of programs. + public int GetProgramIndexMapInfoCount() + { + return ProgramIndexManager.GetProgramCount(); + } + + /// + public Result RegisterProgramIndexMapInfo(ReadOnlySpan programIndexMapInfo) + { + return ProgramIndexManager.Reset(programIndexMapInfo); + } } }