diff --git a/src/LibHac/FsSrv/AccessFailureManagementService.cs b/src/LibHac/FsSrv/AccessFailureManagementService.cs new file mode 100644 index 00000000..5ffe1c24 --- /dev/null +++ b/src/LibHac/FsSrv/AccessFailureManagementService.cs @@ -0,0 +1,103 @@ +using System.Runtime.CompilerServices; +using LibHac.Fs; +using LibHac.FsSrv.Impl; +using LibHac.FsSrv.Sf; +using LibHac.Sf; + +namespace LibHac.FsSrv +{ + public readonly struct AccessFailureManagementService + { + private readonly AccessFailureManagementServiceImpl _serviceImpl; + private readonly ulong _processId; + + public AccessFailureManagementService(AccessFailureManagementServiceImpl serviceImpl, ulong processId) + { + _serviceImpl = serviceImpl; + _processId = processId; + } + + internal Result GetProgramInfo(out ProgramInfo programInfo) + { + return _serviceImpl.GetProgramInfo(out programInfo, _processId); + } + + public Result OpenAccessFailureDetectionEventNotifier(out ReferenceCountedDisposable notifier, + ulong processId, bool notifyOnDeepRetry) + { + notifier = default; + + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.OpenAccessFailureDetectionEventNotifier)) + return ResultFs.PermissionDenied.Log(); + + rc = _serviceImpl.CreateNotifier(out IEventNotifier tempNotifier, processId, notifyOnDeepRetry); + if (rc.IsFailure()) return rc; + + notifier = new ReferenceCountedDisposable(tempNotifier); + return Result.Success; + } + + public Result GetAccessFailureDetectionEvent(out NativeHandle eventHandle) + { + eventHandle = default; + + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.GetAccessFailureDetectionEvent)) + return ResultFs.PermissionDenied.Log(); + + Svc.Handle handle = _serviceImpl.GetEvent(); + eventHandle = new NativeHandle(_serviceImpl.HorizonClient.Os, handle, false); + + return Result.Success; + } + + public Result IsAccessFailureDetected(out bool isDetected, ulong processId) + { + Unsafe.SkipInit(out isDetected); + + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.IsAccessFailureDetected)) + return ResultFs.PermissionDenied.Log(); + + isDetected = _serviceImpl.IsAccessFailureDetectionNotified(processId); + return Result.Success; + } + + public Result ResolveAccessFailure(ulong processId) + { + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.ResolveAccessFailure)) + return ResultFs.PermissionDenied.Log(); + + _serviceImpl.ResetAccessFailureDetection(processId); + + // Todo: Modify ServiceContext + + return Result.Success; + } + + public Result AbandonAccessFailure(ulong processId) + { + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + if (!programInfo.AccessControl.CanCall(OperationType.AbandonAccessFailure)) + return ResultFs.PermissionDenied.Log(); + + _serviceImpl.DisableAccessFailureDetection(processId); + + // Todo: Modify ServiceContext + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsSrv/AccessFailureManagementServiceImpl.cs b/src/LibHac/FsSrv/AccessFailureManagementServiceImpl.cs new file mode 100644 index 00000000..cae8779c --- /dev/null +++ b/src/LibHac/FsSrv/AccessFailureManagementServiceImpl.cs @@ -0,0 +1,61 @@ +using System; +using LibHac.FsSrv.Impl; +using LibHac.FsSrv.Sf; +using LibHac.Svc; + +namespace LibHac.FsSrv +{ + public class AccessFailureManagementServiceImpl + { + private ProgramRegistryImpl _programRegistry; + internal HorizonClient HorizonClient { get; } + private AccessFailureDetectionEventManager _eventManager; + + public AccessFailureManagementServiceImpl(ProgramRegistryImpl programRegistry, HorizonClient horizonClient) + { + _programRegistry = programRegistry; + HorizonClient = horizonClient; + _eventManager = new AccessFailureDetectionEventManager(); + } + + internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) + { + return _programRegistry.GetProgramInfo(out programInfo, processId); + } + + public Result CreateNotifier(out IEventNotifier notifier, ulong processId, bool notifyOnDeepRetry) + { + return _eventManager.CreateNotifier(out notifier, processId, notifyOnDeepRetry); + } + + public void ResetAccessFailureDetection(ulong processId) + { + _eventManager.ResetAccessFailureDetection(processId); + } + + public void DisableAccessFailureDetection(ulong processId) + { + _eventManager.DisableAccessFailureDetection(processId); + } + + public void NotifyAccessFailureDetection(ulong processId) + { + _eventManager.NotifyAccessFailureDetection(processId); + } + + public bool IsAccessFailureDetectionNotified(ulong processId) + { + return _eventManager.IsAccessFailureDetectionNotified(processId); + } + + public Handle GetEvent() + { + return _eventManager.GetEvent(); + } + + public Result HandleResolubleAccessFailure(out bool wasDeferred, Result nonDeferredResult, ulong processId) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs b/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs index e4556233..566b1f2d 100644 --- a/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs +++ b/src/LibHac/FsSrv/FileSystemProxyConfiguration.cs @@ -9,6 +9,7 @@ namespace LibHac.FsSrv public BaseFileSystemServiceImpl BaseFileSystemService { get; set; } public NcaFileSystemServiceImpl NcaFileSystemService { get; set; } public SaveDataFileSystemServiceImpl SaveDataFileSystemService { get; set; } + public AccessFailureManagementServiceImpl AccessFailureManagementService { get; set; } public TimeServiceImpl TimeService { get; set; } public StatusReportServiceImpl StatusReportService { get; set; } public ProgramRegistryServiceImpl ProgramRegistryService { get; set; } diff --git a/src/LibHac/FsSrv/FileSystemProxyImpl.cs b/src/LibHac/FsSrv/FileSystemProxyImpl.cs index a7488705..46c6201c 100644 --- a/src/LibHac/FsSrv/FileSystemProxyImpl.cs +++ b/src/LibHac/FsSrv/FileSystemProxyImpl.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Fs; using LibHac.FsSrv.Impl; @@ -67,6 +66,12 @@ namespace LibHac.FsSrv return new BaseFileSystemService(FsProxyCore.Config.BaseFileSystemService, CurrentProcess); } + private AccessFailureManagementService GetAccessFailureManagementService() + { + return new AccessFailureManagementService(FsProxyCore.Config.AccessFailureManagementService, + CurrentProcess); + } + private TimeService GetTimeService() { return new TimeService(FsProxyCore.Config.TimeService, CurrentProcess); @@ -128,16 +133,6 @@ namespace LibHac.FsSrv return ncaFsService.OpenCodeFileSystem(out fileSystem, out verificationData, in path, programId); } - public Result IsArchivedProgram(out bool isArchived, ulong processId) - { - Unsafe.SkipInit(out isArchived); - - Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); - if (rc.IsFailure()) return rc; - - return ncaFsService.IsArchivedProgram(out isArchived, processId); - } - public Result SetCurrentProcess(ulong processId) { CurrentProcess = processId; @@ -145,7 +140,8 @@ namespace LibHac.FsSrv // Initialize the NCA file system service NcaFsService = NcaFileSystemService.CreateShared(FsProxyCore.Config.NcaFileSystemService, processId); - SaveFsService = SaveDataFileSystemService.CreateShared(FsProxyCore.Config.SaveDataFileSystemService, processId); + SaveFsService = + SaveDataFileSystemService.CreateShared(FsProxyCore.Config.SaveDataFileSystemService, processId); return Result.Success; } @@ -197,7 +193,8 @@ namespace LibHac.FsSrv return ncaFsService.OpenDataStorageByCurrentProcess(out storage); } - public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable storage, ProgramId programId) + public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable storage, + ProgramId programId) { Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); if (rc.IsFailure()) @@ -209,7 +206,8 @@ namespace LibHac.FsSrv return ncaFsService.OpenDataStorageByProgramId(out storage, programId); } - public Result OpenDataStorageByDataId(out ReferenceCountedDisposable storage, DataId dataId, StorageId storageId) + public Result OpenDataStorageByDataId(out ReferenceCountedDisposable storage, DataId dataId, + StorageId storageId) { Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); if (rc.IsFailure()) @@ -240,7 +238,8 @@ namespace LibHac.FsSrv return ncaFsService.OpenDataFileSystemWithProgramIndex(out fileSystem, programIndex); } - public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable storage, byte programIndex) + public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable storage, + byte programIndex) { Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); if (rc.IsFailure()) @@ -276,7 +275,8 @@ namespace LibHac.FsSrv return saveFsService.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId); } - public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, in SaveDataAttribute attribute) + public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, + in SaveDataAttribute attribute) { Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService); if (rc.IsFailure()) return rc; @@ -797,7 +797,8 @@ namespace LibHac.FsSrv return saveFsService.UnsetSaveDataRootPath(); } - public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable fileSystem, ContentStorageId storageId) + public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable fileSystem, + ContentStorageId storageId) { Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); if (rc.IsFailure()) @@ -843,7 +844,8 @@ namespace LibHac.FsSrv } } - public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, CustomStorageId storageId) + public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, + CustomStorageId storageId) { fileSystem = default; var storageFlag = StorageType.NonGameCard; @@ -885,6 +887,16 @@ namespace LibHac.FsSrv return GetBaseFileSystemService().OpenGameCardFileSystem(out fileSystem, handle, partitionId); } + public Result IsArchivedProgram(out bool isArchived, ulong processId) + { + Unsafe.SkipInit(out isArchived); + + Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); + if (rc.IsFailure()) return rc; + + return ncaFsService.IsArchivedProgram(out isArchived, processId); + } + public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize) { Unsafe.SkipInit(out totalSize); @@ -1135,27 +1147,28 @@ namespace LibHac.FsSrv public Result OpenAccessFailureDetectionEventNotifier(out ReferenceCountedDisposable notifier, ulong processId, bool notifyOnDeepRetry) { - throw new NotImplementedException(); + return GetAccessFailureManagementService() + .OpenAccessFailureDetectionEventNotifier(out notifier, processId, notifyOnDeepRetry); } public Result GetAccessFailureDetectionEvent(out NativeHandle eventHandle) { - throw new NotImplementedException(); + return GetAccessFailureManagementService().GetAccessFailureDetectionEvent(out eventHandle); } public Result IsAccessFailureDetected(out bool isDetected, ulong processId) { - throw new NotImplementedException(); + return GetAccessFailureManagementService().IsAccessFailureDetected(out isDetected, processId); } public Result ResolveAccessFailure(ulong processId) { - throw new NotImplementedException(); + return GetAccessFailureManagementService().ResolveAccessFailure(processId); } public Result AbandonAccessFailure(ulong processId) { - throw new NotImplementedException(); + return GetAccessFailureManagementService().AbandonAccessFailure(processId); } public Result OpenMultiCommitManager(out ReferenceCountedDisposable commitManager) diff --git a/src/LibHac/FsSrv/FileSystemServer.cs b/src/LibHac/FsSrv/FileSystemServer.cs index 123bb875..ee619311 100644 --- a/src/LibHac/FsSrv/FileSystemServer.cs +++ b/src/LibHac/FsSrv/FileSystemServer.cs @@ -128,6 +128,8 @@ namespace LibHac.FsSrv baseFsServiceConfig.ProgramRegistry = programRegistry; var baseFsService = new BaseFileSystemServiceImpl(in baseFsServiceConfig); + var accessFailureManagementService = new AccessFailureManagementServiceImpl(programRegistry, Hos); + var ncaFsServiceConfig = new NcaFileSystemServiceImpl.Configuration(); ncaFsServiceConfig.BaseFsService = baseFsService; ncaFsServiceConfig.HostFsCreator = config.FsCreators.HostFileSystemCreator; @@ -186,6 +188,7 @@ namespace LibHac.FsSrv BaseFileSystemService = baseFsService, NcaFileSystemService = ncaFsService, SaveDataFileSystemService = saveFsService, + AccessFailureManagementService = accessFailureManagementService, TimeService = timeService, StatusReportService = statusReportService, ProgramRegistryService = programRegistryService, diff --git a/src/LibHac/FsSrv/Impl/AccessFailureDetectionEventManager.cs b/src/LibHac/FsSrv/Impl/AccessFailureDetectionEventManager.cs new file mode 100644 index 00000000..e4e4d2ea --- /dev/null +++ b/src/LibHac/FsSrv/Impl/AccessFailureDetectionEventManager.cs @@ -0,0 +1,39 @@ +using System; +using LibHac.FsSrv.Sf; +using LibHac.Svc; + +namespace LibHac.FsSrv.Impl +{ + public class AccessFailureDetectionEventManager + { + public Result CreateNotifier(out IEventNotifier notifier, ulong processId, bool notifyOnDeepRetry) + { + throw new NotImplementedException(); + } + + public void NotifyAccessFailureDetection(ulong processId) + { + throw new NotImplementedException(); + } + + public void ResetAccessFailureDetection(ulong processId) + { + throw new NotImplementedException(); + } + + public void DisableAccessFailureDetection(ulong processId) + { + throw new NotImplementedException(); + } + + public bool IsAccessFailureDetectionNotified(ulong processId) + { + throw new NotImplementedException(); + } + + public Handle GetEvent() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/Os/NativeHandle.cs b/src/LibHac/Os/NativeHandle.cs new file mode 100644 index 00000000..d6b587a2 --- /dev/null +++ b/src/LibHac/Os/NativeHandle.cs @@ -0,0 +1,10 @@ +namespace LibHac.Os +{ + public static class NativeHandleApi + { + public static void CloseNativeHandle(this OsState os, object handle) + { + + } + } +} diff --git a/src/LibHac/Sf/NativeHandle.cs b/src/LibHac/Sf/NativeHandle.cs index fd2ed0ac..4eda6cf3 100644 --- a/src/LibHac/Sf/NativeHandle.cs +++ b/src/LibHac/Sf/NativeHandle.cs @@ -1,21 +1,31 @@ -namespace LibHac.Sf +using System; +using LibHac.Os; +using LibHac.Svc; + +namespace LibHac.Sf { - // How should this be handled? Using a C# struct would be more accurate, but C# - // doesn't have copy constructors or any way to prevent a struct from being copied. - public class NativeHandle + public class NativeHandle : IDisposable { - public uint Handle { get; private set; } + private OsState Os { get; } + public Handle Handle { get; private set; } public bool IsManaged { get; private set; } - public NativeHandle(uint handle) + public NativeHandle(OsState os, Handle handle) { + Os = os; Handle = handle; } - public NativeHandle(uint handle, bool isManaged) + public NativeHandle(OsState os, Handle handle, bool isManaged) { Handle = handle; IsManaged = isManaged; } + + public void Dispose() + { + if (IsManaged) + Os.CloseNativeHandle(Handle.Object); + } } } diff --git a/src/LibHac/Svc/Handle.cs b/src/LibHac/Svc/Handle.cs new file mode 100644 index 00000000..19d0d1ee --- /dev/null +++ b/src/LibHac/Svc/Handle.cs @@ -0,0 +1,12 @@ +namespace LibHac.Svc +{ + public readonly struct Handle + { + public readonly object Object; + + public Handle(object obj) + { + Object = obj; + } + } +}