diff options
| author | Alex Barney <thealexbarney@gmail.com> | 2021-08-12 14:56:24 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-12 23:56:24 +0200 |
| commit | dadc0e59daa89c4dd7f0c3356f302481a4e75e6d (patch) | |
| tree | e39b6cd5198fef1fb2fe3461072b0961fd63502d /Ryujinx.HLE/HOS/Services | |
| parent | 3977d1f72b8f091443018b68277044a840931054 (diff) | |
Update to LibHac 0.13.1 (#2475)
* Update to LibHac 0.13.1
* Recreate directories for indexed saves if they're missing on emulator start
Diffstat (limited to 'Ryujinx.HLE/HOS/Services')
18 files changed, 1118 insertions, 354 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs index 2cea57e9..454ed1f3 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs @@ -2,12 +2,9 @@ using LibHac.Fs; using LibHac.Fs.Shim; using Ryujinx.Common; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.IO; using System.Linq; namespace Ryujinx.HLE.HOS.Services.Account.Acc @@ -16,16 +13,20 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc { public static readonly UserId DefaultUserId = new UserId("00000000000000010000000000000000"); - private readonly VirtualFileSystem _virtualFileSystem; private readonly AccountSaveDataManager _accountSaveDataManager; + // Todo: The account service doesn't have the permissions to delete save data. Qlaunch takes care of deleting + // save data, so we're currently passing a client with full permissions. Consider moving save data deletion + // outside of the AccountManager. + private readonly HorizonClient _horizonClient; + private ConcurrentDictionary<string, UserProfile> _profiles; public UserProfile LastOpenedUser { get; private set; } - public AccountManager(VirtualFileSystem virtualFileSystem) + public AccountManager(HorizonClient horizonClient) { - _virtualFileSystem = virtualFileSystem; + _horizonClient = horizonClient; _profiles = new ConcurrentDictionary<string, UserProfile>(); @@ -169,31 +170,22 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc SaveDataFilter saveDataFilter = new SaveDataFilter(); saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low)); - Result result = _virtualFileSystem.FsClient.OpenSaveDataIterator(out SaveDataIterator saveDataIterator, SaveDataSpaceId.User, ref saveDataFilter); - if (result.IsSuccess()) - { - Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; - - while (true) - { - saveDataIterator.ReadSaveDataInfo(out long readCount, saveDataInfo); + _horizonClient.Fs.OpenSaveDataIterator(out SaveDataIterator saveDataIterator, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); - if (readCount == 0) - { - break; - } + Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; - for (int i = 0; i < readCount; i++) - { - // TODO: We use Directory.Delete workaround because DeleteSaveData softlock without, due to a bug in LibHac 0.12.0. - string savePath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataInfo[i].SaveDataId:x16}"); - string saveMetaPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/saveMeta/{saveDataInfo[i].SaveDataId:x16}"); + while (true) + { + saveDataIterator.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure(); - Directory.Delete(savePath, true); - Directory.Delete(saveMetaPath, true); + if (readCount == 0) + { + break; + } - _virtualFileSystem.FsClient.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId); - } + for (int i = 0; i < readCount; i++) + { + _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId).ThrowIfFailure(); } } } diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 3ea956aa..b358606c 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -37,6 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati private int _notificationStorageChannelEventHandle; private int _healthWarningDisappearedSystemEventHandle; + private HorizonClient _horizon; + public IApplicationFunctions(Horizon system) { // TODO: Find where they are signaled. @@ -44,6 +46,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati _friendInvitationStorageChannelEvent = new KEvent(system.KernelContext); _notificationStorageChannelEvent = new KEvent(system.KernelContext); _healthWarningDisappearedSystemEvent = new KEvent(system.KernelContext); + + _horizon = system.LibHacHorizonManager.AmClient; } [CommandHipc(1)] @@ -103,14 +107,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati // EnsureSaveData(nn::account::Uid) -> u64 public ResultCode EnsureSaveData(ServiceCtx context) { - Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid(); - ApplicationId applicationId = new ApplicationId(context.Process.TitleId); + Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid(); + + // Mask out the low nibble of the program ID to get the application ID + ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul); BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData; ref ApplicationControlProperty control = ref controlHolder.Value; - if (LibHac.Utilities.IsEmpty(controlHolder.ByteSpan)) + if (LibHac.Utilities.IsZeros(controlHolder.ByteSpan)) { // If the current application doesn't have a loaded control property, create a dummy one // and set the savedata sizes so a user savedata will be created. @@ -124,7 +130,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games."); } - Result result = EnsureApplicationSaveData(context.Device.FileSystem.FsClient, out long requiredSize, applicationId, ref control, ref userId); + HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient; + Result result = EnsureApplicationSaveData(hos.Fs, out long requiredSize, applicationId, ref control, ref userId); context.ResponseData.Write(requiredSize); @@ -195,7 +202,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati public ResultCode ExtendSaveData(ServiceCtx context) { SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64(); - Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid(); + Uid userId = context.RequestData.ReadStruct<Uid>(); ulong saveDataSize = context.RequestData.ReadUInt64(); ulong journalSize = context.RequestData.ReadUInt64(); @@ -217,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati public ResultCode GetSaveDataSize(ServiceCtx context) { SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64(); - Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid(); + Uid userId = context.RequestData.ReadStruct<Uid>(); // NOTE: Service calls nn::fs::FindSaveDataWithFilter with SaveDataType = 1 hardcoded. // Then it calls nn::fs::GetSaveDataAvailableSize and nn::fs::GetSaveDataJournalSize to get the sizes. @@ -231,6 +238,31 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati return ResultCode.Success; } + [CommandHipc(27)] // 5.0.0+ + // CreateCacheStorage(u16 index, s64 save_size, s64 journal_size) -> (u32 storageTarget, u64 requiredSize) + public ResultCode CreateCacheStorage(ServiceCtx context) + { + ushort index = (ushort)context.RequestData.ReadUInt64(); + long saveSize = context.RequestData.ReadInt64(); + long journalSize = context.RequestData.ReadInt64(); + + // Mask out the low nibble of the program ID to get the application ID + ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul); + + BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData; + + Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize, + out CacheStorageTargetMedia storageTarget, applicationId, ref controlHolder.Value, index, saveSize, + journalSize); + + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write((ulong)storageTarget); + context.ResponseData.Write(requiredSize); + + return ResultCode.Success; + } + [CommandHipc(30)] // BeginBlockingHomeButtonShortAndLongPressed() public ResultCode BeginBlockingHomeButtonShortAndLongPressed(ServiceCtx context) @@ -517,7 +549,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_gpuErrorDetectedSystemEventHandle); // NOTE: This is used by "sdk" NSO during applet-application initialization. - // A seperate thread is setup where event-waiting is handled. + // A separate thread is setup where event-waiting is handled. // When the Event is signaled, official sw will assert. return ResultCode.Success; diff --git a/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs b/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs index dc8ed2e6..d36ec590 100644 --- a/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs +++ b/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs @@ -9,19 +9,14 @@ namespace Ryujinx.HLE.HOS.Services.Arp { class LibHacIReader : LibHac.Arp.Impl.IReader { - private Horizon System { get; } - - public LibHacIReader(Horizon system) - { - System = system; - } + public ApplicationId ApplicationId { get; set; } public Result GetApplicationLaunchProperty(out LibHac.Arp.ApplicationLaunchProperty launchProperty, ulong processId) { launchProperty = new LibHac.Arp.ApplicationLaunchProperty { BaseStorageId = StorageId.BuiltInUser, - ApplicationId = new ApplicationId(System.Device.Application.TitleId) + ApplicationId = ApplicationId }; return Result.Success; @@ -47,5 +42,27 @@ namespace Ryujinx.HLE.HOS.Services.Arp { throw new NotImplementedException(); } + + public Result GetServiceObject(out object serviceObject) + { + throw new NotImplementedException(); + } + } + + internal class LibHacArpServiceObject : LibHac.Sm.IServiceObject + { + private LibHacIReader _serviceObject; + + public LibHacArpServiceObject(LibHacIReader serviceObject) + { + _serviceObject = serviceObject; + } + + public Result GetServiceObject(out object serviceObject) + { + serviceObject = _serviceObject; + + return Result.Success; + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs index 8c408e47..760396b3 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs @@ -11,11 +11,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat [Service("bcat:s", "bcat:s")] class IServiceCreator : IpcService { - private LibHac.Bcat.Detail.Ipc.IServiceCreator _base; + private LibHac.Bcat.Impl.Ipc.IServiceCreator _base; public IServiceCreator(ServiceCtx context, string serviceName) { - context.Device.System.LibHacHorizonClient.Sm.GetService(out _base, serviceName).ThrowIfFailure(); + var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient; + applicationClient.Sm.GetService(out _base, serviceName).ThrowIfFailure(); } [CommandHipc(0)] @@ -42,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat { ulong pid = context.RequestData.ReadUInt64(); - Result rc = _base.CreateDeliveryCacheStorageService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService serv, pid); + Result rc = _base.CreateDeliveryCacheStorageService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService serv, pid); if (rc.IsSuccess()) { @@ -58,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat { ApplicationId applicationId = context.RequestData.ReadStruct<ApplicationId>(); - Result rc = _base.CreateDeliveryCacheStorageServiceWithApplicationId(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService serv, + Result rc = _base.CreateDeliveryCacheStorageServiceWithApplicationId(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService serv, applicationId); if (rc.IsSuccess()) diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs index 46c2c09c..36df6117 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs @@ -7,9 +7,9 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator { class IDeliveryCacheDirectoryService : DisposableIpcService { - private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base; + private LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService _base; - public IDeliveryCacheDirectoryService(LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService baseService) + public IDeliveryCacheDirectoryService(LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService baseService) { _base = baseService; } diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs index 55c89a3e..eada19c2 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs @@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator { class IDeliveryCacheFileService : DisposableIpcService { - private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base; + private LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService _base; - public IDeliveryCacheFileService(LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService baseService) + public IDeliveryCacheFileService(LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService baseService) { _base = baseService; } diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs index 0d2f2521..8fd6a3a8 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs @@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator { class IDeliveryCacheStorageService : DisposableIpcService { - private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base; + private LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService _base; - public IDeliveryCacheStorageService(ServiceCtx context, LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService baseService) + public IDeliveryCacheStorageService(ServiceCtx context, LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService baseService) { _base = baseService; } @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator // CreateFileService() -> object<nn::bcat::detail::ipc::IDeliveryCacheFileService> public ResultCode CreateFileService(ServiceCtx context) { - Result result = _base.CreateFileService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService service); + Result result = _base.CreateFileService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService service); if (result.IsSuccess()) { @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator // CreateDirectoryService() -> object<nn::bcat::detail::ipc::IDeliveryCacheDirectoryService> public ResultCode CreateDirectoryService(ServiceCtx context) { - Result result = _base.CreateDirectoryService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService service); + Result result = _base.CreateDirectoryService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService service); if (result.IsSuccess()) { diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs index 7774af23..1b6c84c3 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs @@ -1,10 +1,16 @@ using LibHac; using LibHac.Common; +using LibHac.Common.Keys; using LibHac.Fs; +using LibHac.FsSrv.Impl; +using LibHac.FsSrv.Sf; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using LibHac.Spl; +using System; using System.IO; +using System.Runtime.InteropServices; +using Path = System.IO.Path; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { @@ -16,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy try { - LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); - PartitionFileSystem nsp = new PartitionFileSystem(storage); + LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); + ReferenceCountedDisposable<LibHac.Fs.Fsa.IFileSystem> nsp = new(new PartitionFileSystem(storage)); - ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); + ImportTitleKeysFromNsp(nsp.Target, context.Device.System.KeySet); - openedFileSystem = new IFileSystem(nsp); + openedFileSystem = new IFileSystem(FileSystemInterfaceAdapter.CreateShared(ref nsp)); } catch (HorizonResultException ex) { @@ -45,8 +51,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy } LibHac.Fs.Fsa.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); + var sharedFs = new ReferenceCountedDisposable<LibHac.Fs.Fsa.IFileSystem>(fileSystem); - openedFileSystem = new IFileSystem(fileSystem); + openedFileSystem = new IFileSystem(FileSystemInterfaceAdapter.CreateShared(ref sharedFs)); } catch (HorizonResultException ex) { @@ -99,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy return ResultCode.PathDoesNotExist; } - public static void ImportTitleKeysFromNsp(LibHac.Fs.Fsa.IFileSystem nsp, Keyset keySet) + public static void ImportTitleKeysFromNsp(LibHac.Fs.Fsa.IFileSystem nsp, KeySet keySet) { foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik")) { @@ -125,5 +132,27 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy return FsPath.FromSpan(out path, pathBytes); } + + public static ref readonly FspPath GetFspPath(ServiceCtx context, int index = 0) + { + ulong position = (ulong)context.Request.PtrBuff[index].Position; + ulong size = (ulong)context.Request.PtrBuff[index].Size; + + ReadOnlySpan<byte> buffer = context.Memory.GetSpan(position, (int)size); + ReadOnlySpan<FspPath> fspBuffer = MemoryMarshal.Cast<byte, FspPath>(buffer); + + return ref fspBuffer[0]; + } + + public static ref readonly LibHac.FsSrv.Sf.Path GetSfPath(ServiceCtx context, int index = 0) + { + ulong position = (ulong)context.Request.PtrBuff[index].Position; + ulong size = (ulong)context.Request.PtrBuff[index].Size; + + ReadOnlySpan<byte> buffer = context.Memory.GetSpan(position, (int)size); + ReadOnlySpan<LibHac.FsSrv.Sf.Path> pathBuffer = MemoryMarshal.Cast<byte, LibHac.FsSrv.Sf.Path>(buffer); + + return ref pathBuffer[0]; + } } } diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs index 565ddc4c..99e545b1 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs @@ -1,15 +1,13 @@ using LibHac; -using LibHac.Fs; -using System; -using System.Runtime.InteropServices; +using LibHac.Sf; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { - class IDirectory : IpcService + class IDirectory : DisposableIpcService { - private LibHac.Fs.Fsa.IDirectory _baseDirectory; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDirectory> _baseDirectory; - public IDirectory(LibHac.Fs.Fsa.IDirectory directory) + public IDirectory(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDirectory> directory) { _baseDirectory = directory; } @@ -19,14 +17,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy public ResultCode Read(ServiceCtx context) { ulong bufferPosition = context.Request.ReceiveBuff[0].Position; - ulong bufferLen = context.Request.ReceiveBuff[0].Size; + ulong bufferLen = context.Request.ReceiveBuff[0].Size; - byte[] entriesBytes = new byte[bufferLen]; - Span<DirectoryEntry> entries = MemoryMarshal.Cast<byte, DirectoryEntry>(entriesBytes); + byte[] entryBuffer = new byte[bufferLen]; - Result result = _baseDirectory.Read(out long entriesRead, entries); + Result result = _baseDirectory.Target.Read(out long entriesRead, new OutBuffer(entryBuffer)); - context.Memory.Write(bufferPosition, entriesBytes); + context.Memory.Write(bufferPosition, entryBuffer); context.ResponseData.Write(entriesRead); return (ResultCode)result.Value; @@ -36,11 +33,19 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetEntryCount() -> u64 public ResultCode GetEntryCount(ServiceCtx context) { - Result result = _baseDirectory.GetEntryCount(out long entryCount); + Result result = _baseDirectory.Target.GetEntryCount(out long entryCount); context.ResponseData.Write(entryCount); return (ResultCode)result.Value; } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + _baseDirectory?.Dispose(); + } + } } } diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs index cf1611e7..3a94a2a7 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs @@ -1,13 +1,15 @@ using LibHac; using LibHac.Fs; +using LibHac.Sf; +using Ryujinx.Common; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { class IFile : DisposableIpcService { - private LibHac.Fs.Fsa.IFile _baseFile; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFile> _baseFile; - public IFile(LibHac.Fs.Fsa.IFile baseFile) + public IFile(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFile> baseFile) { _baseFile = baseFile; } @@ -18,15 +20,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { ulong position = context.Request.ReceiveBuff[0].Position; - ReadOption readOption = new ReadOption(context.RequestData.ReadInt32()); + ReadOption readOption = context.RequestData.ReadStruct<ReadOption>(); context.RequestData.BaseStream.Position += 4; long offset = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64(); - byte[] data = new byte[size]; + byte[] data = new byte[context.Request.ReceiveBuff[0].Size]; - Result result = _baseFile.Read(out long bytesRead, offset, data, readOption); + Result result = _baseFile.Target.Read(out long bytesRead, offset, new OutBuffer(data), size, readOption); context.Memory.Write(position, data); @@ -41,24 +43,24 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { ulong position = context.Request.SendBuff[0].Position; - WriteOption writeOption = new WriteOption(context.RequestData.ReadInt32()); + WriteOption writeOption = context.RequestData.ReadStruct<WriteOption>(); context.RequestData.BaseStream.Position += 4; long offset = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64(); - byte[] data = new byte[size]; + byte[] data = new byte[context.Request.SendBuff[0].Size]; context.Memory.Read(position, data); - return (ResultCode)_baseFile.Write(offset, data, writeOption).Value; + return (ResultCode)_baseFile.Target.Write(offset, new InBuffer(data), size, writeOption).Value; } [CommandHipc(2)] // Flush() public ResultCode Flush(ServiceCtx context) { - return (ResultCode)_baseFile.Flush().Value; + return (ResultCode)_baseFile.Target.Flush().Value; } [CommandHipc(3)] @@ -67,14 +69,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { long size = context.RequestData.ReadInt64(); - return (ResultCode)_baseFile.SetSize(size).Value; + return (ResultCode)_baseFile.Target.SetSize(size).Value; } [CommandHipc(4)] // GetSize() -> u64 fileSize public ResultCode GetSize(ServiceCtx context) { - Result result = _baseFile.GetSize(out long size); + Result result = _baseFile.Target.GetSize(out long size); context.ResponseData.Write(size); diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs index 5aa26258..b9b4266d 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -1,21 +1,19 @@ using LibHac; -using LibHac.Common; using LibHac.Fs; -using LibHac.Fs.Fsa; -using static Ryujinx.HLE.Utilities.StringUtils; +using LibHac.FsSrv.Sf; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { - class IFileSystem : IpcService + class IFileSystem : DisposableIpcService { - private LibHac.Fs.Fsa.IFileSystem _fileSystem; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFileSystem> _fileSystem; - public IFileSystem(LibHac.Fs.Fsa.IFileSystem provider) + public IFileSystem(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFileSystem> provider) { _fileSystem = provider; } - public LibHac.Fs.Fsa.IFileSystem GetBaseFileSystem() + public ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFileSystem> GetBaseFileSystem() { return _fileSystem; } @@ -24,79 +22,79 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // CreateFile(u32 createOption, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode CreateFile(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - CreateFileOptions createOption = (CreateFileOptions)context.RequestData.ReadInt32(); + int createOption = context.RequestData.ReadInt32(); context.RequestData.BaseStream.Position += 4; long size = context.RequestData.ReadInt64(); - return (ResultCode)_fileSystem.CreateFile(name, size, createOption).Value; + return (ResultCode)_fileSystem.Target.CreateFile(in name, size, createOption).Value; } [CommandHipc(1)] // DeleteFile(buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode DeleteFile(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - return (ResultCode)_fileSystem.DeleteFile(name).Value; + return (ResultCode)_fileSystem.Target.DeleteFile(in name).Value; } [CommandHipc(2)] // CreateDirectory(buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode CreateDirectory(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - return (ResultCode)_fileSystem.CreateDirectory(name).Value; + return (ResultCode)_fileSystem.Target.CreateDirectory(in name).Value; } [CommandHipc(3)] // DeleteDirectory(buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode DeleteDirectory(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - return (ResultCode)_fileSystem.DeleteDirectory(name).Value; + return (ResultCode)_fileSystem.Target.DeleteDirectory(in name).Value; } [CommandHipc(4)] // DeleteDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode DeleteDirectoryRecursively(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - return (ResultCode)_fileSystem.DeleteDirectoryRecursively(name).Value; + return (ResultCode)_fileSystem.Target.DeleteDirectoryRecursively(in name).Value; } [CommandHipc(5)] // RenameFile(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath) public ResultCode RenameFile(ServiceCtx context) { - U8Span oldName = ReadUtf8Span(context, 0); - U8Span newName = ReadUtf8Span(context, 1); + ref readonly Path currentName = ref FileSystemProxyHelper.GetSfPath(context, index: 0); + ref readonly Path newName = ref FileSystemProxyHelper.GetSfPath(context, index: 1); - return (ResultCode)_fileSystem.RenameFile(oldName, newName).Value; + return (ResultCode)_fileSystem.Target.RenameFile(in currentName, in newName).Value; } [CommandHipc(6)] // RenameDirectory(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath) public ResultCode RenameDirectory(ServiceCtx context) { - U8Span oldName = ReadUtf8Span(context, 0); - U8Span newName = ReadUtf8Span(context, 1); + ref readonly Path currentName = ref FileSystemProxyHelper.GetSfPath(context, index: 0); + ref readonly Path newName = ref FileSystemProxyHelper.GetSfPath(context, index: 1); - return (ResultCode)_fileSystem.RenameDirectory(oldName, newName).Value; + return (ResultCode)_fileSystem.Target.RenameDirectory(in currentName, in newName).Value; } [CommandHipc(7)] // GetEntryType(buffer<bytes<0x301>, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType public ResultCode GetEntryType(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.GetEntryType(out DirectoryEntryType entryType, name); + Result result = _fileSystem.Target.GetEntryType(out uint entryType, in name); context.ResponseData.Write((int)entryType); @@ -107,11 +105,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // OpenFile(u32 mode, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IFile> file public ResultCode OpenFile(ServiceCtx context) { - OpenMode mode = (OpenMode)context.RequestData.ReadInt32(); + uint mode = context.RequestData.ReadUInt32(); - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.OpenFile(out LibHac.Fs.Fsa.IFile file, name, mode); + Result result = _fileSystem.Target.OpenFile(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFile> file, in name, mode); if (result.IsSuccess()) { @@ -127,11 +125,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // OpenDirectory(u32 filter_flags, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IDirectory> directory public ResultCode OpenDirectory(ServiceCtx context) { - OpenDirectoryMode mode = (OpenDirectoryMode)context.RequestData.ReadInt32(); + uint mode = context.RequestData.ReadUInt32(); - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.OpenDirectory(out LibHac.Fs.Fsa.IDirectory dir, name, mode); + Result result = _fileSystem.Target.OpenDirectory(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDirectory> dir, name, mode); if (result.IsSuccess()) { @@ -147,16 +145,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // Commit() public ResultCode Commit(ServiceCtx context) { - return (ResultCode)_fileSystem.Commit().Value; + return (ResultCode)_fileSystem.Target.Commit().Value; } [CommandHipc(11)] // GetFreeSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalFreeSpace public ResultCode GetFreeSpaceSize(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.GetFreeSpaceSize(out long size, name); + Result result = _fileSystem.Target.GetFreeSpaceSize(out long size, in name); context.ResponseData.Write(size); @@ -167,9 +165,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetTotalSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalSize public ResultCode GetTotalSpaceSize(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.GetTotalSpaceSize(out long size, name); + Result result = _fileSystem.Target.GetTotalSpaceSize(out long size, in name); context.ResponseData.Write(size); @@ -180,18 +178,18 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // CleanDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path) public ResultCode CleanDirectoryRecursively(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - return (ResultCode)_fileSystem.CleanDirectoryRecursively(name).Value; + return (ResultCode)_fileSystem.Target.CleanDirectoryRecursively(in name).Value; } [CommandHipc(14)] // GetFileTimeStampRaw(buffer<bytes<0x301>, 0x19, 0x301> path) -> bytes<0x20> timestamp public ResultCode GetFileTimeStampRaw(ServiceCtx context) { - U8Span name = ReadUtf8Span(context); + ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); - Result result = _fileSystem.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, name); + Result result = _fileSystem.Target.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, in name); context.ResponseData.Write(timestamp.Created); context.ResponseData.Write(timestamp.Modified); @@ -206,5 +204,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy return (ResultCode)result.Value; } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + _fileSystem?.Dispose(); + } + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs index 62a3c62a..08f5b87b 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs @@ -1,13 +1,14 @@ using LibHac; +using LibHac.Sf; using Ryujinx.HLE.HOS.Ipc; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { class IStorage : DisposableIpcService { - private LibHac.Fs.IStorage _baseStorage; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IStorage> _baseStorage; - public IStorage(LibHac.Fs.IStorage baseStorage) + public IStorage(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IStorage> baseStorage) { _baseStorage = baseStorage; } @@ -31,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy byte[] data = new byte[size]; - Result result = _baseStorage.Read((long)offset, data); + Result result = _baseStorage.Target.Read((long)offset, new OutBuffer(data), (long)size); context.Memory.Write(buffDesc.Position, data); @@ -45,7 +46,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetSize() -> u64 size public ResultCode GetSize(ServiceCtx context) { - Result result = _baseStorage.GetSize(out long size); + Result result = _baseStorage.Target.GetSize(out long size); context.ResponseData.Write(size); diff --git a/Ryujinx.HLE/HOS/Services/Fs/IDeviceOperator.cs b/Ryujinx.HLE/HOS/Services/Fs/IDeviceOperator.cs index 4e6ee3a4..2968d89c 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IDeviceOperator.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IDeviceOperator.cs @@ -3,11 +3,11 @@ using LibHac.FsSrv; namespace Ryujinx.HLE.HOS.Services.Fs { - class IDeviceOperator : IpcService + class IDeviceOperator : DisposableIpcService { - private LibHac.FsSrv.IDeviceOperator _baseOperator; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDeviceOperator> _baseOperator; - public IDeviceOperator(LibHac.FsSrv.IDeviceOperator baseOperator) + public IDeviceOperator(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDeviceOperator> baseOperator) { _baseOperator = baseOperator; } @@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs // IsSdCardInserted() -> b8 is_inserted public ResultCode IsSdCardInserted(ServiceCtx context) { - Result result = _baseOperator.IsSdCardInserted(out bool isInserted); + Result result = _baseOperator.Target.IsSdCardInserted(out bool isInserted); context.ResponseData.Write(isInserted); @@ -27,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs // IsGameCardInserted() -> b8 is_inserted public ResultCode IsGameCardInserted(ServiceCtx context) { - Result result = _baseOperator.IsGameCardInserted(out bool isInserted); + Result result = _baseOperator.Target.IsGameCardInserted(out bool isInserted); context.ResponseData.Write(isInserted); @@ -38,11 +38,19 @@ namespace Ryujinx.HLE.HOS.Services.Fs // GetGameCardHandle() -> u32 gamecard_handle public ResultCode GetGameCardHandle(ServiceCtx context) { - Result result = _baseOperator.GetGameCardHandle(out GameCardHandle handle); + Result result = _baseOperator.Target.GetGameCardHandle(out GameCardHandle handle); context.ResponseData.Write(handle.Value); return (ResultCode)result.Value; } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + _baseOperator?.Dispose(); + } + } } } diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index bd07c103..b9205e03 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -1,33 +1,40 @@ using LibHac; using LibHac.Fs; +using LibHac.Fs.Shim; using LibHac.FsSrv; +using LibHac.FsSrv.Impl; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using LibHac.Ncm; +using LibHac.Sf; +using LibHac.Spl; using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using System.IO; using static Ryujinx.HLE.Utilities.StringUtils; +using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; +using IStorage = LibHac.FsSrv.Sf.IStorage; +using RightsId = LibHac.Fs.RightsId; using StorageId = Ryujinx.HLE.FileSystem.StorageId; namespace Ryujinx.HLE.HOS.Services.Fs { [Service("fsp-srv")] - class IFileSystemProxy : IpcService + class IFileSystemProxy : DisposableIpcService { - private LibHac.FsSrv.IFileSystemProxy _baseFileSystemProxy; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy; public IFileSystemProxy(ServiceCtx context) { - _baseFileSystemProxy = context.Device.FileSystem.FsServer.CreateFileSystemProxyService(); + var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient; + _baseFileSystemProxy = applicationClient.Fs.Impl.GetFileSystemProxyServiceObject(); } [CommandHipc(1)] - // Initialize(u64, pid) - public ResultCode Initialize(ServiceCtx context) + // SetCurrentProcess(u64, pid) + public ResultCode SetCurrentProcess(ServiceCtx context) { return ResultCode.Success; } @@ -94,241 +101,382 @@ namespace Ryujinx.HLE.HOS.Services.Fs { BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); - Result rc = FileSystemProxyHelper.ReadFsPath(out FsPath path, context); - if (rc.IsFailure()) return (ResultCode)rc.Value; + ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); - rc = _baseFileSystemProxy.OpenBisFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, ref path, bisPartitionId); - if (rc.IsFailure()) return (ResultCode)rc.Value; + Result result = _baseFileSystemProxy.Target.OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in path, bisPartitionId); + if (result.IsFailure()) return (ResultCode)result.Value; MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); return ResultCode.Success; } + [CommandHipc(12)] + // OpenBisStorage(u32 partitionId) -> object<nn::fssrv::sf::IStorage> bisStorage + public ResultCode OpenBisStorage(ServiceCtx context) + { + BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenBisStorage(out ReferenceCountedDisposable<IStorage> storage, bisPartitionId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IStorage(storage)); + + return ResultCode.Success; + } + + [CommandHipc(13)] + // InvalidateBisCache() -> () + public ResultCode InvalidateBisCache(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.InvalidateBisCache().Value; + } + [CommandHipc(18)] // OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem> public ResultCode OpenSdCardFileSystem(ServiceCtx context) { - Result rc = _baseFileSystemProxy.OpenSdCardFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem); - if (rc.IsFailure()) return (ResultCode)rc.Value; + Result result = _baseFileSystemProxy.Target.OpenSdCardFileSystem(out var fileSystem); + if (result.IsFailure()) return (ResultCode)result.Value; MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); return ResultCode.Success; } + [CommandHipc(19)] + // FormatSdCardFileSystem() -> () + public ResultCode FormatSdCardFileSystem(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.FormatSdCardFileSystem().Value; + } + [CommandHipc(21)] + // DeleteSaveDataFileSystem(u64 saveDataId) -> () public ResultCode DeleteSaveDataFileSystem(ServiceCtx context) { ulong saveDataId = context.RequestData.ReadUInt64(); - Result result = _baseFileSystemProxy.DeleteSaveDataFileSystem(saveDataId); - - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystem(saveDataId).Value; } [CommandHipc(22)] + // CreateSaveDataFileSystem(nn::fs::SaveDataAttribute attribute, nn::fs::SaveDataCreationInfo creationInfo, nn::fs::SaveDataMetaInfo metaInfo) -> () public ResultCode CreateSaveDataFileSystem(ServiceCtx context) { SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct<SaveDataCreationInfo>(); - SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct<SaveMetaCreateInfo>(); - - // TODO: There's currently no program registry for FS to reference. - // Workaround that by setting the application ID and owner ID if they're not already set - if (attribute.ProgramId == ProgramId.InvalidId) - { - attribute.ProgramId = new ProgramId(context.Device.Application.TitleId); - } + SaveDataMetaInfo metaInfo = context.RequestData.ReadStruct<SaveDataMetaInfo>(); - Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}"); - - Result result = _baseFileSystemProxy.CreateSaveDataFileSystem(ref attribute, ref creationInfo, ref metaCreateInfo); - - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo).Value; } [CommandHipc(23)] + // CreateSaveDataFileSystemBySystemSaveDataId(nn::fs::SaveDataAttribute attribute, nn::fs::SaveDataCreationInfo creationInfo) -> () public ResultCode CreateSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) { SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct<SaveDataCreationInfo>(); - Result result = _baseFileSystemProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref creationInfo); + return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in creationInfo).Value; + } - return (ResultCode)result.Value; + [CommandHipc(24)] + // RegisterSaveDataFileSystemAtomicDeletion(buffer<u64, 5> saveDataIds) -> () + public ResultCode RegisterSaveDataFileSystemAtomicDeletion(ServiceCtx context) + { + byte[] saveIdBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, saveIdBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.RegisterSaveDataFileSystemAtomicDeletion(new InBuffer(saveIdBuffer)).Value; } [CommandHipc(25)] + // DeleteSaveDataFileSystemBySaveDataSpaceId(u8 spaceId, u64 saveDataId) -> () public ResultCode DeleteSaveDataFileSystemBySaveDataSpaceId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); ulong saveDataId = context.RequestData.ReadUInt64(); - Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId); + return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId).Value; + } + + [CommandHipc(26)] + // FormatSdCardDryRun() -> () + public ResultCode FormatSdCardDryRun(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.FormatSdCardDryRun().Value; + } + + [CommandHipc(27)] + // IsExFatSupported() -> (u8 isSupported) + public ResultCode IsExFatSupported(ServiceCtx context) + { + Result result = _baseFileSystemProxy.Target.IsExFatSupported(out bool isSupported); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(isSupported); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(28)] + // DeleteSaveDataFileSystemBySaveDataAttribute(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> () public ResultCode DeleteSaveDataFileSystemBySaveDataAttribute(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); - Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, ref attribute); - - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, in attribute).Value; } [CommandHipc(30)] - // OpenGameCardStorage(u32, u32) -> object<nn::fssrv::sf::IStorage> + // OpenGameCardStorage(u32 handle, u32 partitionId) -> object<nn::fssrv::sf::IStorage> public ResultCode OpenGameCardStorage(ServiceCtx context) { GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32()); GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32(); - Result result = _baseFileSystemProxy.OpenGameCardStorage(out LibHac.Fs.IStorage storage, handle, partitionId); + Result result = _baseFileSystemProxy.Target.OpenGameCardStorage(out ReferenceCountedDisposable<IStorage> storage, handle, partitionId); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new FileSystemProxy.IStorage(storage)); - } + MakeObject(context, new FileSystemProxy.IStorage(storage)); + + return ResultCode.Success; + } + + [CommandHipc(31)] + // OpenGameCardFileSystem(u32 handle, u32 partitionId) -> object<nn::fssrv::sf::IFileSystem> + public ResultCode OpenGameCardFileSystem(ServiceCtx context) + { + GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32()); + GameCardPartition partitionId = (GameCardPartition)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, handle, partitionId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(32)] + // ExtendSaveDataFileSystem(u8 spaceId, u64 saveDataId, s64 dataSize, s64 journalSize) -> () + public ResultCode ExtendSaveDataFileSystem(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + long dataSize = context.RequestData.ReadInt64(); + long journalSize = context.RequestData.ReadInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.ExtendSaveDataFileSystem(spaceId, saveDataId, dataSize, journalSize).Value; + } + + [CommandHipc(33)] + // DeleteCacheStorage(u16 index) -> () + public ResultCode DeleteCacheStorage(ServiceCtx context) + { + ushort index = context.RequestData.ReadUInt16(); - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.DeleteCacheStorage(index).Value; + } + + [CommandHipc(34)] + // GetCacheStorageSize(u16 index) -> (s64 dataSize, s64 journalSize) + public ResultCode GetCacheStorageSize(ServiceCtx context) + { + ushort index = context.RequestData.ReadUInt16(); + + Result result = _baseFileSystemProxy.Target.GetCacheStorageSize(out long dataSize, out long journalSize, index); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(dataSize); + context.ResponseData.Write(journalSize); + + return ResultCode.Success; } [CommandHipc(35)] + // CreateSaveDataFileSystemWithHashSalt(nn::fs::SaveDataAttribute attribute, nn::fs::SaveDataCreationInfo creationInfo, nn::fs::SaveDataMetaInfo metaInfo nn::fs::HashSalt hashSalt) -> () public ResultCode CreateSaveDataFileSystemWithHashSalt(ServiceCtx context) { SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct<SaveDataCreationInfo>(); - SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct<SaveMetaCreateInfo>(); + SaveDataMetaInfo metaCreateInfo = context.RequestData.ReadStruct<SaveDataMetaInfo>(); HashSalt hashSalt = context.RequestData.ReadStruct<HashSalt>(); - // TODO: There's currently no program registry for FS to reference. - // Workaround that by setting the application ID and owner ID if they're not already set - if (attribute.ProgramId == ProgramId.InvalidId) - { - attribute.ProgramId = new ProgramId(context.Device.Application.TitleId); - } - - Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt); - - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo, in metaCreateInfo, in hashSalt).Value; } [CommandHipc(51)] - // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs + // OpenSaveDataFileSystem(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object<nn::fssrv::sf::IFileSystem> saveDataFs public ResultCode OpenSaveDataFileSystem(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); - // TODO: There's currently no program registry for FS to reference. - // Workaround that by setting the application ID if it's not already set - if (attribute.ProgramId == ProgramId.InvalidId) - { - attribute.ProgramId = new ProgramId(context.Device.Application.TitleId); - } - - Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); + Result result = _baseFileSystemProxy.Target.OpenSaveDataFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, spaceId, in attribute); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - } + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(52)] - // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs + // OpenSaveDataFileSystemBySystemSaveDataId(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); - Result result = _baseFileSystemProxy.OpenSaveDataFileSystemBySystemSaveDataId(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); + Result result = _baseFileSystemProxy.Target.OpenSaveDataFileSystemBySystemSaveDataId(out ReferenceCountedDisposable<IFileSystem> fileSystem, spaceId, in attribute); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - } + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(53)] - // OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object<nn::fssrv::sf::IFileSystem> + // OpenReadOnlySaveDataFileSystem(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object<nn::fssrv::sf::IFileSystem> public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); - // TODO: There's currently no program registry for FS to reference. - // Workaround that by setting the application ID if it's not already set - if (attribute.ProgramId == ProgramId.InvalidId) - { - attribute.ProgramId = new ProgramId(context.Device.Application.TitleId); - } + Result result = _baseFileSystemProxy.Target.OpenReadOnlySaveDataFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, spaceId, in attribute); + if (result.IsFailure()) return (ResultCode)result.Value; - Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - if (result.IsSuccess()) - { - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); - } + return ResultCode.Success; + } + + [CommandHipc(57)] + // ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(u8 spaceId, u64 saveDataId) -> (buffer<nn::fs::SaveDataExtraData, 6> extraData) + public ResultCode ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] extraDataBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, extraDataBuffer); - return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.Target.ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(new OutBuffer(extraDataBuffer), spaceId, saveDataId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.Memory.Write(context.Request.ReceiveBuff[0].Position, extraDataBuffer); + + return ResultCode.Success; + } + + [CommandHipc(58)] + // ReadSaveDataFileSystemExtraData(u64 saveDataId) -> (buffer<nn::fs::SaveDataExtraData, 6> extraData) + public ResultCode ReadSaveDataFileSystemExtraData(ServiceCtx context) + { + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] extraDataBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, extraDataBuffer); + + Result result = _baseFileSystemProxy.Target.ReadSaveDataFileSystemExtraData(new OutBuffer(extraDataBuffer), saveDataId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.Memory.Write(context.Request.ReceiveBuff[0].Position, extraDataBuffer); + + return ResultCode.Success; + } + + [CommandHipc(59)] + // WriteSaveDataFileSystemExtraData(u8 spaceId, u64 saveDataId, buffer<nn::fs::SaveDataExtraData, 5> extraData) -> () + public ResultCode WriteSaveDataFileSystemExtraData(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] extraDataBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, extraDataBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.WriteSaveDataFileSystemExtraData(saveDataId, spaceId, new InBuffer(extraDataBuffer)).Value; } [CommandHipc(60)] + // OpenSaveDataInfoReader() -> object<nn::fssrv::sf::ISaveDataInfoReader> public ResultCode OpenSaveDataInfoReader(ServiceCtx context) { - Result result = _baseFileSystemProxy.OpenSaveDataInfoReader(out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader); + Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReader(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new ISaveDataInfoReader(infoReader)); - } + MakeObject(context, new ISaveDataInfoReader(infoReader)); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(61)] + // OpenSaveDataInfoReaderBySaveDataSpaceId(u8 spaceId) -> object<nn::fssrv::sf::ISaveDataInfoReader> public ResultCode OpenSaveDataInfoReaderBySaveDataSpaceId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadByte(); - Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, spaceId); + Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderBySaveDataSpaceId(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader, spaceId); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new ISaveDataInfoReader(infoReader)); - } + MakeObject(context, new ISaveDataInfoReader(infoReader)); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(62)] + // OpenSaveDataInfoReaderOnlyCacheStorage() -> object<nn::fssrv::sf::ISaveDataInfoReader> public ResultCode OpenSaveDataInfoReaderOnlyCacheStorage(ServiceCtx context) { - SaveDataFilter filter = new SaveDataFilter(); - filter.SetSaveDataType(SaveDataType.Cache); - filter.SetProgramId(new ProgramId(context.Process.TitleId)); + Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderOnlyCacheStorage(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader); + if (result.IsFailure()) return (ResultCode)result.Value; - // FS would query the User and SdCache space IDs to find where the existing cache is (if any). - // We always have the SD card inserted, so we can always use SdCache for now. - Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId( - out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, SaveDataSpaceId.SdCache); + MakeObject(context, new ISaveDataInfoReader(infoReader)); - if (result.IsSuccess()) - { - MakeObject(context, new ISaveDataInfoReader(infoReader)); - } + return ResultCode.Success; + } + + [CommandHipc(64)] + // OpenSaveDataInternalStorageFileSystem(u8 spaceId, u64 saveDataId) -> object<nn::fssrv::sf::ISaveDataInfoReader> + public ResultCode OpenSaveDataInternalStorageFileSystem(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + Result result = _baseFileSystemProxy.Target.OpenSaveDataInternalStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, spaceId, saveDataId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(65)] + // UpdateSaveDataMacForDebug(u8 spaceId, u64 saveDataId) -> () + public ResultCode UpdateSaveDataMacForDebug(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.UpdateSaveDataMacForDebug(spaceId, saveDataId).Value; + } + + [CommandHipc(66)] + public ResultCode WriteSaveDataFileSystemExtraDataWithMask(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] extraDataBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, extraDataBuffer); + + byte[] maskBuffer = new byte[context.Request.SendBuff[1].Size]; + context.Memory.Read(context.Request.SendBuff[1].Position, maskBuffer); - return (ResultCode)result.Value; + return (ResultCode)_baseFileSystemProxy.Target.WriteSaveDataFileSystemExtraDataWithMask(saveDataId, spaceId, new InBuffer(extraDataBuffer), new InBuffer(maskBuffer)).Value; } [CommandHipc(67)] @@ -342,12 +490,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs byte[] infoBuffer = new byte[bufferLen]; - Result result = _baseFileSystemProxy.FindSaveDataWithFilter(out long count, infoBuffer, spaceId, ref filter); + Result result = _baseFileSystemProxy.Target.FindSaveDataWithFilter(out long count, new OutBuffer(infoBuffer), spaceId, in filter); + if (result.IsFailure()) return (ResultCode)result.Value; context.Memory.Write(bufferPosition, infoBuffer); context.ResponseData.Write(count); - return (ResultCode)result.Value; + return ResultCode.Success; } [CommandHipc(68)] @@ -356,23 +505,160 @@ namespace Ryujinx.HLE.HOS.Services.Fs SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>(); - Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderWithFilter( - out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, spaceId, ref filter); + Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderWithFilter(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader, spaceId, in filter); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new ISaveDataInfoReader(infoReader)); - } + MakeObject(context, new ISaveDataInfoReader(infoReader)); - return (ResultCode)result.Value; + return ResultCode.Success; + } + + [CommandHipc(69)] + public ResultCode ReadSaveDataFileSystemExtraDataBySaveDataAttribute(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); + + byte[] outputBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, outputBuffer); + + Result result = _baseFileSystemProxy.Target.ReadSaveDataFileSystemExtraDataBySaveDataAttribute(new OutBuffer(outputBuffer), spaceId, in attribute); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.Memory.Write(context.Request.ReceiveBuff[0].Position, outputBuffer); + + return ResultCode.Success; + } + + [CommandHipc(70)] + public ResultCode WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); + + byte[] extraDataBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, extraDataBuffer); + + byte[] maskBuffer = new byte[context.Request.SendBuff[1].Size]; + context.Memory.Read(context.Request.SendBuff[1].Position, maskBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(in attribute, spaceId, new InBuffer(extraDataBuffer), new InBuffer(maskBuffer)).Value; } [CommandHipc(71)] public ResultCode ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(ServiceCtx context) { - Logger.Stub?.PrintStub(LogClass.ServiceFs); + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); + + byte[] maskBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, maskBuffer); + + byte[] outputBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, outputBuffer); + + Result result = _baseFileSystemProxy.Target.ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(new OutBuffer(outputBuffer), spaceId, in attribute, new InBuffer(maskBuffer)); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.Memory.Write(context.Request.ReceiveBuff[0].Position, outputBuffer); + + return ResultCode.Success; + } + + [CommandHipc(80)] + public ResultCode OpenSaveDataMetaFile(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt32(); + SaveDataMetaType metaType = (SaveDataMetaType)context.RequestData.ReadInt32(); + SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); + + Result result = _baseFileSystemProxy.Target.OpenSaveDataMetaFile(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.IFile> file, spaceId, in attribute, metaType); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new IFile(file)); + + return ResultCode.Success; + } + + [CommandHipc(84)] + public ResultCode ListAccessibleSaveDataOwnerId(ServiceCtx context) + { + int startIndex = context.RequestData.ReadInt32(); + int bufferCount = context.RequestData.ReadInt32(); + ProgramId programId = context.RequestData.ReadStruct<ProgramId>(); + + byte[] outputBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, outputBuffer); + + Result result = _baseFileSystemProxy.Target.ListAccessibleSaveDataOwnerId(out int readCount, new OutBuffer(outputBuffer), programId, startIndex, bufferCount); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(readCount); + + return ResultCode.Success; + } + + [CommandHipc(100)] + public ResultCode OpenImageDirectoryFileSystem(ServiceCtx context) + { + ImageDirectoryId directoryId = (ImageDirectoryId)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, directoryId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(101)] + public ResultCode OpenBaseFileSystem(ServiceCtx context) + { + BaseFileSystemId fileSystemId = (BaseFileSystemId)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenBaseFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, fileSystemId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(110)] + public ResultCode OpenContentStorageFileSystem(ServiceCtx context) + { + ContentStorageId contentStorageId = (ContentStorageId)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, contentStorageId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(120)] + public ResultCode OpenCloudBackupWorkStorageFileSystem(ServiceCtx context) + { + CloudBackupWorkStorageId storageId = (CloudBackupWorkStorageId)context.RequestData.ReadInt32(); + + Result result = _baseFileSystemProxy.Target.OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, storageId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(130)] + public ResultCode OpenCustomStorageFileSystem(ServiceCtx context) + { + CustomStorageId customStorageId = (CustomStorageId)context.RequestData.ReadInt32(); - MemoryHelper.FillWithZeros(context.Memory, context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size); + Result result = _baseFileSystemProxy.Target.OpenCustomStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, customStorageId); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); return ResultCode.Success; } @@ -381,13 +667,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) { - MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); + var storage = context.Device.FileSystem.RomFs.AsStorage(true); + var sharedStorage = new ReferenceCountedDisposable<LibHac.Fs.IStorage>(storage); + ReferenceCountedDisposable<IStorage> sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); + + MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); - return 0; + return ResultCode.Success; } [CommandHipc(202)] - // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage + // OpenDataStorageByDataId(u8 storageId, nn::ncm::DataId dataId) -> object<nn::fssrv::sf::IStorage> dataStorage public ResultCode OpenDataStorageByDataId(ServiceCtx context) { StorageId storageId = (StorageId)context.RequestData.ReadByte(); @@ -396,11 +686,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs // We do a mitm here to find if the request is for an AOC. // This is because AOC can be distributed over multiple containers in the emulator. - if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel)) + if (context.Device.System.ContentManager.GetAocDataStorage(titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel)) { Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}"); - MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.ModLoader.ApplyRomFsMods((ulong)titleId, aocStorage))); + var storage = context.Device.FileSystem.ModLoader.ApplyRomFsMods(titleId, aocStorage); + var sharedStorage = new ReferenceCountedDisposable<LibHac.Fs.IStorage>(storage); + ReferenceCountedDisposable<IStorage> sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); + + MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); return ResultCode.Success; } @@ -432,8 +726,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); + var sharedStorage = new ReferenceCountedDisposable<LibHac.Fs.IStorage>(romfsStorage); + ReferenceCountedDisposable<IStorage> sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); - MakeObject(context, new FileSystemProxy.IStorage(romfsStorage)); + MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); } catch (HorizonResultException ex) { @@ -460,7 +756,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) { - MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); + var storage = context.Device.FileSystem.RomFs.AsStorage(true); + var sharedStorage = new ReferenceCountedDisposable<LibHac.Fs.IStorage>(storage); + ReferenceCountedDisposable<IStorage> sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); + + MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); return ResultCode.Success; } @@ -469,45 +769,327 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage public ResultCode OpenDeviceOperator(ServiceCtx context) { - Result result = _baseFileSystemProxy.OpenDeviceOperator(out LibHac.FsSrv.IDeviceOperator deviceOperator); + Result result = _baseFileSystemProxy.Target.OpenDeviceOperator(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.IDeviceOperator> deviceOperator); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) - { - MakeObject(context, new IDeviceOperator(deviceOperator)); - } + MakeObject(context, new IDeviceOperator(deviceOperator)); + + return ResultCode.Success; + } + + [CommandHipc(601)] + public ResultCode QuerySaveDataTotalSize(ServiceCtx context) + { + long dataSize = context.RequestData.ReadInt64(); + long journalSize = context.RequestData.ReadInt64(); + + Result result = _baseFileSystemProxy.Target.QuerySaveDataTotalSize(out long totalSize, dataSize, journalSize); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(totalSize); + + return ResultCode.Success; + } + + [CommandHipc(511)] + public ResultCode NotifySystemDataUpdateEvent(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.NotifySystemDataUpdateEvent().Value; + } + + [CommandHipc(523)] + public ResultCode SimulateDeviceDetectionEvent(ServiceCtx context) + { + bool signalEvent = context.RequestData.ReadBoolean(); + context.RequestData.BaseStream.Seek(3, SeekOrigin.Current); + SdmmcPort port = context.RequestData.ReadStruct<SdmmcPort>(); + SimulatingDeviceDetectionMode mode = context.RequestData.ReadStruct<SimulatingDeviceDetectionMode>(); + + return (ResultCode)_baseFileSystemProxy.Target.SimulateDeviceDetectionEvent(port, mode, signalEvent).Value; + } + + [CommandHipc(602)] + public ResultCode VerifySaveDataFileSystem(ServiceCtx context) + { + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] readBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, readBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.VerifySaveDataFileSystem(saveDataId, new OutBuffer(readBuffer)).Value; + } + + [CommandHipc(603)] + public ResultCode CorruptSaveDataFileSystem(ServiceCtx context) + { + ulong saveDataId = context.RequestData.ReadUInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.CorruptSaveDataFileSystem(saveDataId).Value; + } + + [CommandHipc(604)] + public ResultCode CreatePaddingFile(ServiceCtx context) + { + long size = context.RequestData.ReadInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.CreatePaddingFile(size).Value; + } + + [CommandHipc(605)] + public ResultCode DeleteAllPaddingFiles(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.DeleteAllPaddingFiles().Value; + } + + [CommandHipc(606)] + public ResultCode GetRightsId(ServiceCtx context) + { + LibHac.Ncm.StorageId storageId = (LibHac.Ncm.StorageId)context.RequestData.ReadInt64(); + ProgramId programId = context.RequestData.ReadStruct<ProgramId>(); + + Result result = _baseFileSystemProxy.Target.GetRightsId(out RightsId rightsId, programId, storageId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.WriteStruct(rightsId); + + return ResultCode.Success; + } + + [CommandHipc(607)] + public ResultCode RegisterExternalKey(ServiceCtx context) + { + RightsId rightsId = context.RequestData.ReadStruct<RightsId>(); + AccessKey accessKey = context.RequestData.ReadStruct<AccessKey>(); + + return (ResultCode)_baseFileSystemProxy.Target.RegisterExternalKey(in rightsId, in accessKey).Value; + } + + [CommandHipc(608)] + public ResultCode UnregisterAllExternalKey(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.UnregisterAllExternalKey().Value; + } + + [CommandHipc(609)] + public ResultCode GetRightsIdByPath(ServiceCtx context) + { + ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); + + Result result = _baseFileSystemProxy.Target.GetRightsIdByPath(out RightsId rightsId, in path); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.WriteStruct(rightsId); + + return ResultCode.Success; + } + + [CommandHipc(610)] + public ResultCode GetRightsIdAndKeyGenerationByPath(ServiceCtx context) + { + ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); + + Result result = _baseFileSystemProxy.Target.GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, in path); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(keyGeneration); + context.ResponseData.BaseStream.Seek(7, SeekOrigin.Current); + context.ResponseData.WriteStruct(rightsId); + + return ResultCode.Success; + } + + [CommandHipc(611)] + public ResultCode SetCurrentPosixTimeWithTimeDifference(ServiceCtx context) + { + int timeDifference = context.RequestData.ReadInt32(); + context.RequestData.BaseStream.Seek(4, SeekOrigin.Current); + long time = context.RequestData.ReadInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.SetCurrentPosixTimeWithTimeDifference(time, timeDifference).Value; + } + + [CommandHipc(612)] + public ResultCode GetFreeSpaceSizeForSaveData(ServiceCtx context) + { + SaveDataSpaceId spaceId = context.RequestData.ReadStruct<SaveDataSpaceId>(); + + Result result = _baseFileSystemProxy.Target.GetFreeSpaceSizeForSaveData(out long freeSpaceSize, spaceId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(freeSpaceSize); + + return ResultCode.Success; + } + + [CommandHipc(613)] + public ResultCode VerifySaveDataFileSystemBySaveDataSpaceId(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + byte[] readBuffer = new byte[context.Request.ReceiveBuff[0].Size]; + context.Memory.Read(context.Request.ReceiveBuff[0].Position, readBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.VerifySaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId, new OutBuffer(readBuffer)).Value; + } + + [CommandHipc(614)] + public ResultCode CorruptSaveDataFileSystemBySaveDataSpaceId(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.CorruptSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId).Value; + } + + [CommandHipc(615)] + public ResultCode QuerySaveDataInternalStorageTotalSize(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + Result result = _baseFileSystemProxy.Target.QuerySaveDataInternalStorageTotalSize(out long size, spaceId, saveDataId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(size); + + return ResultCode.Success; + } - return (ResultCode)result.Value; + [CommandHipc(616)] + public ResultCode GetSaveDataCommitId(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + + Result result = _baseFileSystemProxy.Target.GetSaveDataCommitId(out long commitId, spaceId, saveDataId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(commitId); + + return ResultCode.Success; + } + + [CommandHipc(617)] + public ResultCode UnregisterExternalKey(ServiceCtx context) + { + RightsId rightsId = context.RequestData.ReadStruct<RightsId>(); + + return (ResultCode)_baseFileSystemProxy.Target.UnregisterExternalKey(in rightsId).Value; + } + + [CommandHipc(620)] + public ResultCode SetSdCardEncryptionSeed(ServiceCtx context) + { + EncryptionSeed encryptionSeed = context.RequestData.ReadStruct<EncryptionSeed>(); + + return (ResultCode)_baseFileSystemProxy.Target.SetSdCardEncryptionSeed(in encryptionSeed).Value; } [CommandHipc(630)] - // SetSdCardAccessibility(u8) + // SetSdCardAccessibility(u8 isAccessible) public ResultCode SetSdCardAccessibility(ServiceCtx context) { bool isAccessible = context.RequestData.ReadBoolean(); - return (ResultCode)_baseFileSystemProxy.SetSdCardAccessibility(isAccessible).Value; + return (ResultCode)_baseFileSystemProxy.Target.SetSdCardAccessibility(isAccessible).Value; } [CommandHipc(631)] - // IsSdCardAccessible() -> u8 + // IsSdCardAccessible() -> u8 isAccessible public ResultCode IsSdCardAccessible(ServiceCtx context) { - Result result = _baseFileSystemProxy.IsSdCardAccessible(out bool isAccessible); + Result result = _baseFileSystemProxy.Target.IsSdCardAccessible(out bool isAccessible); + if (result.IsFailure()) return (ResultCode)result.Value; context.ResponseData.Write(isAccessible); - return (ResultCode)result.Value; + return ResultCode.Success; } - [CommandHipc(1003)] - // DisableAutoSaveDataCreation() - public ResultCode DisableAutoSaveDataCreation(ServiceCtx context) + [CommandHipc(702)] + public ResultCode IsAccessFailureDetected(ServiceCtx context) + { + ulong processId = context.RequestData.ReadUInt64(); + + Result result = _baseFileSystemProxy.Target.IsAccessFailureDetected(out bool isDetected, processId); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(isDetected); + + return ResultCode.Success; + } + + [CommandHipc(710)] + public ResultCode ResolveAccessFailure(ServiceCtx context) + { + ulong processId = context.RequestData.ReadUInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.ResolveAccessFailure(processId).Value; + } + + [CommandHipc(720)] + public ResultCode AbandonAccessFailure(ServiceCtx context) { - // NOTE: This call does nothing in original service. + ulong processId = context.RequestData.ReadUInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.AbandonAccessFailure(processId).Value; + } + + [CommandHipc(800)] + public ResultCode GetAndClearErrorInfo(ServiceCtx context) + { + Result result = _baseFileSystemProxy.Target.GetAndClearErrorInfo(out FileSystemProxyErrorInfo errorInfo); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.WriteStruct(errorInfo); return ResultCode.Success; } + [CommandHipc(810)] + public ResultCode RegisterProgramIndexMapInfo(ServiceCtx context) + { + int programCount = context.RequestData.ReadInt32(); + + byte[] mapInfoBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, mapInfoBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.RegisterProgramIndexMapInfo(new InBuffer(mapInfoBuffer), programCount).Value; + } + + [CommandHipc(1000)] + public ResultCode SetBisRootForHost(ServiceCtx context) + { + BisPartitionId partitionId = (BisPartitionId)context.RequestData.ReadInt32(); + ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); + + return (ResultCode)_baseFileSystemProxy.Target.SetBisRootForHost(partitionId, in path).Value; + } + + [CommandHipc(1001)] + public ResultCode SetSaveDataSize(ServiceCtx context) + { + long dataSize = context.RequestData.ReadInt64(); + long journalSize = context.RequestData.ReadInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.SetSaveDataSize(dataSize, journalSize).Value; + } + + [CommandHipc(1002)] + public ResultCode SetSaveDataRootPath(ServiceCtx context) + { + ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); + + return (ResultCode)_baseFileSystemProxy.Target.SetSaveDataRootPath(in path).Value; + } + + [CommandHipc(1003)] + public ResultCode DisableAutoSaveDataCreation(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.DisableAutoSaveDataCreation().Value; + } + [CommandHipc(1004)] // SetGlobalAccessLogMode(u32 mode) public ResultCode SetGlobalAccessLogMode(ServiceCtx context) @@ -542,11 +1124,39 @@ namespace Ryujinx.HLE.HOS.Services.Fs return ResultCode.Success; } + [CommandHipc(1007)] + public ResultCode RegisterUpdatePartition(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.RegisterUpdatePartition().Value; + } + + [CommandHipc(1008)] + public ResultCode OpenRegisteredUpdatePartition(ServiceCtx context) + { + Result result = _baseFileSystemProxy.Target.OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystem> fileSystem); + if (result.IsFailure()) return (ResultCode)result.Value; + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [CommandHipc(1009)] + public ResultCode GetAndClearMemoryReportInfo(ServiceCtx context) + { + Result result = _baseFileSystemProxy.Target.GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.WriteStruct(reportInfo); + + return ResultCode.Success; + } + [CommandHipc(1011)] public ResultCode GetProgramIndexForAccessLog(ServiceCtx context) { - int programIndex = 0; - int programCount = 1; + Result result = _baseFileSystemProxy.Target.GetProgramIndexForAccessLog(out int programIndex, out int programCount); + if (result.IsFailure()) return (ResultCode)result.Value; context.ResponseData.Write(programIndex); context.ResponseData.Write(programCount); @@ -554,18 +1164,82 @@ namespace Ryujinx.HLE.HOS.Services.Fs return ResultCode.Success; } + [CommandHipc(1012)] + public ResultCode GetFsStackUsage(ServiceCtx context) + { + FsStackUsageThreadType threadType = context.RequestData.ReadStruct<FsStackUsageThreadType>(); + + Result result = _baseFileSystemProxy.Target.GetFsStackUsage(out uint usage, threadType); + if (result.IsFailure()) return (ResultCode)result.Value; + + context.ResponseData.Write(usage); + + return ResultCode.Success; + } + + [CommandHipc(1013)] + public ResultCode UnsetSaveDataRootPath(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.UnsetSaveDataRootPath().Value; + } + + [CommandHipc(1014)] + public ResultCode OutputMultiProgramTagAccessLog(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.OutputMultiProgramTagAccessLog().Value; + } + + [CommandHipc(1016)] + public ResultCode FlushAccessLogOnSdCard(ServiceCtx context) + { + return (ResultCode)_baseFileSystemProxy.Target.FlushAccessLogOnSdCard().Value; + } + + [CommandHipc(1017)] + public ResultCode OutputApplicationInfoAccessLog(ServiceCtx context) + { + ApplicationInfo info = context.RequestData.ReadStruct<ApplicationInfo>(); + + return (ResultCode)_baseFileSystemProxy.Target.OutputApplicationInfoAccessLog(in info).Value; + } + + [CommandHipc(1100)] + public ResultCode OverrideSaveDataTransferTokenSignVerificationKey(ServiceCtx context) + { + byte[] keyBuffer = new byte[context.Request.SendBuff[0].Size]; + context.Memory.Read(context.Request.SendBuff[0].Position, keyBuffer); + + return (ResultCode)_baseFileSystemProxy.Target.OverrideSaveDataTransferTokenSignVerificationKey(new InBuffer(keyBuffer)).Value; + } + + [CommandHipc(1110)] + public ResultCode CorruptSaveDataFileSystemByOffset(ServiceCtx context) + { + SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); + ulong saveDataId = context.RequestData.ReadUInt64(); + long offset = context.RequestData.ReadInt64(); + + return (ResultCode)_baseFileSystemProxy.Target.CorruptSaveDataFileSystemByOffset(spaceId, saveDataId, offset).Value; + } + [CommandHipc(1200)] // 6.0.0+ // OpenMultiCommitManager() -> object<nn::fssrv::sf::IMultiCommitManager> public ResultCode OpenMultiCommitManager(ServiceCtx context) { - Result result = _baseFileSystemProxy.OpenMultiCommitManager(out LibHac.FsSrv.IMultiCommitManager commitManager); + Result result = _baseFileSystemProxy.Target.OpenMultiCommitManager(out ReferenceCountedDisposable<LibHac.FsSrv.Sf.IMultiCommitManager> commitManager); + if (result.IsFailure()) return (ResultCode)result.Value; - if (result.IsSuccess()) + MakeObject(context, new IMultiCommitManager(commitManager)); + + return ResultCode.Success; + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) { - MakeObject(context, new IMultiCommitManager(commitManager)); + _baseFileSystemProxy?.Dispose(); } - - return (ResultCode)result.Value; } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs b/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs index 675f71d2..f8245819 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs @@ -3,11 +3,11 @@ using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; namespace Ryujinx.HLE.HOS.Services.Fs { - class IMultiCommitManager : IpcService // 6.0.0+ + class IMultiCommitManager : DisposableIpcService // 6.0.0+ { - private LibHac.FsSrv.IMultiCommitManager _baseCommitManager; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.IMultiCommitManager> _baseCommitManager; - public IMultiCommitManager(LibHac.FsSrv.IMultiCommitManager baseCommitManager) + public IMultiCommitManager(ReferenceCountedDisposable<LibHac.FsSrv.Sf.IMultiCommitManager> baseCommitManager) { _baseCommitManager = baseCommitManager; } @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs { IFileSystem fileSystem = GetObject<IFileSystem>(context, 0); - Result result = _baseCommitManager.Add(fileSystem.GetBaseFileSystem()); + Result result = _baseCommitManager.Target.Add(fileSystem.GetBaseFileSystem()); return (ResultCode)result.Value; } @@ -27,9 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs // Commit() public ResultCode Commit(ServiceCtx context) { - Result result = _baseCommitManager.Commit(); + Result result = _baseCommitManager.Target.Commit(); return (ResultCode)result.Value; } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + _baseCommitManager?.Dispose(); + } + } } } diff --git a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs index bc4a2eb9..43e9a85a 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs @@ -1,13 +1,13 @@ -using System; -using LibHac; +using LibHac; +using LibHac.Sf; namespace Ryujinx.HLE.HOS.Services.Fs { class ISaveDataInfoReader : DisposableIpcService { - private ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> _baseReader; + private ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> _baseReader; - public ISaveDataInfoReader(ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> baseReader) + public ISaveDataInfoReader(ReferenceCountedDisposable<LibHac.FsSrv.Sf.ISaveDataInfoReader> baseReader) { _baseReader = baseReader; } @@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs byte[] infoBuffer = new byte[bufferLen]; - Result result = _baseReader.Target.Read(out long readCount, infoBuffer); + Result result = _baseReader.Target.Read(out long readCount, new OutBuffer(infoBuffer)); context.Memory.Write(bufferPosition, infoBuffer); context.ResponseData.Write(readCount); diff --git a/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs b/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs index d5331920..ee094ddf 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.HOS.Services.Mii.Types; +using LibHac; +using Ryujinx.HLE.HOS.Services.Mii.Types; using System; namespace Ryujinx.HLE.HOS.Services.Mii @@ -147,9 +148,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii return GetDefault(flag, ref count, elements); } - public ResultCode InitializeDatabase(Switch device) + public ResultCode InitializeDatabase(HorizonClient horizonClient) { - _miiDatabase.InitializeDatabase(device); + _miiDatabase.InitializeDatabase(horizonClient); _miiDatabase.LoadFromFile(out _isBroken); // Nintendo ignore any error code from before diff --git a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs index 0bf15a7f..682283b0 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs @@ -1,7 +1,9 @@ using LibHac; using LibHac.Common; using LibHac.Fs; +using LibHac.Fs.Fsa; using LibHac.Fs.Shim; +using LibHac.Ncm; using Ryujinx.HLE.HOS.Services.Mii.Types; using System.Runtime.CompilerServices; @@ -14,8 +16,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii private const ulong DatabaseTestSaveDataId = 0x8000000000000031; private const ulong DatabaseSaveDataId = 0x8000000000000030; - private const ulong NsTitleId = 0x010000000000001F; - private const ulong SdbTitleId = 0x0100000000000039; private static U8String DatabasePath = new U8String("mii:/MiiDatabase.dat"); private static U8String MountName = new U8String("mii"); @@ -23,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii private NintendoFigurineDatabase _database; private bool _isDirty; - private FileSystemClient _filesystemClient; + private HorizonClient _horizonClient; protected ulong UpdateCounter { get; private set; } @@ -94,74 +94,62 @@ namespace Ryujinx.HLE.HOS.Services.Mii return virtualIndex; } - public void InitializeDatabase(Switch device) + public void InitializeDatabase(HorizonClient horizonClient) { - _filesystemClient = device.FileSystem.FsClient; + _horizonClient = horizonClient; // Ensure we have valid data in the database _database.Format(); - // TODO: Unmount is currently not implemented properly at dispose, implement that and decrement MountCounter. - MountCounter = 0; - MountSave(); } private Result MountSave() { - Result result = Result.Success; + if (MountCounter != 0) + { + MountCounter++; + return Result.Success; + } - if (MountCounter == 0) + ulong saveDataId = IsTestModeEnabled ? DatabaseTestSaveDataId : DatabaseSaveDataId; + + Result result = _horizonClient.Fs.MountSystemSaveData(MountName, SaveDataSpaceId.System, saveDataId); + + if (result.IsFailure()) { - ulong targetSaveDataId; - ulong targetTitleId; + if (!ResultFs.TargetNotFound.Includes(result)) + return result; if (IsTestModeEnabled) { - targetSaveDataId = DatabaseTestSaveDataId; - targetTitleId = SdbTitleId; + result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, 0x10000, 0x10000, + SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData); + if (result.IsFailure()) return result; } else { - targetSaveDataId = DatabaseSaveDataId; - - // Nintendo use NS TitleID when creating the production save even on sdb, let's follow that behaviour. - targetTitleId = NsTitleId; - } - - U8Span mountName = new U8Span(MountName); - - result = _filesystemClient.MountSystemSaveData(mountName, SaveDataSpaceId.System, targetSaveDataId); - - if (result.IsFailure()) - { - if (ResultFs.TargetNotFound.Includes(result)) - { - // TODO: We're currently always specifying the owner ID because FS doesn't have a way of - // knowing which process called it - result = _filesystemClient.CreateSystemSaveData(targetSaveDataId, targetTitleId, 0x10000, - 0x10000, SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData); - if (result.IsFailure()) return result; - - result = _filesystemClient.MountSystemSaveData(mountName, SaveDataSpaceId.System, targetSaveDataId); - if (result.IsFailure()) return result; - } + result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, SystemProgramId.Ns.Value, 0x10000, + 0x10000, SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData); + if (result.IsFailure()) return result; } - if (result == Result.Success) - { - MountCounter++; - } + result = _horizonClient.Fs.MountSystemSaveData(MountName, SaveDataSpaceId.System, saveDataId); + if (result.IsFailure()) return result; } + if (result == Result.Success) + { + MountCounter++; + } return result; } public ResultCode DeleteFile() { - ResultCode result = (ResultCode)_filesystemClient.DeleteFile(DatabasePath).Value; + ResultCode result = (ResultCode)_horizonClient.Fs.DeleteFile(DatabasePath).Value; - _filesystemClient.Commit(MountName); + _horizonClient.Fs.Commit(MountName); return result; } @@ -179,17 +167,17 @@ namespace Ryujinx.HLE.HOS.Services.Mii ResetDatabase(); - Result result = _filesystemClient.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Read); + Result result = _horizonClient.Fs.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Read); if (result.IsSuccess()) { - result = _filesystemClient.GetFileSize(out long fileSize, handle); + result = _horizonClient.Fs.GetFileSize(out long fileSize, handle); if (result.IsSuccess()) { if (fileSize == Unsafe.SizeOf<NintendoFigurineDatabase>()) { - result = _filesystemClient.ReadFile(handle, 0, _database.AsSpan()); + result = _horizonClient.Fs.ReadFile(handle, 0, _database.AsSpan()); if (result.IsSuccess()) { @@ -211,7 +199,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii } } - _filesystemClient.CloseFile(handle); + _horizonClient.Fs.CloseFile(handle); return (ResultCode)result.Value; } @@ -225,32 +213,32 @@ namespace Ryujinx.HLE.HOS.Services.Mii private Result ForceSaveDatabase() { - Result result = _filesystemClient.CreateFile(DatabasePath, Unsafe.SizeOf<NintendoFigurineDatabase>()); + Result result = _horizonClient.Fs.CreateFile(DatabasePath, Unsafe.SizeOf<NintendoFigurineDatabase>()); if (result.IsSuccess() || ResultFs.PathAlreadyExists.Includes(result)) { - result = _filesystemClient.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Write); + result = _horizonClient.Fs.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Write); if (result.IsSuccess()) { - result = _filesystemClient.GetFileSize(out long fileSize, handle); + result = _horizonClient.Fs.GetFileSize(out long fileSize, handle); if (result.IsSuccess()) { // If the size doesn't match, recreate the file if (fileSize != Unsafe.SizeOf<NintendoFigurineDatabase>()) { - _filesystemClient.CloseFile(handle); + _horizonClient.Fs.CloseFile(handle); - result = _filesystemClient.DeleteFile(DatabasePath); + result = _horizonClient.Fs.DeleteFile(DatabasePath); if (result.IsSuccess()) { - result = _filesystemClient.CreateFile(DatabasePath, Unsafe.SizeOf<NintendoFigurineDatabase>()); + result = _horizonClient.Fs.CreateFile(DatabasePath, Unsafe.SizeOf<NintendoFigurineDatabase>()); if (result.IsSuccess()) { - result = _filesystemClient.OpenFile(out handle, DatabasePath, OpenMode.Write); + result = _horizonClient.Fs.OpenFile(out handle, DatabasePath, OpenMode.Write); } } @@ -260,10 +248,10 @@ namespace Ryujinx.HLE.HOS.Services.Mii } } - result = _filesystemClient.WriteFile(handle, 0, _database.AsReadOnlySpan(), WriteOption.Flush); + result = _horizonClient.Fs.WriteFile(handle, 0, _database.AsReadOnlySpan(), WriteOption.Flush); } - _filesystemClient.CloseFile(handle); + _horizonClient.Fs.CloseFile(handle); } } @@ -271,7 +259,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii { _isDirty = false; - result = _filesystemClient.Commit(MountName); + result = _horizonClient.Fs.Commit(MountName); } return result; |
