Add functions to ProgramRegistryService

Adds RegisterProgramIndexMapInfo and GetProgramIndexForAccessLog to both FileSystemProxy and ProgramRegistryService
This commit is contained in:
Alex Barney 2020-08-22 01:03:32 -07:00
parent 0b050d2189
commit deaf111ac3
10 changed files with 153 additions and 80 deletions

View file

@ -37,7 +37,7 @@ namespace LibHac.FsSrv
private ProgramRegistryService GetProgramRegistryService() 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) public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, ulong id, FileSystemProxyType type)
@ -649,6 +649,11 @@ namespace LibHac.FsSrv
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result RegisterProgramIndexMapInfo(ReadOnlySpan<byte> programIndexMapInfoBuffer, int programCount)
{
return GetProgramRegistryService().RegisterProgramIndexMapInfo(programIndexMapInfoBuffer, programCount);
}
public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path) public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -1087,7 +1092,7 @@ namespace LibHac.FsSrv
public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount) public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount)
{ {
throw new NotImplementedException(); return GetProgramRegistryService().GetProgramIndexForAccessLog(out programIndex, out programCount);
} }
public Result OutputAccessLogToSdCard(U8Span logString) 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) private static bool IsSystemSaveDataId(ulong id)
{ {
return (long)id < 0; return (long)id < 0;

View file

@ -5,6 +5,6 @@ namespace LibHac.FsSrv
public class FileSystemProxyConfiguration public class FileSystemProxyConfiguration
{ {
public FileSystemCreators FsCreatorInterfaces { get; set; } public FileSystemCreators FsCreatorInterfaces { get; set; }
public ProgramRegistryServiceImpl ProgramRegistryService { get; set; } public ProgramRegistryServiceImpl ProgramRegistryServiceImpl { get; set; }
} }
} }

View file

@ -35,7 +35,7 @@ namespace LibHac.FsSrv
public FileSystemProxyCore(FileSystemProxyConfiguration config, ExternalKeySet externalKeys, IDeviceOperator deviceOperator) public FileSystemProxyCore(FileSystemProxyConfiguration config, ExternalKeySet externalKeys, IDeviceOperator deviceOperator)
{ {
Config = config; Config = config;
ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryService); ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryServiceImpl);
ExternalKeys = externalKeys ?? new ExternalKeySet(); ExternalKeys = externalKeys ?? new ExternalKeySet();
DeviceOperator = deviceOperator; DeviceOperator = deviceOperator;
} }

View file

@ -37,7 +37,7 @@ namespace LibHac.FsSrv
var fspConfig = new FileSystemProxyConfiguration var fspConfig = new FileSystemProxyConfiguration
{ {
FsCreatorInterfaces = config.FsCreators, FsCreatorInterfaces = config.FsCreators,
ProgramRegistryService = new ProgramRegistryServiceImpl(this) ProgramRegistryServiceImpl = new ProgramRegistryServiceImpl(this)
}; };
FsProxyCore = new FileSystemProxyCore(fspConfig, externalKeySet, config.DeviceOperator); FsProxyCore = new FileSystemProxyCore(fspConfig, externalKeySet, config.DeviceOperator);

View file

@ -88,6 +88,7 @@ namespace LibHac.FsSrv
Result SetSdCardAccessibility(bool isAccessible); Result SetSdCardAccessibility(bool isAccessible);
Result IsSdCardAccessible(out bool isAccessible); Result IsSdCardAccessible(out bool isAccessible);
Result RegisterProgramIndexMapInfo(ReadOnlySpan<byte> programIndexMapInfoBuffer, int programCount);
Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path); Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path);
Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize);
Result SetSaveDataRootPath(ref FsPath path); Result SetSaveDataRootPath(ref FsPath path);

View file

@ -37,7 +37,7 @@ namespace LibHac.FsSrv.Impl
} }
/// <summary> /// <summary>
/// Registers a program with information about the program in the program registry. /// Registers a program with information about that program in the program registry.
/// </summary> /// </summary>
/// <param name="processId">The process ID of the program.</param> /// <param name="processId">The process ID of the program.</param>
/// <param name="programId">The <see cref="ProgramId"/> of the program.</param> /// <param name="programId">The <see cref="ProgramId"/> of the program.</param>

View file

@ -5,30 +5,36 @@ using LibHac.Ncm;
namespace LibHac.FsSrv namespace LibHac.FsSrv
{ {
/// <summary>
/// Keeps track of the program IDs and program indexes of each program in a multi-program application.
/// </summary>
public class ProgramIndexMapInfoManager public class ProgramIndexMapInfoManager
{ {
private LinkedList<ProgramIndexMapInfo> MapEntries { get; } = new LinkedList<ProgramIndexMapInfo>(); private LinkedList<ProgramIndexMapInfo> MapEntries { get; } = new LinkedList<ProgramIndexMapInfo>();
/// <summary> /// <summary>
/// Clears any existing /// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary> /// </summary>
/// <param name="entries">The entries </param> /// <param name="programIndexMapInfo">The program map info entries to register.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.</returns> /// <returns><see cref="Result.Success"/>: The operation was successful.</returns>
public Result Reset(ReadOnlySpan<ProgramIndexMapInfo> entries) public Result Reset(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{ {
lock (MapEntries) lock (MapEntries)
{ {
ClearImpl(); 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; return Result.Success;
} }
} }
/// <summary>
/// Unregisters all currently registered program index map info.
/// </summary>
public void Clear() public void Clear()
{ {
lock (MapEntries) lock (MapEntries)
@ -37,6 +43,12 @@ namespace LibHac.FsSrv
} }
} }
/// <summary>
/// Gets the <see cref="ProgramIndexMapInfo"/> associated with the specified program ID.
/// </summary>
/// <param name="programId">The program ID of the map info to get.</param>
/// <returns>If the program ID was found, the <see cref="ProgramIndexMapInfo"/> associated
/// with that ID; otherwise, <see langword="null"/>.</returns>
public ProgramIndexMapInfo? Get(ProgramId programId) public ProgramIndexMapInfo? Get(ProgramId programId)
{ {
lock (MapEntries) lock (MapEntries)
@ -72,6 +84,10 @@ namespace LibHac.FsSrv
} }
} }
/// <summary>
/// Gets the number of currently registered programs,
/// </summary>
/// <returns>The number of registered programs.</returns>
public int GetProgramCount() public int GetProgramCount()
{ {
lock (MapEntries) lock (MapEntries)

View file

@ -8,6 +8,8 @@ namespace LibHac.FsSrv
internal class ProgramRegistryImpl internal class ProgramRegistryImpl
{ {
private ulong _processId; private ulong _processId;
// Note: FS keeps this object as a global variable
private readonly ProgramRegistryServiceImpl _registryService; private readonly ProgramRegistryServiceImpl _registryService;
public ProgramRegistryImpl(ProgramRegistryServiceImpl registryService) public ProgramRegistryImpl(ProgramRegistryServiceImpl registryService)
@ -22,17 +24,10 @@ namespace LibHac.FsSrv
_registryService = registryService; _registryService = registryService;
} }
/// <summary>
/// Registers a program with information about the program in the program registry.
/// </summary>
/// <param name="processId">The process ID of the program.</param>
/// <param name="programId">The <see cref="ProgramId"/> of the program.</param>
/// <param name="storageId">The <see cref="StorageId"/> where the program is located.</param>
/// <param name="accessControlData">The FS access control data header located in the program's ACI.</param>
/// <param name="accessControlDescriptor">The FS access control descriptor located in the program's ACID.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/> /// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: The process ID is already registered.<br/> /// <see cref="ResultFs.InvalidArgument"/>: The process ID is already registered.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns> /// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
/// <inheritdoc cref="ProgramRegistryManager.RegisterProgram"/>
public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId,
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor) ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{ {
@ -43,13 +38,10 @@ namespace LibHac.FsSrv
accessControlDescriptor); accessControlDescriptor);
} }
/// <summary>
/// Unregisters the program with the specified process ID.
/// </summary>
/// <param name="processId">The process ID of the program to unregister.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/> /// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: The process ID is not registered.<br/> /// <see cref="ResultFs.InvalidArgument"/>: The process ID is not registered.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns> /// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgram(ulong processId) public Result UnregisterProgram(ulong processId)
{ {
if (!ProgramInfo.IsInitialProgram(_processId)) if (!ProgramInfo.IsInitialProgram(_processId))
@ -58,27 +50,13 @@ namespace LibHac.FsSrv
return _registryService.UnregisterProgram(processId); return _registryService.UnregisterProgram(processId);
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
/// Gets the <see cref="ProgramInfo"/> associated with the specified process ID.
/// </summary>
/// <param name="programInfo">If the method returns successfully, contains the <see cref="ProgramInfo"/>
/// associated with the specified process ID.</param>
/// <param name="processId">The process ID of the <see cref="ProgramInfo"/> to get.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetProgramNotFound"/>: The <see cref="ProgramInfo"/> was not found.</returns>
public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{ {
return _registryService.GetProgramInfo(out programInfo, processId); return _registryService.GetProgramInfo(out programInfo, processId);
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
/// Gets the <see cref="ProgramInfo"/> associated with the specified program ID.
/// </summary>
/// <param name="programInfo">If the method returns successfully, contains the <see cref="ProgramInfo"/>
/// associated with the specified program ID.</param>
/// <param name="programId">The program ID of the <see cref="ProgramInfo"/> to get.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetProgramNotFound"/>: The <see cref="ProgramInfo"/> was not found.</returns>
public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId) public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId)
{ {
return _registryService.GetProgramInfoByProgramId(out programInfo, programId); return _registryService.GetProgramInfoByProgramId(out programInfo, programId);

View file

@ -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 internal readonly struct ProgramRegistryService
{ {
@ -10,5 +16,78 @@
ServiceImpl = serviceImpl; ServiceImpl = serviceImpl;
ProcessId = processId; ProcessId = processId;
} }
/// <summary>
/// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary>
/// <param name="programIndexMapInfo">A buffer containing the program map info to register.</param>
/// <param name="programCount">The number of programs to register. The provided buffer must be
/// large enough to hold this many <see cref="ProgramIndexMapInfo"/> entries.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.<br/>
/// <see cref="ResultFs.InvalidSize"/>: The buffer was too small to hold the specified
/// number of <see cref="ProgramIndexMapInfo"/> entries.</returns>
public Result RegisterProgramIndexMapInfo(ReadOnlySpan<byte> 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<ProgramIndexMapInfo>
mapInfo = MemoryMarshal.Cast<byte, ProgramIndexMapInfo>(programIndexMapInfo);
if (mapInfo.Length < programCount)
return ResultFs.InvalidSize.Log();
// Register the map info
return ServiceImpl.RegisterProgramIndexMapInfo(mapInfo.Slice(0, programCount));
}
/// <summary>
/// Gets the multi-program index of the calling process and the number of programs
/// in the current application.
/// </summary>
/// <param name="programIndex">When this method returns successfully, contains the
/// program index of the calling process.</param>
/// <param name="programCount">When this method returns successfully, contains the
/// number of programs in the current application.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetProgramNotFound"/>: The calling program was not found
/// in the program registry. Something's wrong with Loader if this happens.</returns>
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;
}
/// <inheritdoc cref="ProgramRegistryServiceImpl.GetProgramInfo"/>
private Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
return ServiceImpl.GetProgramInfo(out programInfo, processId);
}
} }
} }

View file

@ -5,6 +5,9 @@ using LibHac.Ncm;
namespace LibHac.FsSrv namespace LibHac.FsSrv
{ {
/// <summary>
/// Manages the main program registry and the multi-program registry.
/// </summary>
public class ProgramRegistryServiceImpl public class ProgramRegistryServiceImpl
{ {
private ProgramRegistryManager RegistryManager { get; } private ProgramRegistryManager RegistryManager { get; }
@ -16,16 +19,7 @@ namespace LibHac.FsSrv
ProgramIndexManager = new ProgramIndexMapInfoManager(); ProgramIndexManager = new ProgramIndexMapInfoManager();
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.RegisterProgram"/>
/// Registers a program with information about the program in the program registry.
/// </summary>
/// <param name="processId">The process ID of the program.</param>
/// <param name="programId">The <see cref="ProgramId"/> of the program.</param>
/// <param name="storageId">The <see cref="StorageId"/> where the program is located.</param>
/// <param name="accessControlData">The FS access control data header located in the program's ACI.</param>
/// <param name="accessControlDescriptor">The FS access control descriptor located in the program's ACID.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: The process ID is already registered.</returns>
public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId,
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor) ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{ {
@ -33,54 +27,49 @@ namespace LibHac.FsSrv
accessControlDescriptor); accessControlDescriptor);
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
/// Unregisters the program with the specified process ID.
/// </summary>
/// <param name="processId">The process ID of the program to unregister.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: The process ID is not registered.</returns>
public Result UnregisterProgram(ulong processId) public Result UnregisterProgram(ulong processId)
{ {
return RegistryManager.UnregisterProgram(processId); return RegistryManager.UnregisterProgram(processId);
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
/// Gets the <see cref="ProgramInfo"/> associated with the specified process ID.
/// </summary>
/// <param name="programInfo">If the method returns successfully, contains the <see cref="ProgramInfo"/>
/// associated with the specified process ID.</param>
/// <param name="processId">The process ID of the <see cref="ProgramInfo"/> to get.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetProgramNotFound"/>: The <see cref="ProgramInfo"/> was not found.</returns>
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);
} }
/// <summary> /// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
/// Gets the <see cref="ProgramInfo"/> associated with the specified program ID.
/// </summary>
/// <param name="programInfo">If the method returns successfully, contains the <see cref="ProgramInfo"/>
/// associated with the specified program ID.</param>
/// <param name="programId">The program ID of the <see cref="ProgramInfo"/> to get.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetProgramNotFound"/>: The <see cref="ProgramInfo"/> was not found.</returns>
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);
} }
/// <summary> /// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
/// Gets the <see cref="ProgramId"/> of the program with index <paramref name="programIndex"/> in the
/// multi-program app <paramref name="programId"/> is part of.
/// </summary>
/// <param name="programId">A program ID in the multi-program app to query.</param>
/// <param name="programIndex">The index of the program to get.</param>
/// <returns>If the program exists, the ID of the program with the specified index,
/// otherwise <see cref="ProgramId.InvalidId"/></returns>
public ProgramId GetProgramId(ProgramId programId, byte programIndex) public ProgramId GetProgramId(ProgramId programId, byte programIndex)
{ {
return ProgramIndexManager.GetProgramId(programId, programIndex); return ProgramIndexManager.GetProgramId(programId, programIndex);
} }
/// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/>
public ProgramIndexMapInfo? GetProgramIndexMapInfo(ProgramId programId)
{
return ProgramIndexManager.Get(programId);
}
/// <summary>
/// Gets the number of programs in the currently registered application.
/// </summary>
/// <returns>The number of programs.</returns>
public int GetProgramIndexMapInfoCount()
{
return ProgramIndexManager.GetProgramCount();
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Reset"/>
public Result RegisterProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
return ProgramIndexManager.Reset(programIndexMapInfo);
}
} }
} }