diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs index 2bffb2a05..a18838abe 100644 --- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs +++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs @@ -653,11 +653,11 @@ namespace Ryujinx.HLE.FileSystem.Content public SystemVersion VerifyFirmwarePackage(string firmwarePackage) { - _virtualFileSystem.ReloadKeySet(); + _virtualFileSystem.Reload(); // LibHac.NcaHeader's DecryptHeader doesn't check if HeaderKey is empty and throws InvalidDataException instead // So, we check it early for a better user experience. - if (_virtualFileSystem.KeySet.HeaderKey.IsZeros()) + if (_virtualFileSystem.KeySet.HeaderKey.IsEmpty()) { throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers."); } diff --git a/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs b/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs index 6e7e85fdd..08ec35125 100644 --- a/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs +++ b/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; diff --git a/Ryujinx.HLE/FileSystem/SaveHelper.cs b/Ryujinx.HLE/FileSystem/SaveHelper.cs new file mode 100644 index 000000000..51a255152 --- /dev/null +++ b/Ryujinx.HLE/FileSystem/SaveHelper.cs @@ -0,0 +1,45 @@ +using LibHac.Fs.Fsa; +using LibHac.FsSystem; +using Ryujinx.HLE.HOS; +using System.IO; + +namespace Ryujinx.HLE.FileSystem +{ + static class SaveHelper + { + public static IFileSystem OpenSystemSaveData(ServiceCtx context, ulong saveId) + { + SaveInfo saveInfo = new SaveInfo(0, (long)saveId, SaveDataType.SystemSaveData, SaveSpaceId.NandSystem); + string savePath = context.Device.FileSystem.GetSavePath(context, saveInfo, false); + + if (File.Exists(savePath)) + { + string tempDirectoryPath = $"{savePath}_temp"; + + Directory.CreateDirectory(tempDirectoryPath); + + IFileSystem outputFolder = new LocalFileSystem(tempDirectoryPath); + + using (LocalStorage systemSaveData = new LocalStorage(savePath, FileAccess.Read, FileMode.Open)) + { + IFileSystem saveFs = new LibHac.FsSystem.Save.SaveDataFileSystem(context.Device.System.KeySet, systemSaveData, IntegrityCheckLevel.None, false); + + saveFs.CopyDirectory(outputFolder, "/", "/"); + } + + File.Delete(savePath); + + Directory.Move(tempDirectoryPath, savePath); + } + else + { + if (!Directory.Exists(savePath)) + { + Directory.CreateDirectory(savePath); + } + } + + return new LocalFileSystem(savePath); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index fbedd8d4e..ff3232c26 100644 --- a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -1,23 +1,15 @@ using LibHac; using LibHac.Common; -using LibHac.Common.Keys; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.Fs.Shim; using LibHac.FsSrv; using LibHac.FsSystem; -using LibHac.Ncm; using LibHac.Spl; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using System; -using System.Buffers.Text; -using System.Collections.Generic; using System.IO; -using System.Runtime.CompilerServices; -using RightsId = LibHac.Fs.RightsId; namespace Ryujinx.HLE.FileSystem { @@ -32,15 +24,17 @@ namespace Ryujinx.HLE.FileSystem private static bool _isInitialized = false; - public KeySet KeySet { get; private set; } + public Keyset KeySet { get; private set; } + public FileSystemServer FsServer { get; private set; } + public FileSystemClient FsClient { get; private set; } public EmulatedGameCard GameCard { get; private set; } public EmulatedSdCard SdCard { get; private set; } - public ModLoader ModLoader { get; private set; } + public ModLoader ModLoader {get; private set;} private VirtualFileSystem() { - ReloadKeySet(); + Reload(); ModLoader = new ModLoader(); // Should only be created once } @@ -86,6 +80,39 @@ namespace Ryujinx.HLE.FileSystem internal string GetSdCardPath() => MakeFullPath(SdCardPath); public string GetNandPath() => MakeFullPath(NandPath); + internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true) + { + string saveUserPath = ""; + string baseSavePath = NandPath; + ulong currentTitleId = saveInfo.TitleId; + + switch (saveInfo.SaveSpaceId) + { + case SaveSpaceId.NandUser: baseSavePath = UserNandPath; break; + case SaveSpaceId.NandSystem: baseSavePath = SystemNandPath; break; + case SaveSpaceId.SdCard: baseSavePath = Path.Combine(SdCardPath, "Nintendo"); break; + } + + baseSavePath = Path.Combine(baseSavePath, "save"); + + if (saveInfo.TitleId == 0 && saveInfo.SaveDataType == SaveDataType.SaveData) + { + currentTitleId = context.Process.TitleId; + } + + if (saveInfo.SaveSpaceId == SaveSpaceId.NandUser) + { + saveUserPath = saveInfo.UserId.IsNull ? "savecommon" : saveInfo.UserId.ToString(); + } + + string savePath = Path.Combine(baseSavePath, + saveInfo.SaveId.ToString("x16"), + saveUserPath, + saveInfo.SaveDataType == SaveDataType.SaveData ? currentTitleId.ToString("x16") : string.Empty); + + return MakeFullPath(savePath, isDirectory); + } + public string GetFullPartitionPath(string partitionPath) { return MakeFullPath(partitionPath); @@ -109,8 +136,8 @@ namespace Ryujinx.HLE.FileSystem if (systemPath.StartsWith(baseSystemPath)) { - string rawPath = systemPath.Replace(baseSystemPath, ""); - int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar); + string rawPath = systemPath.Replace(baseSystemPath, ""); + int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar); if (firstSeparatorOffset == -1) { @@ -169,34 +196,33 @@ namespace Ryujinx.HLE.FileSystem return new DriveInfo(Path.GetPathRoot(GetBasePath())); } - public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) + public void Reload() { + ReloadKeySet(); + LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); - fsServerClient = horizon.CreatePrivilegedHorizonClient(); - var fsServer = new FileSystemServer(fsServerClient); - - DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet, fsServer); + DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet); GameCard = fsServerObjects.GameCard; - SdCard = fsServerObjects.SdCard; + SdCard = fsServerObjects.SdCard; SdCard.SetSdCardInsertionStatus(true); - var fsServerConfig = new FileSystemServerConfig + FileSystemServerConfig fsServerConfig = new FileSystemServerConfig { + FsCreators = fsServerObjects.FsCreators, DeviceOperator = fsServerObjects.DeviceOperator, - ExternalKeySet = KeySet.ExternalKeySet, - FsCreators = fsServerObjects.FsCreators + ExternalKeySet = KeySet.ExternalKeySet }; - FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig); + FsServer = new FileSystemServer(fsServerConfig); + FsClient = FsServer.CreateFileSystemClient(); } - public void ReloadKeySet() - { - KeySet ??= KeySet.CreateDefaultKeySet(); + private void ReloadKeySet() + { string keyFile = null; string titleKeyFile = null; string consoleKeyFile = null; @@ -230,7 +256,7 @@ namespace Ryujinx.HLE.FileSystem } } - ExternalKeyReader.ReadKeyFile(KeySet, keyFile, titleKeyFile, consoleKeyFile, null); + KeySet = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile); } public void ImportTickets(IFileSystem fs) @@ -251,269 +277,6 @@ namespace Ryujinx.HLE.FileSystem } } - // Save data created before we supported extra data in directory save data will not work properly if - // given empty extra data. Luckily some of that extra data can be created using the data from the - // save data indexer, which should be enough to check access permissions for user saves. - // Every single save data's extra data will be checked and fixed if needed each time the emulator is opened. - // Consider removing this at some point in the future when we don't need to worry about old saves. - public static Result FixExtraData(HorizonClient hos) - { - Result rc = GetSystemSaveList(hos, out List systemSaveIds); - if (rc.IsFailure()) return rc; - - rc = FixUnindexedSystemSaves(hos, systemSaveIds); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.System); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.User); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.SdCache); - if (rc.IsFailure()) return rc; - - return Result.Success; - } - - private static Result FixExtraDataInSpaceId(HorizonClient hos, SaveDataSpaceId spaceId) - { - Span info = stackalloc SaveDataInfo[8]; - - Result rc = hos.Fs.OpenSaveDataIterator(out var iterator, spaceId); - if (rc.IsFailure()) return rc; - - while (true) - { - rc = iterator.ReadSaveDataInfo(out long count, info); - if (rc.IsFailure()) return rc; - - if (count == 0) - return Result.Success; - - for (int i = 0; i < count; i++) - { - rc = FixExtraData(out bool wasFixNeeded, hos, in info[i]); - - if (rc.IsFailure()) - { - Logger.Warning?.Print(LogClass.Application, $"Error {rc.ToStringWithName()} when fixing extra data for save data 0x{info[i].SaveDataId:x} in the {spaceId} save data space"); - } - else if (wasFixNeeded) - { - Logger.Info?.Print(LogClass.Application, $"Tried to rebuild extra data for save data 0x{info[i].SaveDataId:x} in the {spaceId} save data space"); - } - } - } - } - - // Gets a list of all the save data files or directories in the system partition. - private static Result GetSystemSaveList(HorizonClient hos, out List list) - { - list = null; - - var mountName = "system".ToU8Span(); - DirectoryHandle handle = default; - List localList = new List(); - - try - { - Result rc = hos.Fs.MountBis(mountName, BisPartitionId.System); - if (rc.IsFailure()) return rc; - - rc = hos.Fs.OpenDirectory(out handle, "system:/save".ToU8Span(), OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - DirectoryEntry entry = new DirectoryEntry(); - - while (true) - { - rc = hos.Fs.ReadDirectory(out long readCount, SpanHelpers.AsSpan(ref entry), handle); - if (rc.IsFailure()) return rc; - - if (readCount == 0) - break; - - if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') && - bytesRead == 16 && (long)saveDataId < 0) - { - localList.Add(saveDataId); - } - } - - list = localList; - - return Result.Success; - } - finally - { - if (handle.IsValid) - { - hos.Fs.CloseDirectory(handle); - } - - if (hos.Fs.IsMounted(mountName)) - { - hos.Fs.Unmount(mountName); - } - } - } - - // Adds system save data that isn't in the save data indexer to the indexer and creates extra data for it. - // Only save data IDs added to SystemExtraDataFixInfo will be fixed. - private static Result FixUnindexedSystemSaves(HorizonClient hos, List existingSaveIds) - { - foreach (var fixInfo in SystemExtraDataFixInfo) - { - if (!existingSaveIds.Contains(fixInfo.StaticSaveDataId)) - { - continue; - } - - Result rc = FixSystemExtraData(out bool wasFixNeeded, hos, in fixInfo); - - if (rc.IsFailure()) - { - Logger.Warning?.Print(LogClass.Application, - $"Error {rc.ToStringWithName()} when fixing extra data for system save data 0x{fixInfo.StaticSaveDataId:x}"); - } - else if (wasFixNeeded) - { - Logger.Info?.Print(LogClass.Application, - $"Tried to rebuild extra data for system save data 0x{fixInfo.StaticSaveDataId:x}"); - } - } - - return Result.Success; - } - - private static Result FixSystemExtraData(out bool wasFixNeeded, HorizonClient hos, in ExtraDataFixInfo info) - { - wasFixNeeded = true; - - Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.StaticSaveDataId); - if (!rc.IsSuccess()) - { - if (!ResultFs.TargetNotFound.Includes(rc)) - return rc; - - // We'll reach this point only if the save data directory exists but it's not in the save data indexer. - // Creating the save will add it to the indexer while leaving its existing contents intact. - return hos.Fs.CreateSystemSaveData(info.StaticSaveDataId, UserId.InvalidId, info.OwnerId, info.DataSize, - info.JournalSize, info.Flags); - } - - if (extraData.Attribute.StaticSaveDataId != 0 && extraData.OwnerId != 0) - { - wasFixNeeded = false; - return Result.Success; - } - - extraData = new SaveDataExtraData - { - Attribute = { StaticSaveDataId = info.StaticSaveDataId }, - OwnerId = info.OwnerId, - Flags = info.Flags, - DataSize = info.DataSize, - JournalSize = info.JournalSize - }; - - // Make a mask for writing the entire extra data - Unsafe.SkipInit(out SaveDataExtraData extraDataMask); - SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF); - - return hos.Fs.Impl.WriteSaveDataFileSystemExtraData(SaveDataSpaceId.System, info.StaticSaveDataId, - in extraData, in extraDataMask); - } - - private static Result FixExtraData(out bool wasFixNeeded, HorizonClient hos, in SaveDataInfo info) - { - wasFixNeeded = true; - - Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId, - info.SaveDataId); - if (rc.IsFailure()) return rc; - - // The extra data should have program ID or static save data ID set if it's valid. - // We only try to fix the extra data if the info from the save data indexer has a program ID or static save data ID. - bool canFixByProgramId = extraData.Attribute.ProgramId == ProgramId.InvalidId && - info.ProgramId != ProgramId.InvalidId; - - bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0; - - if (!canFixByProgramId && !canFixBySaveDataId) - { - wasFixNeeded = false; - return Result.Success; - } - - // The save data attribute struct can be completely created from the save data info. - extraData.Attribute.ProgramId = info.ProgramId; - extraData.Attribute.UserId = info.UserId; - extraData.Attribute.StaticSaveDataId = info.StaticSaveDataId; - extraData.Attribute.Type = info.Type; - extraData.Attribute.Rank = info.Rank; - extraData.Attribute.Index = info.Index; - - // The rest of the extra data can't be created from the save data info. - // On user saves the owner ID will almost certainly be the same as the program ID. - if (info.Type != LibHac.Fs.SaveDataType.System) - { - extraData.OwnerId = info.ProgramId.Value; - } - else - { - // Try to match the system save with one of the known saves - foreach (ExtraDataFixInfo fixInfo in SystemExtraDataFixInfo) - { - if (extraData.Attribute.StaticSaveDataId == fixInfo.StaticSaveDataId) - { - extraData.OwnerId = fixInfo.OwnerId; - extraData.Flags = fixInfo.Flags; - extraData.DataSize = fixInfo.DataSize; - extraData.JournalSize = fixInfo.JournalSize; - - break; - } - } - } - - // Make a mask for writing the entire extra data - Unsafe.SkipInit(out SaveDataExtraData extraDataMask); - SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF); - - return hos.Fs.Impl.WriteSaveDataFileSystemExtraData(info.SpaceId, info.SaveDataId, in extraData, in extraDataMask); - } - - struct ExtraDataFixInfo - { - public ulong StaticSaveDataId; - public ulong OwnerId; - public SaveDataFlags Flags; - public long DataSize; - public long JournalSize; - } - - private static readonly ExtraDataFixInfo[] SystemExtraDataFixInfo = - { - new ExtraDataFixInfo() - { - StaticSaveDataId = 0x8000000000000030, - OwnerId = 0x010000000000001F, - Flags = SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData, - DataSize = 0x10000, - JournalSize = 0x10000 - }, - new ExtraDataFixInfo() - { - StaticSaveDataId = 0x8000000000001040, - OwnerId = 0x0100000000001009, - Flags = SaveDataFlags.None, - DataSize = 0xC000, - JournalSize = 0xC000 - } - }; - public void Unload() { RomFs?.Dispose(); @@ -536,7 +299,7 @@ namespace Ryujinx.HLE.FileSystem { if (_isInitialized) { - throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!"); + throw new InvalidOperationException($"VirtualFileSystem can only be instantiated once!"); } _isInitialized = true; diff --git a/Ryujinx.HLE/HLEConfiguration.cs b/Ryujinx.HLE/HLEConfiguration.cs index 0329ddb7f..ba35b92c1 100644 --- a/Ryujinx.HLE/HLEConfiguration.cs +++ b/Ryujinx.HLE/HLEConfiguration.cs @@ -1,6 +1,8 @@ using LibHac.FsSystem; using Ryujinx.Audio.Integration; +using Ryujinx.Common; using Ryujinx.Common.Configuration; +using Ryujinx.Common.Configuration.Hid; using Ryujinx.Graphics.GAL; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem.Content; @@ -8,6 +10,7 @@ using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using System; +using System.Collections.Generic; namespace Ryujinx.HLE { @@ -22,12 +25,6 @@ namespace Ryujinx.HLE /// This cannot be changed after instantiation. internal readonly VirtualFileSystem VirtualFileSystem; - /// - /// The manager for handling a LibHac Horizon instance. - /// - /// This cannot be changed after instantiation. - internal readonly LibHacHorizonManager LibHacHorizonManager; - /// /// The account manager used by the account service. /// @@ -41,7 +38,7 @@ namespace Ryujinx.HLE internal readonly ContentManager ContentManager; /// - /// The persistent information between run for multi-application capabilities. + /// The persistant information between run for multi-application capabilities. /// /// This cannot be changed after instantiation. public readonly UserChannelPersistence UserChannelPersistence; @@ -127,7 +124,7 @@ namespace Ryujinx.HLE public MemoryManagerMode MemoryManagerMode { internal get; set; } /// - /// Control the initial state of the ignore missing services setting. + /// Control the inital state of the ignore missing services setting. /// If this is set to true, when a missing service is encountered, it will try to automatically handle it instead of throwing an exception. /// /// TODO: Update this again. @@ -144,7 +141,6 @@ namespace Ryujinx.HLE public Action RefreshInputConfig { internal get; set; } public HLEConfiguration(VirtualFileSystem virtualFileSystem, - LibHacHorizonManager libHacHorizonManager, ContentManager contentManager, AccountManager accountManager, UserChannelPersistence userChannelPersistence, @@ -166,7 +162,6 @@ namespace Ryujinx.HLE AspectRatio aspectRatio) { VirtualFileSystem = virtualFileSystem; - LibHacHorizonManager = libHacHorizonManager; AccountManager = accountManager; ContentManager = contentManager; UserChannelPersistence = userChannelPersistence; diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs index f794d199e..0d48cc815 100644 --- a/Ryujinx.HLE/HOS/ApplicationLoader.cs +++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs @@ -4,17 +4,15 @@ using LibHac.Account; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.Fs.Shim; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; -using LibHac.Loader; -using LibHac.Ncm; using LibHac.Ns; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.HLE.Loaders.Npdm; using System; using System.Collections.Generic; using System.Globalization; @@ -59,14 +57,14 @@ namespace Ryujinx.HLE.HOS public string TitleName => _titleName; public string DisplayVersion => _displayVersion; - public ulong TitleId { get; private set; } - public bool TitleIs64Bit { get; private set; } + public ulong TitleId { get; private set; } + public bool TitleIs64Bit { get; private set; } public string TitleIdText => TitleId.ToString("x16"); public ApplicationLoader(Switch device) { - _device = device; + _device = device; _controlData = new BlitStruct(1); } @@ -79,7 +77,7 @@ namespace Ryujinx.HLE.HOS LocalFileSystem codeFs = new LocalFileSystem(exeFsDir); - MetaLoader metaData = ReadNpdm(codeFs); + Npdm metaData = ReadNpdm(codeFs); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { TitleId }, _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath()); @@ -93,8 +91,8 @@ namespace Ryujinx.HLE.HOS public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex) { - Nca mainNca = null; - Nca patchNca = null; + Nca mainNca = null; + Nca patchNca = null; Nca controlNca = null; fileSystem.ImportTickets(pfs); @@ -204,7 +202,7 @@ namespace Ryujinx.HLE.HOS public void LoadXci(string xciFile) { FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read); - Xci xci = new Xci(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage()); + Xci xci = new Xci(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage()); if (!xci.HasPartition(XciPartitionType.Secure)) { @@ -222,8 +220,6 @@ namespace Ryujinx.HLE.HOS try { (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, securePartition, _device.Configuration.UserChannelPersistence.Index); - - RegisterProgramMapInfo(securePartition).ThrowIfFailure(); } catch (Exception e) { @@ -248,8 +244,8 @@ namespace Ryujinx.HLE.HOS public void LoadNsp(string nspFile) { - FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); - PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); + FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); + PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); Nca mainNca; Nca patchNca; @@ -258,8 +254,6 @@ namespace Ryujinx.HLE.HOS try { (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, nsp, _device.Configuration.UserChannelPersistence.Index); - - RegisterProgramMapInfo(nsp).ThrowIfFailure(); } catch (Exception e) { @@ -292,7 +286,7 @@ namespace Ryujinx.HLE.HOS public void LoadNca(string ncaFile) { FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read); - Nca nca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); + Nca nca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); LoadNca(nca, null, null); } @@ -306,8 +300,8 @@ namespace Ryujinx.HLE.HOS return; } - IStorage dataStorage = null; - IFileSystem codeFs = null; + IStorage dataStorage = null; + IFileSystem codeFs = null; (Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), _device.Configuration.UserChannelPersistence.Index, out _); @@ -372,7 +366,7 @@ namespace Ryujinx.HLE.HOS return; } - MetaLoader metaData = ReadNpdm(codeFs); + Npdm metaData = ReadNpdm(codeFs); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(_device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId), _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath()); @@ -406,12 +400,9 @@ namespace Ryujinx.HLE.HOS _device.Configuration.VirtualFileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read)); } - // Don't create save data for system programs. - if (TitleId != 0 && (TitleId < SystemProgramId.Start.Value || TitleId > SystemAppletId.End.Value)) + if (TitleId != 0) { - // Multi-program applications can technically use any program ID for the main program, but in practice they always use 0 in the low nibble. - // We'll know if this changes in the future because stuff will get errors when trying to mount the correct save. - EnsureSaveData(new ApplicationId(TitleId & ~0xFul)); + EnsureSaveData(new ApplicationId(TitleId)); } LoadExeFs(codeFs, metaData); @@ -420,11 +411,11 @@ namespace Ryujinx.HLE.HOS } // Sets TitleId, so be sure to call before using it - private MetaLoader ReadNpdm(IFileSystem fs) + private Npdm ReadNpdm(IFileSystem fs) { Result result = fs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read); - MetaLoader metaData; + Npdm metaData; if (ResultFs.PathNotFound.Includes(result)) { @@ -434,20 +425,11 @@ namespace Ryujinx.HLE.HOS } else { - npdmFile.GetSize(out long fileSize).ThrowIfFailure(); - - var npdmBuffer = new byte[fileSize]; - npdmFile.Read(out _, 0, npdmBuffer).ThrowIfFailure(); - - metaData = new MetaLoader(); - metaData.Load(npdmBuffer).ThrowIfFailure(); + metaData = new Npdm(npdmFile.AsStream()); } - metaData.GetNpdm(out var npdm).ThrowIfFailure(); - - TitleId = npdm.Aci.Value.ProgramId.Value; - TitleIs64Bit = (npdm.Meta.Value.Flags & 1) != 0; - _device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(TitleId); + TitleId = metaData.Aci0.TitleId; + TitleIs64Bit = metaData.Is64Bit; return metaData; } @@ -455,7 +437,7 @@ namespace Ryujinx.HLE.HOS private static void ReadControlData(Switch device, Nca controlNca, ref BlitStruct controlData, ref string titleName, ref string displayVersion) { IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel); - Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read); + Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read); if (result.IsSuccess()) { @@ -479,7 +461,7 @@ namespace Ryujinx.HLE.HOS } } - private void LoadExeFs(IFileSystem codeFs, MetaLoader metaData = null) + private void LoadExeFs(IFileSystem codeFs, Npdm metaData = null) { if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs)) { @@ -537,26 +519,22 @@ namespace Ryujinx.HLE.HOS Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, _device.Configuration.MemoryManagerMode); - metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); - ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, new ProgramInfo(in npdm), executables: programs); + ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: programs); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); } public void LoadProgram(string filePath) { - MetaLoader metaData = GetDefaultNpdm(); - metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); - ProgramInfo programInfo = new ProgramInfo(in npdm); - - bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; + Npdm metaData = GetDefaultNpdm(); + bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; IExecutable executable; if (isNro) { - FileStream input = new FileStream(filePath, FileMode.Open); - NroExecutable obj = new NroExecutable(input.AsStorage()); + FileStream input = new FileStream(filePath, FileMode.Open); + NroExecutable obj = new NroExecutable(input.AsStorage()); executable = obj; @@ -574,13 +552,13 @@ namespace Ryujinx.HLE.HOS if (asetVersion == 0) { ulong iconOffset = reader.ReadUInt64(); - ulong iconSize = reader.ReadUInt64(); + ulong iconSize = reader.ReadUInt64(); ulong nacpOffset = reader.ReadUInt64(); - ulong nacpSize = reader.ReadUInt64(); + ulong nacpSize = reader.ReadUInt64(); ulong romfsOffset = reader.ReadUInt64(); - ulong romfsSize = reader.ReadUInt64(); + ulong romfsSize = reader.ReadUInt64(); if (romfsSize != 0) { @@ -595,28 +573,28 @@ namespace Ryujinx.HLE.HOS ref ApplicationControlProperty nacp = ref ControlData.Value; - programInfo.Name = nacp.Titles[(int)_device.System.State.DesiredTitleLanguage].Name.ToString(); + metaData.TitleName = nacp.Titles[(int)_device.System.State.DesiredTitleLanguage].Name.ToString(); - if (string.IsNullOrWhiteSpace(programInfo.Name)) + if (string.IsNullOrWhiteSpace(metaData.TitleName)) { - programInfo.Name = nacp.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.ToString(); + metaData.TitleName = nacp.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.ToString(); } if (nacp.PresenceGroupId != 0) { - programInfo.ProgramId = nacp.PresenceGroupId; + metaData.Aci0.TitleId = nacp.PresenceGroupId; } else if (nacp.SaveDataOwnerId.Value != 0) { - programInfo.ProgramId = nacp.SaveDataOwnerId.Value; + metaData.Aci0.TitleId = nacp.SaveDataOwnerId.Value; } else if (nacp.AddOnContentBaseId != 0) { - programInfo.ProgramId = nacp.AddOnContentBaseId - 0x1000; + metaData.Aci0.TitleId = nacp.AddOnContentBaseId - 0x1000; } else { - programInfo.ProgramId = 0000000000000000; + metaData.Aci0.TitleId = 0000000000000000; } } } @@ -634,109 +612,29 @@ namespace Ryujinx.HLE.HOS _device.Configuration.ContentManager.LoadEntries(_device); - _titleName = programInfo.Name; - TitleId = programInfo.ProgramId; - TitleIs64Bit = (npdm.Meta.Value.Flags & 1) != 0; - _device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(TitleId); + _titleName = metaData.TitleName; + TitleId = metaData.Aci0.TitleId; + TitleIs64Bit = metaData.Is64Bit; // Explicitly null titleid to disable the shader cache Graphics.Gpu.GraphicsConfig.TitleId = null; _device.Gpu.HostInitalized.Set(); - ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: executable); + ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: executable); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); } - private MetaLoader GetDefaultNpdm() + private Npdm GetDefaultNpdm() { Assembly asm = Assembly.GetCallingAssembly(); using (Stream npdmStream = asm.GetManifestResourceStream("Ryujinx.HLE.Homebrew.npdm")) { - var npdmBuffer = new byte[npdmStream.Length]; - npdmStream.Read(npdmBuffer); - - var metaLoader = new MetaLoader(); - metaLoader.Load(npdmBuffer).ThrowIfFailure(); - - return metaLoader; + return new Npdm(npdmStream); } } - private static (ulong applicationId, int programCount) GetMultiProgramInfo(VirtualFileSystem fileSystem, PartitionFileSystem pfs) - { - ulong mainProgramId = 0; - Span hasIndex = stackalloc bool[0x10]; - - fileSystem.ImportTickets(pfs); - - foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) - { - pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = new Nca(fileSystem.KeySet, ncaFile.AsStorage()); - - if (nca.Header.ContentType != NcaContentType.Program) - { - continue; - } - - int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); - - if (nca.Header.GetFsHeader(dataIndex).IsPatchSection()) - { - continue; - } - - ulong currentProgramId = nca.Header.TitleId; - ulong currentMainProgramId = currentProgramId & ~0xFFFul; - - if (mainProgramId == 0 && currentMainProgramId != 0) - { - mainProgramId = currentMainProgramId; - } - - if (mainProgramId != currentMainProgramId) - { - // As far as I know there aren't any multi-application game cards containing multi-program applications, - // so because multi-application game cards are the only way we should run into multiple applications - // we'll just return that there's a single program. - return (mainProgramId, 1); - } - - hasIndex[(int)(currentProgramId & 0xF)] = true; - } - - int programCount = 0; - - for (int i = 0; i < hasIndex.Length && hasIndex[i]; i++) - { - programCount++; - } - - return (mainProgramId, programCount); - } - - private Result RegisterProgramMapInfo(PartitionFileSystem pfs) - { - (ulong applicationId, int programCount) = GetMultiProgramInfo(_device.Configuration.VirtualFileSystem, pfs); - - if (programCount <= 0) - return Result.Success; - - Span mapInfo = stackalloc ProgramIndexMapInfo[0x10]; - - for (int i = 0; i < programCount; i++) - { - mapInfo[i].ProgramId = new ProgramId(applicationId + (uint)i); - mapInfo[i].MainProgramId = new ProgramId(applicationId); - mapInfo[i].ProgramIndex = (byte)i; - } - - return _device.System.LibHacHorizonManager.NsClient.Fs.RegisterProgramIndexMapInfo(mapInfo.Slice(0, programCount)); - } - private Result EnsureSaveData(ApplicationId applicationId) { Logger.Info?.Print(LogClass.Application, "Ensuring required savedata exists."); @@ -745,7 +643,7 @@ namespace Ryujinx.HLE.HOS ref ApplicationControlProperty control = ref ControlData.Value; - if (LibHac.Utilities.IsZeros(ControlData.ByteSpan)) + if (LibHac.Utilities.IsEmpty(ControlData.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. @@ -759,8 +657,8 @@ namespace Ryujinx.HLE.HOS "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games."); } - HorizonClient hos = _device.System.LibHacHorizonManager.RyujinxClient; - Result resultCode = hos.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, ref control); + FileSystemClient fileSystem = _device.Configuration.VirtualFileSystem.FsClient; + Result resultCode = fileSystem.EnsureApplicationCacheStorage(out _, applicationId, ref control); if (resultCode.IsFailure()) { @@ -769,7 +667,7 @@ namespace Ryujinx.HLE.HOS return resultCode; } - resultCode = EnsureApplicationSaveData(hos.Fs, out _, applicationId, ref control, ref user); + resultCode = EnsureApplicationSaveData(fileSystem, out _, applicationId, ref control, ref user); if (resultCode.IsFailure()) { diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 851d7e137..916ed7973 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -1,6 +1,6 @@ -using LibHac.Common.Keys; +using LibHac; +using LibHac.Bcat; using LibHac.Fs; -using LibHac.Fs.Shim; using LibHac.FsSystem; using Ryujinx.Audio; using Ryujinx.Audio.Input; @@ -18,6 +18,7 @@ using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy; using Ryujinx.HLE.HOS.Services.Apm; +using Ryujinx.HLE.HOS.Services.Arp; using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; using Ryujinx.HLE.HOS.Services.Caps; using Ryujinx.HLE.HOS.Services.Mii; @@ -37,7 +38,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; -using TimeSpanType = Ryujinx.HLE.HOS.Services.Time.Clock.TimeSpanType; namespace Ryujinx.HLE.HOS { @@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS internal KEvent DisplayResolutionChangeEvent { get; private set; } - public KeySet KeySet => Device.FileSystem.KeySet; + public Keyset KeySet => Device.FileSystem.KeySet; private bool _isDisposed; @@ -111,7 +111,8 @@ namespace Ryujinx.HLE.HOS internal NvHostSyncpt HostSyncpoint { get; private set; } - internal LibHacHorizonManager LibHacHorizonManager { get; private set; } + internal LibHac.Horizon LibHacHorizonServer { get; private set; } + internal HorizonClient LibHacHorizonClient { get; private set; } public Horizon(Switch device) { @@ -183,8 +184,6 @@ namespace Ryujinx.HLE.HOS ContentManager = device.Configuration.ContentManager; CaptureManager = new CaptureManager(device); - LibHacHorizonManager = device.Configuration.LibHacHorizonManager; - // TODO: use set:sys (and get external clock source id from settings) // TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate. UInt128 clockSourceId = new UInt128(Guid.NewGuid().ToByteArray()); @@ -224,16 +223,17 @@ namespace Ryujinx.HLE.HOS TimeServiceManager.Instance.SetupStandardUserSystemClock(null, false, SteadyClockTimePoint.GetRandom()); - // FIXME: TimeZone should be init here but it's actually done in ContentManager + // FIXME: TimeZone shoud be init here but it's actually done in ContentManager TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock(); - DatabaseImpl.Instance.InitializeDatabase(LibHacHorizonManager.SdbClient); + DatabaseImpl.Instance.InitializeDatabase(device); HostSyncpoint = new NvHostSyncpt(device); SurfaceFlinger = new SurfaceFlinger(device); + InitLibHacHorizon(); InitializeAudioRenderer(); } @@ -309,6 +309,20 @@ namespace Ryujinx.HLE.HOS ProgramLoader.LoadKip(KernelContext, new KipExecutable(kipFile)); } + private void InitLibHacHorizon() + { + LibHac.Horizon horizon = new LibHac.Horizon(null, Device.FileSystem.FsServer); + + horizon.CreateHorizonClient(out HorizonClient ryujinxClient).ThrowIfFailure(); + horizon.CreateHorizonClient(out HorizonClient bcatClient).ThrowIfFailure(); + + ryujinxClient.Sm.RegisterService(new LibHacIReader(this), "arp:r").ThrowIfFailure(); + new BcatServer(bcatClient); + + LibHacHorizonServer = horizon; + LibHacHorizonClient = ryujinxClient; + } + public void ChangeDockedModeState(bool newState) { if (newState != State.DockedMode) @@ -341,8 +355,8 @@ namespace Ryujinx.HLE.HOS { if (NfpDevices[nfpDeviceId].State == NfpDeviceState.SearchingForTag) { - NfpDevices[nfpDeviceId].State = NfpDeviceState.TagFound; - NfpDevices[nfpDeviceId].AmiiboId = amiiboId; + NfpDevices[nfpDeviceId].State = NfpDeviceState.TagFound; + NfpDevices[nfpDeviceId].AmiiboId = amiiboId; NfpDevices[nfpDeviceId].UseRandomUuid = useRandomUuid; } } @@ -439,8 +453,6 @@ namespace Ryujinx.HLE.HOS AudioRendererManager.Dispose(); - LibHacHorizonManager.AmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value); - KernelContext.Dispose(); } } diff --git a/Ryujinx.HLE/HOS/LibHacHorizonManager.cs b/Ryujinx.HLE/HOS/LibHacHorizonManager.cs deleted file mode 100644 index 48077aa8a..000000000 --- a/Ryujinx.HLE/HOS/LibHacHorizonManager.cs +++ /dev/null @@ -1,124 +0,0 @@ -using LibHac; -using LibHac.Bcat; -using LibHac.FsSrv.Impl; -using LibHac.Loader; -using LibHac.Ncm; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Arp; -using System; -using StorageId = LibHac.Ncm.StorageId; - -namespace Ryujinx.HLE.HOS -{ - public class LibHacHorizonManager - { - private LibHac.Horizon Server { get; set; } - public HorizonClient RyujinxClient { get; private set; } - - public HorizonClient ApplicationClient { get; private set; } - - public HorizonClient AccountClient { get; private set; } - public HorizonClient AmClient { get; private set; } - public HorizonClient BcatClient { get; private set; } - public HorizonClient FsClient { get; private set; } - public HorizonClient NsClient { get; private set; } - public HorizonClient SdbClient { get; private set; } - - internal LibHacIReader ArpIReader { get; private set; } - - public LibHacHorizonManager() - { - InitializeServer(); - } - - private void InitializeServer() - { - Server = new LibHac.Horizon(new HorizonConfiguration()); - - RyujinxClient = Server.CreatePrivilegedHorizonClient(); - } - - public void InitializeArpServer() - { - ArpIReader = new LibHacIReader(); - RyujinxClient.Sm.RegisterService(new LibHacArpServiceObject(ArpIReader), "arp:r").ThrowIfFailure(); - } - - public void InitializeBcatServer() - { - BcatClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Bcat, StorageId.BuiltInSystem), - BcatFsPermissions); - - _ = new BcatServer(BcatClient); - } - - public void InitializeFsServer(VirtualFileSystem virtualFileSystem) - { - virtualFileSystem.InitializeFsServer(Server, out var fsClient); - - FsClient = fsClient; - } - - public void InitializeSystemClients() - { - AccountClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Account, StorageId.BuiltInSystem), - AccountFsPermissions); - - AmClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Am, StorageId.BuiltInSystem), - AmFsPermissions); - - NsClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Ns, StorageId.BuiltInSystem), - NsFsPermissions); - - SdbClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Sdb, StorageId.BuiltInSystem), - SdbFacData, SdbFacDescriptor); - } - - public void InitializeApplicationClient(ProgramId programId, in Npdm npdm) - { - ApplicationClient = Server.CreateHorizonClient(new ProgramLocation(programId, StorageId.BuiltInUser), - npdm.FsAccessControlData, npdm.FsAccessControlDescriptor); - } - - private static AccessControlBits.Bits AccountFsPermissions => AccessControlBits.Bits.SystemSaveData | - AccessControlBits.Bits.GameCard | - AccessControlBits.Bits.SaveDataMeta | - AccessControlBits.Bits.GetRightsId; - - private static AccessControlBits.Bits AmFsPermissions => AccessControlBits.Bits.SaveDataManagement | - AccessControlBits.Bits.CreateSaveData | - AccessControlBits.Bits.SystemData; - private static AccessControlBits.Bits BcatFsPermissions => AccessControlBits.Bits.SystemSaveData; - - private static AccessControlBits.Bits NsFsPermissions => AccessControlBits.Bits.ApplicationInfo | - AccessControlBits.Bits.SystemSaveData | - AccessControlBits.Bits.GameCard | - AccessControlBits.Bits.SaveDataManagement | - AccessControlBits.Bits.ContentManager | - AccessControlBits.Bits.ImageManager | - AccessControlBits.Bits.SystemSaveDataManagement | - AccessControlBits.Bits.SystemUpdate | - AccessControlBits.Bits.SdCard | - AccessControlBits.Bits.FormatSdCard | - AccessControlBits.Bits.GetRightsId | - AccessControlBits.Bits.RegisterProgramIndexMapInfo | - AccessControlBits.Bits.MoveCacheStorage; - - // Sdb has save data access control info so we can't store just its access control bits - private static ReadOnlySpan SdbFacData => new byte[] - { - 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01 - }; - - private static ReadOnlySpan SdbFacDescriptor => new byte[] - { - 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - } -} diff --git a/Ryujinx.HLE/HOS/ModLoader.cs b/Ryujinx.HLE/HOS/ModLoader.cs index d09e837d1..a2e9af18a 100644 --- a/Ryujinx.HLE/HOS/ModLoader.cs +++ b/Ryujinx.HLE/HOS/ModLoader.cs @@ -3,7 +3,6 @@ using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; using LibHac.FsSystem.RomFs; -using LibHac.Loader; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.HLE.Loaders.Mods; @@ -13,6 +12,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.IO; +using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.HOS.Kernel.Process; using System.Globalization; @@ -522,7 +522,7 @@ namespace Ryujinx.HLE.HOS { public BitVector32 Stubs; public BitVector32 Replaces; - public MetaLoader Npdm; + public Npdm Npdm; public bool Modified => (Stubs.Data | Replaces.Data) != 0; } @@ -582,10 +582,9 @@ namespace Ryujinx.HLE.HOS continue; } - modLoadResult.Npdm = new MetaLoader(); - modLoadResult.Npdm.Load(File.ReadAllBytes(npdmFile.FullName)); + modLoadResult.Npdm = new Npdm(npdmFile.OpenRead()); - Logger.Info?.Print(LogClass.ModLoader, "main.npdm replaced"); + Logger.Info?.Print(LogClass.ModLoader, $"main.npdm replaced"); } } diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs index 2a49561f8..93ddd7ee6 100644 --- a/Ryujinx.HLE/HOS/ProgramLoader.cs +++ b/Ryujinx.HLE/HOS/ProgramLoader.cs @@ -1,7 +1,4 @@ using ARMeilleure.Translation.PTC; -using LibHac.Loader; -using LibHac.Ncm; -using LibHac.Util; using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel; @@ -9,25 +6,12 @@ using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.HLE.Loaders.Npdm; using System; using System.Linq; -using System.Runtime.InteropServices; -using Npdm = LibHac.Loader.Npdm; namespace Ryujinx.HLE.HOS { - struct ProgramInfo - { - public string Name; - public ulong ProgramId; - - public ProgramInfo(in Npdm npdm) - { - Name = StringUtils.Utf8ZToString(npdm.Meta.Value.ProgramName); - ProgramId = npdm.Aci.Value.ProgramId.Value; - } - } - static class ProgramLoader { private const bool AslrEnabled = true; @@ -141,21 +125,11 @@ namespace Ryujinx.HLE.HOS return true; } - public static bool LoadNsos(KernelContext context, out ProcessTamperInfo tamperInfo, MetaLoader metaData, ProgramInfo programInfo, byte[] arguments = null, params IExecutable[] executables) + public static bool LoadNsos(KernelContext context, out ProcessTamperInfo tamperInfo, Npdm metaData, byte[] arguments = null, params IExecutable[] executables) { - LibHac.Result rc = metaData.GetNpdm(out var npdm); - - if (rc.IsFailure()) - { - tamperInfo = null; - return false; - } - - ref readonly var meta = ref npdm.Meta.Value; - ulong argsStart = 0; uint argsSize = 0; - ulong codeStart = (meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL; + ulong codeStart = metaData.Is64Bit ? 0x8000000UL : 0x200000UL; uint codeSize = 0; var buildIds = executables.Select(e => (e switch @@ -208,20 +182,18 @@ namespace Ryujinx.HLE.HOS int codePagesCount = (int)(codeSize / KPageTableBase.PageSize); - int personalMmHeapPagesCount = (int)(meta.SystemResourceSize / KPageTableBase.PageSize); + int personalMmHeapPagesCount = metaData.PersonalMmHeapSize / KPageTableBase.PageSize; ProcessCreationInfo creationInfo = new ProcessCreationInfo( - programInfo.Name, - (int)meta.Version, - programInfo.ProgramId, + metaData.TitleName, + metaData.Version, + metaData.Aci0.TitleId, codeStart, codePagesCount, - (ProcessCreationFlags)meta.Flags | ProcessCreationFlags.IsApplication, + (ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication, 0, personalMmHeapPagesCount); - context.Device.System.LibHacHorizonManager.InitializeApplicationClient(new ProgramId(programInfo.ProgramId), in npdm); - KernelResult result; KResourceLimit resourceLimit = new KResourceLimit(context); @@ -245,7 +217,7 @@ namespace Ryujinx.HLE.HOS KProcess process = new KProcess(context); - MemoryRegion memoryRegion = (MemoryRegion)((npdm.Acid.Value.Flags >> 2) & 0xf); + MemoryRegion memoryRegion = (MemoryRegion)((metaData.Acid.Flags >> 2) & 0xf); if (memoryRegion > MemoryRegion.NvServices) { @@ -260,7 +232,7 @@ namespace Ryujinx.HLE.HOS result = process.Initialize( creationInfo, - MemoryMarshal.Cast(npdm.KernelCapabilityData).ToArray(), + metaData.Aci0.KernelAccessControl.Capabilities, resourceLimit, memoryRegion, processContextFactory); @@ -290,9 +262,9 @@ namespace Ryujinx.HLE.HOS } } - process.DefaultCpuCore = meta.DefaultCpuId; + process.DefaultCpuCore = metaData.DefaultCpuId; - result = process.Start(meta.MainThreadPriority, meta.MainThreadStackSize); + result = process.Start(metaData.MainThreadPriority, (ulong)metaData.MainThreadStackSize); if (result != KernelResult.Success) { diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs index 454ed1f35..2cea57e9e 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs @@ -2,9 +2,12 @@ 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 @@ -13,20 +16,16 @@ 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 _profiles; public UserProfile LastOpenedUser { get; private set; } - public AccountManager(HorizonClient horizonClient) + public AccountManager(VirtualFileSystem virtualFileSystem) { - _horizonClient = horizonClient; + _virtualFileSystem = virtualFileSystem; _profiles = new ConcurrentDictionary(); @@ -170,22 +169,31 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc SaveDataFilter saveDataFilter = new SaveDataFilter(); saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low)); - _horizonClient.Fs.OpenSaveDataIterator(out SaveDataIterator saveDataIterator, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); - - Span saveDataInfo = stackalloc SaveDataInfo[10]; - - while (true) + Result result = _virtualFileSystem.FsClient.OpenSaveDataIterator(out SaveDataIterator saveDataIterator, SaveDataSpaceId.User, ref saveDataFilter); + if (result.IsSuccess()) { - saveDataIterator.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure(); + Span saveDataInfo = stackalloc SaveDataInfo[10]; - if (readCount == 0) + while (true) { - break; - } + saveDataIterator.ReadSaveDataInfo(out long readCount, saveDataInfo); - for (int i = 0; i < readCount; i++) - { - _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId).ThrowIfFailure(); + if (readCount == 0) + { + break; + } + + 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}"); + + Directory.Delete(savePath, true); + Directory.Delete(saveMetaPath, true); + + _virtualFileSystem.FsClient.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId); + } } } } 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 b358606ca..3ea956aa0 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -37,8 +37,6 @@ 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. @@ -46,8 +44,6 @@ 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)] @@ -107,16 +103,14 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati // EnsureSaveData(nn::account::Uid) -> u64 public ResultCode EnsureSaveData(ServiceCtx context) { - Uid userId = context.RequestData.ReadStruct().ToLibHacUid(); - - // Mask out the low nibble of the program ID to get the application ID - ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul); + Uid userId = context.RequestData.ReadStruct().ToLibHacUid(); + ApplicationId applicationId = new ApplicationId(context.Process.TitleId); BlitStruct controlHolder = context.Device.Application.ControlData; ref ApplicationControlProperty control = ref controlHolder.Value; - if (LibHac.Utilities.IsZeros(controlHolder.ByteSpan)) + if (LibHac.Utilities.IsEmpty(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. @@ -130,8 +124,7 @@ 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."); } - HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient; - Result result = EnsureApplicationSaveData(hos.Fs, out long requiredSize, applicationId, ref control, ref userId); + Result result = EnsureApplicationSaveData(context.Device.FileSystem.FsClient, out long requiredSize, applicationId, ref control, ref userId); context.ResponseData.Write(requiredSize); @@ -202,7 +195,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(); + Uid userId = context.RequestData.ReadStruct().ToLibHacUid(); ulong saveDataSize = context.RequestData.ReadUInt64(); ulong journalSize = context.RequestData.ReadUInt64(); @@ -224,7 +217,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(); + Uid userId = context.RequestData.ReadStruct().ToLibHacUid(); // NOTE: Service calls nn::fs::FindSaveDataWithFilter with SaveDataType = 1 hardcoded. // Then it calls nn::fs::GetSaveDataAvailableSize and nn::fs::GetSaveDataJournalSize to get the sizes. @@ -238,31 +231,6 @@ 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 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) @@ -549,7 +517,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 separate thread is setup where event-waiting is handled. + // A seperate 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 d36ec5900..dc8ed2e6c 100644 --- a/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs +++ b/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs @@ -9,14 +9,19 @@ namespace Ryujinx.HLE.HOS.Services.Arp { class LibHacIReader : LibHac.Arp.Impl.IReader { - public ApplicationId ApplicationId { get; set; } + private Horizon System { get; } + + public LibHacIReader(Horizon system) + { + System = system; + } public Result GetApplicationLaunchProperty(out LibHac.Arp.ApplicationLaunchProperty launchProperty, ulong processId) { launchProperty = new LibHac.Arp.ApplicationLaunchProperty { BaseStorageId = StorageId.BuiltInUser, - ApplicationId = ApplicationId + ApplicationId = new ApplicationId(System.Device.Application.TitleId) }; return Result.Success; @@ -42,27 +47,5 @@ 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 760396b3e..8c408e476 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs @@ -11,12 +11,11 @@ namespace Ryujinx.HLE.HOS.Services.Bcat [Service("bcat:s", "bcat:s")] class IServiceCreator : IpcService { - private LibHac.Bcat.Impl.Ipc.IServiceCreator _base; + private LibHac.Bcat.Detail.Ipc.IServiceCreator _base; public IServiceCreator(ServiceCtx context, string serviceName) { - var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient; - applicationClient.Sm.GetService(out _base, serviceName).ThrowIfFailure(); + context.Device.System.LibHacHorizonClient.Sm.GetService(out _base, serviceName).ThrowIfFailure(); } [CommandHipc(0)] @@ -43,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat { ulong pid = context.RequestData.ReadUInt64(); - Result rc = _base.CreateDeliveryCacheStorageService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService serv, pid); + Result rc = _base.CreateDeliveryCacheStorageService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService serv, pid); if (rc.IsSuccess()) { @@ -59,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat { ApplicationId applicationId = context.RequestData.ReadStruct(); - Result rc = _base.CreateDeliveryCacheStorageServiceWithApplicationId(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService serv, + Result rc = _base.CreateDeliveryCacheStorageServiceWithApplicationId(out LibHac.Bcat.Detail.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 36df6117a..46c2c09c9 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.Impl.Ipc.IDeliveryCacheDirectoryService _base; + private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base; - public IDeliveryCacheDirectoryService(LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService baseService) + public IDeliveryCacheDirectoryService(LibHac.Bcat.Detail.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 eada19c22..55c89a3eb 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.Impl.Ipc.IDeliveryCacheFileService _base; + private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base; - public IDeliveryCacheFileService(LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService baseService) + public IDeliveryCacheFileService(LibHac.Bcat.Detail.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 8fd6a3a87..0d2f25213 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.Impl.Ipc.IDeliveryCacheStorageService _base; + private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base; - public IDeliveryCacheStorageService(ServiceCtx context, LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService baseService) + public IDeliveryCacheStorageService(ServiceCtx context, LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService baseService) { _base = baseService; } @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator // CreateFileService() -> object public ResultCode CreateFileService(ServiceCtx context) { - Result result = _base.CreateFileService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService service); + Result result = _base.CreateFileService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService service); if (result.IsSuccess()) { @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator // CreateDirectoryService() -> object public ResultCode CreateDirectoryService(ServiceCtx context) { - Result result = _base.CreateDirectoryService(out LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService service); + Result result = _base.CreateDirectoryService(out LibHac.Bcat.Detail.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 1b6c84c3b..7774af232 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs @@ -1,16 +1,10 @@ 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 { @@ -22,12 +16,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy try { - LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); - ReferenceCountedDisposable nsp = new(new PartitionFileSystem(storage)); + LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); + PartitionFileSystem nsp = new PartitionFileSystem(storage); - ImportTitleKeysFromNsp(nsp.Target, context.Device.System.KeySet); + ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - openedFileSystem = new IFileSystem(FileSystemInterfaceAdapter.CreateShared(ref nsp)); + openedFileSystem = new IFileSystem(nsp); } catch (HorizonResultException ex) { @@ -51,9 +45,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy } LibHac.Fs.Fsa.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); - var sharedFs = new ReferenceCountedDisposable(fileSystem); - openedFileSystem = new IFileSystem(FileSystemInterfaceAdapter.CreateShared(ref sharedFs)); + openedFileSystem = new IFileSystem(fileSystem); } catch (HorizonResultException ex) { @@ -106,7 +99,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")) { @@ -132,27 +125,5 @@ 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 buffer = context.Memory.GetSpan(position, (int)size); - ReadOnlySpan fspBuffer = MemoryMarshal.Cast(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 buffer = context.Memory.GetSpan(position, (int)size); - ReadOnlySpan pathBuffer = MemoryMarshal.Cast(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 99e545b1e..565ddc4c6 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs @@ -1,13 +1,15 @@ using LibHac; -using LibHac.Sf; +using LibHac.Fs; +using System; +using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { - class IDirectory : DisposableIpcService + class IDirectory : IpcService { - private ReferenceCountedDisposable _baseDirectory; + private LibHac.Fs.Fsa.IDirectory _baseDirectory; - public IDirectory(ReferenceCountedDisposable directory) + public IDirectory(LibHac.Fs.Fsa.IDirectory directory) { _baseDirectory = directory; } @@ -17,13 +19,14 @@ 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[] entryBuffer = new byte[bufferLen]; + byte[] entriesBytes = new byte[bufferLen]; + Span entries = MemoryMarshal.Cast(entriesBytes); - Result result = _baseDirectory.Target.Read(out long entriesRead, new OutBuffer(entryBuffer)); + Result result = _baseDirectory.Read(out long entriesRead, entries); - context.Memory.Write(bufferPosition, entryBuffer); + context.Memory.Write(bufferPosition, entriesBytes); context.ResponseData.Write(entriesRead); return (ResultCode)result.Value; @@ -33,19 +36,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetEntryCount() -> u64 public ResultCode GetEntryCount(ServiceCtx context) { - Result result = _baseDirectory.Target.GetEntryCount(out long entryCount); + Result result = _baseDirectory.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 3a94a2a72..cf1611e78 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs @@ -1,15 +1,13 @@ using LibHac; using LibHac.Fs; -using LibHac.Sf; -using Ryujinx.Common; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { class IFile : DisposableIpcService { - private ReferenceCountedDisposable _baseFile; + private LibHac.Fs.Fsa.IFile _baseFile; - public IFile(ReferenceCountedDisposable baseFile) + public IFile(LibHac.Fs.Fsa.IFile baseFile) { _baseFile = baseFile; } @@ -20,15 +18,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { ulong position = context.Request.ReceiveBuff[0].Position; - ReadOption readOption = context.RequestData.ReadStruct(); + ReadOption readOption = new ReadOption(context.RequestData.ReadInt32()); context.RequestData.BaseStream.Position += 4; long offset = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64(); - byte[] data = new byte[context.Request.ReceiveBuff[0].Size]; + byte[] data = new byte[size]; - Result result = _baseFile.Target.Read(out long bytesRead, offset, new OutBuffer(data), size, readOption); + Result result = _baseFile.Read(out long bytesRead, offset, data, readOption); context.Memory.Write(position, data); @@ -43,24 +41,24 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { ulong position = context.Request.SendBuff[0].Position; - WriteOption writeOption = context.RequestData.ReadStruct(); + WriteOption writeOption = new WriteOption(context.RequestData.ReadInt32()); context.RequestData.BaseStream.Position += 4; long offset = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64(); - byte[] data = new byte[context.Request.SendBuff[0].Size]; + byte[] data = new byte[size]; context.Memory.Read(position, data); - return (ResultCode)_baseFile.Target.Write(offset, new InBuffer(data), size, writeOption).Value; + return (ResultCode)_baseFile.Write(offset, data, writeOption).Value; } [CommandHipc(2)] // Flush() public ResultCode Flush(ServiceCtx context) { - return (ResultCode)_baseFile.Target.Flush().Value; + return (ResultCode)_baseFile.Flush().Value; } [CommandHipc(3)] @@ -69,14 +67,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { long size = context.RequestData.ReadInt64(); - return (ResultCode)_baseFile.Target.SetSize(size).Value; + return (ResultCode)_baseFile.SetSize(size).Value; } [CommandHipc(4)] // GetSize() -> u64 fileSize public ResultCode GetSize(ServiceCtx context) { - Result result = _baseFile.Target.GetSize(out long size); + Result result = _baseFile.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 b9b4266d2..5aa26258c 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -1,19 +1,21 @@ using LibHac; +using LibHac.Common; using LibHac.Fs; -using LibHac.FsSrv.Sf; +using LibHac.Fs.Fsa; +using static Ryujinx.HLE.Utilities.StringUtils; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { - class IFileSystem : DisposableIpcService + class IFileSystem : IpcService { - private ReferenceCountedDisposable _fileSystem; + private LibHac.Fs.Fsa.IFileSystem _fileSystem; - public IFileSystem(ReferenceCountedDisposable provider) + public IFileSystem(LibHac.Fs.Fsa.IFileSystem provider) { _fileSystem = provider; } - public ReferenceCountedDisposable GetBaseFileSystem() + public LibHac.Fs.Fsa.IFileSystem GetBaseFileSystem() { return _fileSystem; } @@ -22,79 +24,79 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // CreateFile(u32 createOption, u64 size, buffer, 0x19, 0x301> path) public ResultCode CreateFile(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - int createOption = context.RequestData.ReadInt32(); + CreateFileOptions createOption = (CreateFileOptions)context.RequestData.ReadInt32(); context.RequestData.BaseStream.Position += 4; long size = context.RequestData.ReadInt64(); - return (ResultCode)_fileSystem.Target.CreateFile(in name, size, createOption).Value; + return (ResultCode)_fileSystem.CreateFile(name, size, createOption).Value; } [CommandHipc(1)] // DeleteFile(buffer, 0x19, 0x301> path) public ResultCode DeleteFile(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - return (ResultCode)_fileSystem.Target.DeleteFile(in name).Value; + return (ResultCode)_fileSystem.DeleteFile(name).Value; } [CommandHipc(2)] // CreateDirectory(buffer, 0x19, 0x301> path) public ResultCode CreateDirectory(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - return (ResultCode)_fileSystem.Target.CreateDirectory(in name).Value; + return (ResultCode)_fileSystem.CreateDirectory(name).Value; } [CommandHipc(3)] // DeleteDirectory(buffer, 0x19, 0x301> path) public ResultCode DeleteDirectory(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - return (ResultCode)_fileSystem.Target.DeleteDirectory(in name).Value; + return (ResultCode)_fileSystem.DeleteDirectory(name).Value; } [CommandHipc(4)] // DeleteDirectoryRecursively(buffer, 0x19, 0x301> path) public ResultCode DeleteDirectoryRecursively(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - return (ResultCode)_fileSystem.Target.DeleteDirectoryRecursively(in name).Value; + return (ResultCode)_fileSystem.DeleteDirectoryRecursively(name).Value; } [CommandHipc(5)] // RenameFile(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) public ResultCode RenameFile(ServiceCtx context) { - ref readonly Path currentName = ref FileSystemProxyHelper.GetSfPath(context, index: 0); - ref readonly Path newName = ref FileSystemProxyHelper.GetSfPath(context, index: 1); + U8Span oldName = ReadUtf8Span(context, 0); + U8Span newName = ReadUtf8Span(context, 1); - return (ResultCode)_fileSystem.Target.RenameFile(in currentName, in newName).Value; + return (ResultCode)_fileSystem.RenameFile(oldName, newName).Value; } [CommandHipc(6)] // RenameDirectory(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) public ResultCode RenameDirectory(ServiceCtx context) { - ref readonly Path currentName = ref FileSystemProxyHelper.GetSfPath(context, index: 0); - ref readonly Path newName = ref FileSystemProxyHelper.GetSfPath(context, index: 1); + U8Span oldName = ReadUtf8Span(context, 0); + U8Span newName = ReadUtf8Span(context, 1); - return (ResultCode)_fileSystem.Target.RenameDirectory(in currentName, in newName).Value; + return (ResultCode)_fileSystem.RenameDirectory(oldName, newName).Value; } [CommandHipc(7)] // GetEntryType(buffer, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType public ResultCode GetEntryType(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.GetEntryType(out uint entryType, in name); + Result result = _fileSystem.GetEntryType(out DirectoryEntryType entryType, name); context.ResponseData.Write((int)entryType); @@ -105,11 +107,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // OpenFile(u32 mode, buffer, 0x19, 0x301> path) -> object file public ResultCode OpenFile(ServiceCtx context) { - uint mode = context.RequestData.ReadUInt32(); + OpenMode mode = (OpenMode)context.RequestData.ReadInt32(); - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.OpenFile(out ReferenceCountedDisposable file, in name, mode); + Result result = _fileSystem.OpenFile(out LibHac.Fs.Fsa.IFile file, name, mode); if (result.IsSuccess()) { @@ -125,11 +127,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // OpenDirectory(u32 filter_flags, buffer, 0x19, 0x301> path) -> object directory public ResultCode OpenDirectory(ServiceCtx context) { - uint mode = context.RequestData.ReadUInt32(); + OpenDirectoryMode mode = (OpenDirectoryMode)context.RequestData.ReadInt32(); - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.OpenDirectory(out ReferenceCountedDisposable dir, name, mode); + Result result = _fileSystem.OpenDirectory(out LibHac.Fs.Fsa.IDirectory dir, name, mode); if (result.IsSuccess()) { @@ -145,16 +147,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // Commit() public ResultCode Commit(ServiceCtx context) { - return (ResultCode)_fileSystem.Target.Commit().Value; + return (ResultCode)_fileSystem.Commit().Value; } [CommandHipc(11)] // GetFreeSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalFreeSpace public ResultCode GetFreeSpaceSize(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.GetFreeSpaceSize(out long size, in name); + Result result = _fileSystem.GetFreeSpaceSize(out long size, name); context.ResponseData.Write(size); @@ -165,9 +167,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetTotalSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalSize public ResultCode GetTotalSpaceSize(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.GetTotalSpaceSize(out long size, in name); + Result result = _fileSystem.GetTotalSpaceSize(out long size, name); context.ResponseData.Write(size); @@ -178,18 +180,18 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // CleanDirectoryRecursively(buffer, 0x19, 0x301> path) public ResultCode CleanDirectoryRecursively(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - return (ResultCode)_fileSystem.Target.CleanDirectoryRecursively(in name).Value; + return (ResultCode)_fileSystem.CleanDirectoryRecursively(name).Value; } [CommandHipc(14)] // GetFileTimeStampRaw(buffer, 0x19, 0x301> path) -> bytes<0x20> timestamp public ResultCode GetFileTimeStampRaw(ServiceCtx context) { - ref readonly Path name = ref FileSystemProxyHelper.GetSfPath(context); + U8Span name = ReadUtf8Span(context); - Result result = _fileSystem.Target.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, in name); + Result result = _fileSystem.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, name); context.ResponseData.Write(timestamp.Created); context.ResponseData.Write(timestamp.Modified); @@ -204,13 +206,5 @@ 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 08f5b87b5..62a3c62ad 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs @@ -1,14 +1,13 @@ using LibHac; -using LibHac.Sf; using Ryujinx.HLE.HOS.Ipc; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { class IStorage : DisposableIpcService { - private ReferenceCountedDisposable _baseStorage; + private LibHac.Fs.IStorage _baseStorage; - public IStorage(ReferenceCountedDisposable baseStorage) + public IStorage(LibHac.Fs.IStorage baseStorage) { _baseStorage = baseStorage; } @@ -32,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy byte[] data = new byte[size]; - Result result = _baseStorage.Target.Read((long)offset, new OutBuffer(data), (long)size); + Result result = _baseStorage.Read((long)offset, data); context.Memory.Write(buffDesc.Position, data); @@ -46,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // GetSize() -> u64 size public ResultCode GetSize(ServiceCtx context) { - Result result = _baseStorage.Target.GetSize(out long size); + Result result = _baseStorage.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 2968d89c8..4e6ee3a49 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 : DisposableIpcService + class IDeviceOperator : IpcService { - private ReferenceCountedDisposable _baseOperator; + private LibHac.FsSrv.IDeviceOperator _baseOperator; - public IDeviceOperator(ReferenceCountedDisposable baseOperator) + public IDeviceOperator(LibHac.FsSrv.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.Target.IsSdCardInserted(out bool isInserted); + Result result = _baseOperator.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.Target.IsGameCardInserted(out bool isInserted); + Result result = _baseOperator.IsGameCardInserted(out bool isInserted); context.ResponseData.Write(isInserted); @@ -38,19 +38,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs // GetGameCardHandle() -> u32 gamecard_handle public ResultCode GetGameCardHandle(ServiceCtx context) { - Result result = _baseOperator.Target.GetGameCardHandle(out GameCardHandle handle); + Result result = _baseOperator.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 b9205e03e..bd07c103a 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -1,40 +1,33 @@ 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 : DisposableIpcService + class IFileSystemProxy : IpcService { - private ReferenceCountedDisposable _baseFileSystemProxy; + private LibHac.FsSrv.IFileSystemProxy _baseFileSystemProxy; public IFileSystemProxy(ServiceCtx context) { - var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient; - _baseFileSystemProxy = applicationClient.Fs.Impl.GetFileSystemProxyServiceObject(); + _baseFileSystemProxy = context.Device.FileSystem.FsServer.CreateFileSystemProxyService(); } [CommandHipc(1)] - // SetCurrentProcess(u64, pid) - public ResultCode SetCurrentProcess(ServiceCtx context) + // Initialize(u64, pid) + public ResultCode Initialize(ServiceCtx context) { return ResultCode.Success; } @@ -101,382 +94,241 @@ namespace Ryujinx.HLE.HOS.Services.Fs { BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); - ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); + Result rc = FileSystemProxyHelper.ReadFsPath(out FsPath path, context); + if (rc.IsFailure()) return (ResultCode)rc.Value; - Result result = _baseFileSystemProxy.Target.OpenBisFileSystem(out ReferenceCountedDisposable fileSystem, in path, bisPartitionId); - if (result.IsFailure()) return (ResultCode)result.Value; + rc = _baseFileSystemProxy.OpenBisFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, ref path, bisPartitionId); + if (rc.IsFailure()) return (ResultCode)rc.Value; MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); return ResultCode.Success; } - [CommandHipc(12)] - // OpenBisStorage(u32 partitionId) -> object bisStorage - public ResultCode OpenBisStorage(ServiceCtx context) - { - BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); - - Result result = _baseFileSystemProxy.Target.OpenBisStorage(out ReferenceCountedDisposable 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 public ResultCode OpenSdCardFileSystem(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.OpenSdCardFileSystem(out var fileSystem); - if (result.IsFailure()) return (ResultCode)result.Value; + Result rc = _baseFileSystemProxy.OpenSdCardFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem); + if (rc.IsFailure()) return (ResultCode)rc.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(); - return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystem(saveDataId).Value; + Result result = _baseFileSystemProxy.DeleteSaveDataFileSystem(saveDataId); + + return (ResultCode)result.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(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct(); - SaveDataMetaInfo metaInfo = context.RequestData.ReadStruct(); + SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct(); - return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo).Value; + // 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); + } + + 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; } [CommandHipc(23)] - // CreateSaveDataFileSystemBySystemSaveDataId(nn::fs::SaveDataAttribute attribute, nn::fs::SaveDataCreationInfo creationInfo) -> () public ResultCode CreateSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) { SaveDataAttribute attribute = context.RequestData.ReadStruct(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct(); - return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in creationInfo).Value; - } + Result result = _baseFileSystemProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref creationInfo); - [CommandHipc(24)] - // RegisterSaveDataFileSystemAtomicDeletion(buffer 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; + return (ResultCode)result.Value; } [CommandHipc(25)] - // DeleteSaveDataFileSystemBySaveDataSpaceId(u8 spaceId, u64 saveDataId) -> () public ResultCode DeleteSaveDataFileSystemBySaveDataSpaceId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); ulong saveDataId = context.RequestData.ReadUInt64(); - return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId).Value; - } + Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId); - [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.Success; + return (ResultCode)result.Value; } [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(); - return (ResultCode)_baseFileSystemProxy.Target.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, in attribute).Value; + Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, ref attribute); + + return (ResultCode)result.Value; } [CommandHipc(30)] - // OpenGameCardStorage(u32 handle, u32 partitionId) -> object + // OpenGameCardStorage(u32, u32) -> object public ResultCode OpenGameCardStorage(ServiceCtx context) { GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32()); GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32(); - Result result = _baseFileSystemProxy.Target.OpenGameCardStorage(out ReferenceCountedDisposable storage, handle, partitionId); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenGameCardStorage(out LibHac.Fs.IStorage storage, handle, partitionId); - MakeObject(context, new FileSystemProxy.IStorage(storage)); + if (result.IsSuccess()) + { + MakeObject(context, new FileSystemProxy.IStorage(storage)); + } - return ResultCode.Success; - } - - [CommandHipc(31)] - // OpenGameCardFileSystem(u32 handle, u32 partitionId) -> object - 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 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)_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; + return (ResultCode)result.Value; } [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(); SaveDataCreationInfo creationInfo = context.RequestData.ReadStruct(); - SaveDataMetaInfo metaCreateInfo = context.RequestData.ReadStruct(); + SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct(); HashSalt hashSalt = context.RequestData.ReadStruct(); - return (ResultCode)_baseFileSystemProxy.Target.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo, in metaCreateInfo, in hashSalt).Value; + // 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; } [CommandHipc(51)] - // OpenSaveDataFileSystem(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object saveDataFs + // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object saveDataFs public ResultCode OpenSaveDataFileSystem(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct(); - Result result = _baseFileSystemProxy.Target.OpenSaveDataFileSystem(out ReferenceCountedDisposable fileSystem, spaceId, in attribute); - if (result.IsFailure()) return (ResultCode)result.Value; + // 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); + } - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); - return ResultCode.Success; + if (result.IsSuccess()) + { + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + } + + return (ResultCode)result.Value; } [CommandHipc(52)] - // OpenSaveDataFileSystemBySystemSaveDataId(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object systemSaveDataFs + // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object systemSaveDataFs public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct(); - Result result = _baseFileSystemProxy.Target.OpenSaveDataFileSystemBySystemSaveDataId(out ReferenceCountedDisposable fileSystem, spaceId, in attribute); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenSaveDataFileSystemBySystemSaveDataId(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; + return (ResultCode)result.Value; } [CommandHipc(53)] - // OpenReadOnlySaveDataFileSystem(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object + // OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataAttribute attribute = context.RequestData.ReadStruct(); - Result result = _baseFileSystemProxy.Target.OpenReadOnlySaveDataFileSystem(out ReferenceCountedDisposable fileSystem, spaceId, in attribute); - if (result.IsFailure()) return (ResultCode)result.Value; + // 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); + } - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); - return ResultCode.Success; - } + if (result.IsSuccess()) + { + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + } - [CommandHipc(57)] - // ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(u8 spaceId, u64 saveDataId) -> (buffer 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); - - 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 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 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; + return (ResultCode)result.Value; } [CommandHipc(60)] - // OpenSaveDataInfoReader() -> object public ResultCode OpenSaveDataInfoReader(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReader(out ReferenceCountedDisposable infoReader); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenSaveDataInfoReader(out ReferenceCountedDisposable infoReader); - MakeObject(context, new ISaveDataInfoReader(infoReader)); + if (result.IsSuccess()) + { + MakeObject(context, new ISaveDataInfoReader(infoReader)); + } - return ResultCode.Success; + return (ResultCode)result.Value; } [CommandHipc(61)] - // OpenSaveDataInfoReaderBySaveDataSpaceId(u8 spaceId) -> object public ResultCode OpenSaveDataInfoReaderBySaveDataSpaceId(ServiceCtx context) { SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadByte(); - Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderBySaveDataSpaceId(out ReferenceCountedDisposable infoReader, spaceId); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(out ReferenceCountedDisposable infoReader, spaceId); - MakeObject(context, new ISaveDataInfoReader(infoReader)); + if (result.IsSuccess()) + { + MakeObject(context, new ISaveDataInfoReader(infoReader)); + } - return ResultCode.Success; + return (ResultCode)result.Value; } [CommandHipc(62)] - // OpenSaveDataInfoReaderOnlyCacheStorage() -> object public ResultCode OpenSaveDataInfoReaderOnlyCacheStorage(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderOnlyCacheStorage(out ReferenceCountedDisposable infoReader); - if (result.IsFailure()) return (ResultCode)result.Value; + SaveDataFilter filter = new SaveDataFilter(); + filter.SetSaveDataType(SaveDataType.Cache); + filter.SetProgramId(new ProgramId(context.Process.TitleId)); - MakeObject(context, new ISaveDataInfoReader(infoReader)); + // 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 infoReader, SaveDataSpaceId.SdCache); - return ResultCode.Success; - } + if (result.IsSuccess()) + { + MakeObject(context, new ISaveDataInfoReader(infoReader)); + } - [CommandHipc(64)] - // OpenSaveDataInternalStorageFileSystem(u8 spaceId, u64 saveDataId) -> object - public ResultCode OpenSaveDataInternalStorageFileSystem(ServiceCtx context) - { - SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); - ulong saveDataId = context.RequestData.ReadUInt64(); - - Result result = _baseFileSystemProxy.Target.OpenSaveDataInternalStorageFileSystem(out ReferenceCountedDisposable 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)_baseFileSystemProxy.Target.WriteSaveDataFileSystemExtraDataWithMask(saveDataId, spaceId, new InBuffer(extraDataBuffer), new InBuffer(maskBuffer)).Value; + return (ResultCode)result.Value; } [CommandHipc(67)] @@ -490,13 +342,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs byte[] infoBuffer = new byte[bufferLen]; - Result result = _baseFileSystemProxy.Target.FindSaveDataWithFilter(out long count, new OutBuffer(infoBuffer), spaceId, in filter); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.FindSaveDataWithFilter(out long count, infoBuffer, spaceId, ref filter); context.Memory.Write(bufferPosition, infoBuffer); context.ResponseData.Write(count); - return ResultCode.Success; + return (ResultCode)result.Value; } [CommandHipc(68)] @@ -505,160 +356,23 @@ namespace Ryujinx.HLE.HOS.Services.Fs SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataFilter filter = context.RequestData.ReadStruct(); - Result result = _baseFileSystemProxy.Target.OpenSaveDataInfoReaderWithFilter(out ReferenceCountedDisposable infoReader, spaceId, in filter); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderWithFilter( + out ReferenceCountedDisposable infoReader, spaceId, ref filter); - MakeObject(context, new ISaveDataInfoReader(infoReader)); + if (result.IsSuccess()) + { + MakeObject(context, new ISaveDataInfoReader(infoReader)); + } - return ResultCode.Success; - } - - [CommandHipc(69)] - public ResultCode ReadSaveDataFileSystemExtraDataBySaveDataAttribute(ServiceCtx context) - { - SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); - SaveDataAttribute attribute = context.RequestData.ReadStruct(); - - 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(); - - 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; + return (ResultCode)result.Value; } [CommandHipc(71)] public ResultCode ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(ServiceCtx context) { - SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); - SaveDataAttribute attribute = context.RequestData.ReadStruct(); + Logger.Stub?.PrintStub(LogClass.ServiceFs); - 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(); - - Result result = _baseFileSystemProxy.Target.OpenSaveDataMetaFile(out ReferenceCountedDisposable 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(); - - 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 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 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 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 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(); - - Result result = _baseFileSystemProxy.Target.OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, customStorageId); - if (result.IsFailure()) return (ResultCode)result.Value; - - MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + MemoryHelper.FillWithZeros(context.Memory, context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size); return ResultCode.Success; } @@ -667,17 +381,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenDataStorageByCurrentProcess() -> object dataStorage public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) { - var storage = context.Device.FileSystem.RomFs.AsStorage(true); - var sharedStorage = new ReferenceCountedDisposable(storage); - ReferenceCountedDisposable sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); + MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); - MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); - - return ResultCode.Success; + return 0; } [CommandHipc(202)] - // OpenDataStorageByDataId(u8 storageId, nn::ncm::DataId dataId) -> object dataStorage + // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object dataStorage public ResultCode OpenDataStorageByDataId(ServiceCtx context) { StorageId storageId = (StorageId)context.RequestData.ReadByte(); @@ -686,15 +396,11 @@ 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(titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel)) + if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel)) { Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}"); - var storage = context.Device.FileSystem.ModLoader.ApplyRomFsMods(titleId, aocStorage); - var sharedStorage = new ReferenceCountedDisposable(storage); - ReferenceCountedDisposable sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); - - MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); + MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.ModLoader.ApplyRomFsMods((ulong)titleId, aocStorage))); return ResultCode.Success; } @@ -726,10 +432,8 @@ 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(romfsStorage); - ReferenceCountedDisposable sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); - MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); + MakeObject(context, new FileSystemProxy.IStorage(romfsStorage)); } catch (HorizonResultException ex) { @@ -756,11 +460,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenPatchDataStorageByCurrentProcess() -> object public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) { - var storage = context.Device.FileSystem.RomFs.AsStorage(true); - var sharedStorage = new ReferenceCountedDisposable(storage); - ReferenceCountedDisposable sfStorage = StorageInterfaceAdapter.CreateShared(ref sharedStorage); - - MakeObject(context, new FileSystemProxy.IStorage(sfStorage)); + MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); return ResultCode.Success; } @@ -769,325 +469,43 @@ namespace Ryujinx.HLE.HOS.Services.Fs // OpenDataStorageByCurrentProcess() -> object dataStorage public ResultCode OpenDeviceOperator(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.OpenDeviceOperator(out ReferenceCountedDisposable deviceOperator); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenDeviceOperator(out LibHac.FsSrv.IDeviceOperator deviceOperator); - MakeObject(context, new IDeviceOperator(deviceOperator)); + if (result.IsSuccess()) + { + 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(); - SimulatingDeviceDetectionMode mode = context.RequestData.ReadStruct(); - - 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(); - - 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(); - AccessKey accessKey = context.RequestData.ReadStruct(); - - 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(); - - 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; - } - - [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(); - - return (ResultCode)_baseFileSystemProxy.Target.UnregisterExternalKey(in rightsId).Value; - } - - [CommandHipc(620)] - public ResultCode SetSdCardEncryptionSeed(ServiceCtx context) - { - EncryptionSeed encryptionSeed = context.RequestData.ReadStruct(); - - return (ResultCode)_baseFileSystemProxy.Target.SetSdCardEncryptionSeed(in encryptionSeed).Value; + return (ResultCode)result.Value; } [CommandHipc(630)] - // SetSdCardAccessibility(u8 isAccessible) + // SetSdCardAccessibility(u8) public ResultCode SetSdCardAccessibility(ServiceCtx context) { bool isAccessible = context.RequestData.ReadBoolean(); - return (ResultCode)_baseFileSystemProxy.Target.SetSdCardAccessibility(isAccessible).Value; + return (ResultCode)_baseFileSystemProxy.SetSdCardAccessibility(isAccessible).Value; } [CommandHipc(631)] - // IsSdCardAccessible() -> u8 isAccessible + // IsSdCardAccessible() -> u8 public ResultCode IsSdCardAccessible(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.IsSdCardAccessible(out bool isAccessible); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.IsSdCardAccessible(out bool isAccessible); context.ResponseData.Write(isAccessible); - return ResultCode.Success; - } - - [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) - { - 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; + return (ResultCode)result.Value; } [CommandHipc(1003)] + // DisableAutoSaveDataCreation() public ResultCode DisableAutoSaveDataCreation(ServiceCtx context) { - return (ResultCode)_baseFileSystemProxy.Target.DisableAutoSaveDataCreation().Value; + // NOTE: This call does nothing in original service. + + return ResultCode.Success; } [CommandHipc(1004)] @@ -1124,39 +542,11 @@ 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 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) { - Result result = _baseFileSystemProxy.Target.GetProgramIndexForAccessLog(out int programIndex, out int programCount); - if (result.IsFailure()) return (ResultCode)result.Value; + int programIndex = 0; + int programCount = 1; context.ResponseData.Write(programIndex); context.ResponseData.Write(programCount); @@ -1164,82 +554,18 @@ namespace Ryujinx.HLE.HOS.Services.Fs return ResultCode.Success; } - [CommandHipc(1012)] - public ResultCode GetFsStackUsage(ServiceCtx context) - { - FsStackUsageThreadType threadType = context.RequestData.ReadStruct(); - - 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(); - - 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 public ResultCode OpenMultiCommitManager(ServiceCtx context) { - Result result = _baseFileSystemProxy.Target.OpenMultiCommitManager(out ReferenceCountedDisposable commitManager); - if (result.IsFailure()) return (ResultCode)result.Value; + Result result = _baseFileSystemProxy.OpenMultiCommitManager(out LibHac.FsSrv.IMultiCommitManager commitManager); - MakeObject(context, new IMultiCommitManager(commitManager)); - - return ResultCode.Success; - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) + if (result.IsSuccess()) { - _baseFileSystemProxy?.Dispose(); + MakeObject(context, new IMultiCommitManager(commitManager)); } + + 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 f8245819f..675f71d20 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 : DisposableIpcService // 6.0.0+ + class IMultiCommitManager : IpcService // 6.0.0+ { - private ReferenceCountedDisposable _baseCommitManager; + private LibHac.FsSrv.IMultiCommitManager _baseCommitManager; - public IMultiCommitManager(ReferenceCountedDisposable baseCommitManager) + public IMultiCommitManager(LibHac.FsSrv.IMultiCommitManager baseCommitManager) { _baseCommitManager = baseCommitManager; } @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs { IFileSystem fileSystem = GetObject(context, 0); - Result result = _baseCommitManager.Target.Add(fileSystem.GetBaseFileSystem()); + Result result = _baseCommitManager.Add(fileSystem.GetBaseFileSystem()); return (ResultCode)result.Value; } @@ -27,17 +27,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs // Commit() public ResultCode Commit(ServiceCtx context) { - Result result = _baseCommitManager.Target.Commit(); + Result result = _baseCommitManager.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 43e9a85a8..bc4a2eb95 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs @@ -1,13 +1,13 @@ -using LibHac; -using LibHac.Sf; +using System; +using LibHac; namespace Ryujinx.HLE.HOS.Services.Fs { class ISaveDataInfoReader : DisposableIpcService { - private ReferenceCountedDisposable _baseReader; + private ReferenceCountedDisposable _baseReader; - public ISaveDataInfoReader(ReferenceCountedDisposable baseReader) + public ISaveDataInfoReader(ReferenceCountedDisposable 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, new OutBuffer(infoBuffer)); + Result result = _baseReader.Target.Read(out long readCount, 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 ee094ddf2..d5331920d 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs @@ -1,5 +1,4 @@ -using LibHac; -using Ryujinx.HLE.HOS.Services.Mii.Types; +using Ryujinx.HLE.HOS.Services.Mii.Types; using System; namespace Ryujinx.HLE.HOS.Services.Mii @@ -148,9 +147,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii return GetDefault(flag, ref count, elements); } - public ResultCode InitializeDatabase(HorizonClient horizonClient) + public ResultCode InitializeDatabase(Switch device) { - _miiDatabase.InitializeDatabase(horizonClient); + _miiDatabase.InitializeDatabase(device); _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 682283b04..0bf15a7f5 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs @@ -1,9 +1,7 @@ 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; @@ -16,6 +14,8 @@ 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 HorizonClient _horizonClient; + private FileSystemClient _filesystemClient; protected ulong UpdateCounter { get; private set; } @@ -94,62 +94,74 @@ namespace Ryujinx.HLE.HOS.Services.Mii return virtualIndex; } - public void InitializeDatabase(HorizonClient horizonClient) + public void InitializeDatabase(Switch device) { - _horizonClient = horizonClient; + _filesystemClient = device.FileSystem.FsClient; // 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() { - if (MountCounter != 0) + Result result = Result.Success; + + if (MountCounter == 0) { - MountCounter++; - return Result.Success; - } - - ulong saveDataId = IsTestModeEnabled ? DatabaseTestSaveDataId : DatabaseSaveDataId; - - Result result = _horizonClient.Fs.MountSystemSaveData(MountName, SaveDataSpaceId.System, saveDataId); - - if (result.IsFailure()) - { - if (!ResultFs.TargetNotFound.Includes(result)) - return result; + ulong targetSaveDataId; + ulong targetTitleId; if (IsTestModeEnabled) { - result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, 0x10000, 0x10000, - SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData); - if (result.IsFailure()) return result; + targetSaveDataId = DatabaseTestSaveDataId; + targetTitleId = SdbTitleId; } else { - result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, SystemProgramId.Ns.Value, 0x10000, - 0x10000, SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData); - if (result.IsFailure()) return result; + targetSaveDataId = DatabaseSaveDataId; + + // Nintendo use NS TitleID when creating the production save even on sdb, let's follow that behaviour. + targetTitleId = NsTitleId; } - result = _horizonClient.Fs.MountSystemSaveData(MountName, SaveDataSpaceId.System, saveDataId); - if (result.IsFailure()) return result; + 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; + } + } + + if (result == Result.Success) + { + MountCounter++; + } } - if (result == Result.Success) - { - MountCounter++; - } return result; } public ResultCode DeleteFile() { - ResultCode result = (ResultCode)_horizonClient.Fs.DeleteFile(DatabasePath).Value; + ResultCode result = (ResultCode)_filesystemClient.DeleteFile(DatabasePath).Value; - _horizonClient.Fs.Commit(MountName); + _filesystemClient.Commit(MountName); return result; } @@ -167,17 +179,17 @@ namespace Ryujinx.HLE.HOS.Services.Mii ResetDatabase(); - Result result = _horizonClient.Fs.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Read); + Result result = _filesystemClient.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Read); if (result.IsSuccess()) { - result = _horizonClient.Fs.GetFileSize(out long fileSize, handle); + result = _filesystemClient.GetFileSize(out long fileSize, handle); if (result.IsSuccess()) { if (fileSize == Unsafe.SizeOf()) { - result = _horizonClient.Fs.ReadFile(handle, 0, _database.AsSpan()); + result = _filesystemClient.ReadFile(handle, 0, _database.AsSpan()); if (result.IsSuccess()) { @@ -199,7 +211,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii } } - _horizonClient.Fs.CloseFile(handle); + _filesystemClient.CloseFile(handle); return (ResultCode)result.Value; } @@ -213,32 +225,32 @@ namespace Ryujinx.HLE.HOS.Services.Mii private Result ForceSaveDatabase() { - Result result = _horizonClient.Fs.CreateFile(DatabasePath, Unsafe.SizeOf()); + Result result = _filesystemClient.CreateFile(DatabasePath, Unsafe.SizeOf()); if (result.IsSuccess() || ResultFs.PathAlreadyExists.Includes(result)) { - result = _horizonClient.Fs.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Write); + result = _filesystemClient.OpenFile(out FileHandle handle, DatabasePath, OpenMode.Write); if (result.IsSuccess()) { - result = _horizonClient.Fs.GetFileSize(out long fileSize, handle); + result = _filesystemClient.GetFileSize(out long fileSize, handle); if (result.IsSuccess()) { // If the size doesn't match, recreate the file if (fileSize != Unsafe.SizeOf()) { - _horizonClient.Fs.CloseFile(handle); + _filesystemClient.CloseFile(handle); - result = _horizonClient.Fs.DeleteFile(DatabasePath); + result = _filesystemClient.DeleteFile(DatabasePath); if (result.IsSuccess()) { - result = _horizonClient.Fs.CreateFile(DatabasePath, Unsafe.SizeOf()); + result = _filesystemClient.CreateFile(DatabasePath, Unsafe.SizeOf()); if (result.IsSuccess()) { - result = _horizonClient.Fs.OpenFile(out handle, DatabasePath, OpenMode.Write); + result = _filesystemClient.OpenFile(out handle, DatabasePath, OpenMode.Write); } } @@ -248,10 +260,10 @@ namespace Ryujinx.HLE.HOS.Services.Mii } } - result = _horizonClient.Fs.WriteFile(handle, 0, _database.AsReadOnlySpan(), WriteOption.Flush); + result = _filesystemClient.WriteFile(handle, 0, _database.AsReadOnlySpan(), WriteOption.Flush); } - _horizonClient.Fs.CloseFile(handle); + _filesystemClient.CloseFile(handle); } } @@ -259,7 +271,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii { _isDirty = false; - result = _horizonClient.Fs.Commit(MountName); + result = _filesystemClient.Commit(MountName); } return result; diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj index 17fbe2c5c..022dc42dc 100644 --- a/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -20,7 +20,7 @@ - + diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index f1444a843..2884f38a3 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -43,7 +43,6 @@ namespace Ryujinx.Headless.SDL2 private static VirtualFileSystem _virtualFileSystem; private static ContentManager _contentManager; private static AccountManager _accountManager; - private static LibHacHorizonManager _libHacHorizonManager; private static UserChannelPersistence _userChannelPersistence; private static InputManager _inputManager; private static Switch _emulationContext; @@ -62,15 +61,8 @@ namespace Ryujinx.Headless.SDL2 AppDataManager.Initialize(null); _virtualFileSystem = VirtualFileSystem.CreateInstance(); - _libHacHorizonManager = new LibHacHorizonManager(); - - _libHacHorizonManager.InitializeFsServer(_virtualFileSystem); - _libHacHorizonManager.InitializeArpServer(); - _libHacHorizonManager.InitializeBcatServer(); - _libHacHorizonManager.InitializeSystemClients(); - _contentManager = new ContentManager(_virtualFileSystem); - _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient); + _accountManager = new AccountManager(_virtualFileSystem); _userChannelPersistence = new UserChannelPersistence(); _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver()); @@ -428,7 +420,6 @@ namespace Ryujinx.Headless.SDL2 private static Switch InitializeEmulationContext(WindowBase window, Options options) { HLEConfiguration configuration = new HLEConfiguration(_virtualFileSystem, - _libHacHorizonManager, _contentManager, _accountManager, _userChannelPersistence, diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 9aa0d6f48..c7d86c7e6 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -52,10 +52,9 @@ namespace Ryujinx.Ui { public class MainWindow : Window { - private readonly VirtualFileSystem _virtualFileSystem; - private readonly ContentManager _contentManager; - private readonly AccountManager _accountManager; - private readonly LibHacHorizonManager _libHacHorizonManager; + private readonly VirtualFileSystem _virtualFileSystem; + private readonly ContentManager _contentManager; + private readonly AccountManager _accountManager; private UserChannelPersistence _userChannelPersistence; @@ -157,27 +156,13 @@ namespace Ryujinx.Ui // Hide emulation context status bar. _statusBar.Hide(); - // Instantiate HLE objects. - _virtualFileSystem = VirtualFileSystem.CreateInstance(); - _libHacHorizonManager = new LibHacHorizonManager(); - - _libHacHorizonManager.InitializeFsServer(_virtualFileSystem); - _libHacHorizonManager.InitializeArpServer(); - _libHacHorizonManager.InitializeBcatServer(); - _libHacHorizonManager.InitializeSystemClients(); - - // Save data created before we supported extra data in directory save data will not work properly if - // given empty extra data. Luckily some of that extra data can be created using the data from the - // save data indexer, which should be enough to check access permissions for user saves. - // Every single save data's extra data will be checked and fixed if needed each time the emulator is opened. - // Consider removing this at some point in the future when we don't need to worry about old saves. - VirtualFileSystem.FixExtraData(_libHacHorizonManager.RyujinxClient); - + // Instanciate HLE objects. + _virtualFileSystem = VirtualFileSystem.CreateInstance(); _contentManager = new ContentManager(_virtualFileSystem); - _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient); + _accountManager = new AccountManager(_virtualFileSystem); _userChannelPersistence = new UserChannelPersistence(); - // Instantiate GUI objects. + // Instanciate GUI objects. _applicationLibrary = new ApplicationLibrary(_virtualFileSystem); _uiHandler = new GtkHostUiHandler(this); _deviceExitStatus = new AutoResetEvent(false); @@ -385,7 +370,7 @@ namespace Ryujinx.Ui private void InitializeSwitchInstance() { - _virtualFileSystem.ReloadKeySet(); + _virtualFileSystem.Reload(); IRenderer renderer; @@ -455,7 +440,6 @@ namespace Ryujinx.Ui IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(_virtualFileSystem, - _libHacHorizonManager, _contentManager, _accountManager, _userChannelPersistence, @@ -1108,7 +1092,7 @@ namespace Ryujinx.Ui BlitStruct controlData = (BlitStruct)_tableStore.GetValue(treeIter, 10); - _ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, _libHacHorizonManager.RyujinxClient, titleFilePath, titleName, titleId, controlData); + _ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, titleFilePath, titleName, titleId, controlData); } private void Load_Application_File(object sender, EventArgs args) @@ -1224,15 +1208,15 @@ namespace Ryujinx.Ui SystemVersion firmwareVersion = _contentManager.VerifyFirmwarePackage(filename); - if (firmwareVersion is null) + string dialogTitle = $"Install Firmware {firmwareVersion.VersionString}"; + + if (firmwareVersion == null) { GtkDialog.CreateErrorDialog($"A valid system firmware was not found in {filename}."); return; } - string dialogTitle = $"Install Firmware {firmwareVersion.VersionString}"; - SystemVersion currentVersion = _contentManager.GetCurrentFirmwareVersion(); string dialogMessage = $"System version {firmwareVersion.VersionString} will be installed."; diff --git a/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs index 4a8d1096f..eb3150cea 100644 --- a/Ryujinx/Ui/Widgets/GameTableContextMenu.cs +++ b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs @@ -33,7 +33,6 @@ namespace Ryujinx.Ui.Widgets private readonly MainWindow _parent; private readonly VirtualFileSystem _virtualFileSystem; private readonly AccountManager _accountManager; - private readonly HorizonClient _horizonClient; private readonly BlitStruct _controlData; private readonly string _titleFilePath; @@ -44,7 +43,7 @@ namespace Ryujinx.Ui.Widgets private MessageDialog _dialog; private bool _cancel; - public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, string titleFilePath, string titleName, string titleId, BlitStruct controlData) + public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, string titleFilePath, string titleName, string titleId, BlitStruct controlData) { _parent = parent; @@ -52,7 +51,6 @@ namespace Ryujinx.Ui.Widgets _virtualFileSystem = virtualFileSystem; _accountManager = accountManager; - _horizonClient = horizonClient; _titleFilePath = titleFilePath; _titleName = titleName; _titleIdText = titleId; @@ -65,9 +63,9 @@ namespace Ryujinx.Ui.Widgets return; } - _openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0; - _openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0; - _openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0; + _openSaveUserDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0; + _openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0; + _openSaveBcatDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0; string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower(); bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci"; @@ -83,7 +81,7 @@ namespace Ryujinx.Ui.Widgets { saveDataId = default; - Result result = _horizonClient.Fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, in filter); + Result result = _virtualFileSystem.FsClient.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter); if (ResultFs.TargetNotFound.Includes(result)) { @@ -104,7 +102,7 @@ namespace Ryujinx.Ui.Widgets ref ApplicationControlProperty control = ref controlHolder.Value; - if (Utilities.IsZeros(controlHolder.ByteSpan)) + if (Utilities.IsEmpty(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. @@ -119,7 +117,7 @@ namespace Ryujinx.Ui.Widgets Uid user = new Uid((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low); - result = EnsureApplicationSaveData(_horizonClient.Fs, out _, new LibHac.Ncm.ApplicationId(titleId), ref control, ref user); + result = EnsureApplicationSaveData(_virtualFileSystem.FsClient, out _, new LibHac.Ncm.ApplicationId(titleId), ref control, ref user); if (result.IsFailure()) { @@ -129,7 +127,7 @@ namespace Ryujinx.Ui.Widgets } // Try to find the savedata again after creating it - result = _horizonClient.Fs.FindSaveDataWithFilter(out saveDataInfo, SaveDataSpaceId.User, in filter); + result = _virtualFileSystem.FsClient.FindSaveDataWithFilter(out saveDataInfo, SaveDataSpaceId.User, ref filter); } if (result.IsSuccess()) @@ -286,7 +284,7 @@ namespace Ryujinx.Ui.Widgets IFileSystem ncaFileSystem = patchNca != null ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid) : mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid); - FileSystemClient fsClient = _horizonClient.Fs; + FileSystemClient fsClient = _virtualFileSystem.FsClient; string source = DateTime.Now.ToFileTime().ToString()[10..]; string output = DateTime.Now.ToFileTime().ToString()[10..]; @@ -411,7 +409,7 @@ namespace Ryujinx.Ui.Widgets rc = fs.ReadFile(out long _, sourceHandle, offset, buf); if (rc.IsFailure()) return rc; - rc = fs.WriteFile(destHandle, offset, buf, WriteOption.None); + rc = fs.WriteFile(destHandle, offset, buf); if (rc.IsFailure()) return rc; } }