From d773d5152e685a164a6eb9f419873ef1908364f7 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 22 Oct 2023 16:30:46 -0700 Subject: [PATCH] Update to LibHac 0.19.0 (#5831) * Update to LibHac v0.19.0 - PartitionFileSystem classes now fully match Nintendo's implementation. Current code creating a PartitionFileSystem now need to use the Initialize method. - Implementing nn::gcsrv and nn::sdmmcsrv now means the FS server now uses that abstraction instead of the old one where we passed in an IDeviceOperator. * Add GetFileSystemAttribute --- Directory.Packages.props | 2 +- src/Ryujinx.Ava/Common/ApplicationHelper.cs | 6 ++++-- .../DownloadableContentManagerViewModel.cs | 6 ++++-- .../UI/ViewModels/TitleUpdateViewModel.cs | 4 +++- src/Ryujinx.HLE/FileSystem/ContentManager.cs | 11 ++++++----- .../FileSystem/VirtualFileSystem.cs | 9 +++++---- src/Ryujinx.HLE/HOS/ModLoader.cs | 4 +++- .../FileSystemProxy/FileSystemProxyHelper.cs | 7 +++++-- .../Fs/FileSystemProxy/IFileSystem.cs | 11 +++++++++++ .../HOS/Services/Fs/IFileSystemProxy.cs | 5 ++++- .../PartitionFileSystemExtensions.cs | 9 +++++++-- .../Loaders/Processes/ProcessLoader.cs | 3 ++- .../Loaders/Processes/ProcessLoaderHelper.cs | 4 ++-- src/Ryujinx.Ui.Common/App/ApplicationData.cs | 6 ++++-- .../App/ApplicationLibrary.cs | 19 ++++++++++++------- .../Ui/Widgets/GameTableContextMenu.cs | 6 ++++-- src/Ryujinx/Ui/Windows/DlcWindow.cs | 6 ++++-- src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs | 3 ++- 18 files changed, 83 insertions(+), 38 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 6fdaafdd..4fd079af 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,7 +18,7 @@ - + diff --git a/src/Ryujinx.Ava/Common/ApplicationHelper.cs b/src/Ryujinx.Ava/Common/ApplicationHelper.cs index b8cd06f3..91ca8f4d 100644 --- a/src/Ryujinx.Ava/Common/ApplicationHelper.cs +++ b/src/Ryujinx.Ava/Common/ApplicationHelper.cs @@ -173,7 +173,7 @@ namespace Ryujinx.Ava.Common string extension = Path.GetExtension(titleFilePath).ToLower(); if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci") { - PartitionFileSystem pfs; + IFileSystem pfs; if (extension == ".xci") { @@ -181,7 +181,9 @@ namespace Ryujinx.Ava.Common } else { - pfs = new PartitionFileSystem(file.AsStorage()); + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; } foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs index b88bd3d9..cdecae77 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -126,7 +126,8 @@ namespace Ryujinx.Ava.UI.ViewModels { using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath); - PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); + PartitionFileSystem partitionFileSystem = new(); + partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); _virtualFileSystem.ImportTickets(partitionFileSystem); @@ -232,7 +233,8 @@ namespace Ryujinx.Ava.UI.ViewModels using FileStream containerFile = File.OpenRead(path); - PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); + PartitionFileSystem partitionFileSystem = new(); + partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); bool containsDownloadableContent = false; _virtualFileSystem.ImportTickets(partitionFileSystem); diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs index dd0b92a5..5090a8c7 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs @@ -170,7 +170,9 @@ namespace Ryujinx.Ava.UI.ViewModels try { - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0); + var pfs = new PartitionFileSystem(); + pfs.Initialize(file.AsStorage()).ThrowIfFailure(); + (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0); if (controlNca != null && patchNca != null) { diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index 646808e7..8ade34a8 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -238,7 +238,8 @@ namespace Ryujinx.HLE.FileSystem if (!mergedToContainer) { using FileStream fileStream = File.OpenRead(containerPath); - using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage()); + using PartitionFileSystem partitionFileSystem = new(); + partitionFileSystem.Initialize(fileStream.AsStorage()).ThrowIfFailure(); _virtualFileSystem.ImportTickets(partitionFileSystem); } @@ -259,16 +260,16 @@ namespace Ryujinx.HLE.FileSystem { var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read); using var ncaFile = new UniqueRef(); - PartitionFileSystem pfs; switch (Path.GetExtension(aoc.ContainerPath)) { case ".xci": - pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); - pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read); + var xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); + xci.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read); break; case ".nsp": - pfs = new PartitionFileSystem(file.AsStorage()); + var pfs = new PartitionFileSystem(); + pfs.Initialize(file.AsStorage()); pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read); break; default: diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 807020c6..eaf481dd 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -7,6 +7,7 @@ using LibHac.Fs.Shim; using LibHac.FsSrv; using LibHac.FsSystem; using LibHac.Ncm; +using LibHac.Sdmmc; using LibHac.Spl; using LibHac.Tools.Es; using LibHac.Tools.Fs; @@ -32,7 +33,7 @@ namespace Ryujinx.HLE.FileSystem public KeySet KeySet { get; private set; } public EmulatedGameCard GameCard { get; private set; } - public EmulatedSdCard SdCard { get; private set; } + public SdmmcApi SdCard { get; private set; } public ModLoader ModLoader { get; private set; } private readonly ConcurrentDictionary _romFsByPid; @@ -198,15 +199,15 @@ namespace Ryujinx.HLE.FileSystem fsServerObjects.FsCreators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(); GameCard = fsServerObjects.GameCard; - SdCard = fsServerObjects.SdCard; + SdCard = fsServerObjects.Sdmmc; - SdCard.SetSdCardInsertionStatus(true); + SdCard.SetSdCardInserted(true); var fsServerConfig = new FileSystemServerConfig { - DeviceOperator = fsServerObjects.DeviceOperator, ExternalKeySet = KeySet.ExternalKeySet, FsCreators = fsServerObjects.FsCreators, + StorageDeviceManagerFactory = fsServerObjects.StorageDeviceManagerFactory, RandomGenerator = randomGenerator, }; diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index 6706006c..834bc059 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -533,7 +533,9 @@ namespace Ryujinx.HLE.HOS Logger.Info?.Print(LogClass.ModLoader, "Using replacement ExeFS partition"); - exefs = new PartitionFileSystem(mods.ExefsContainers[0].Path.OpenRead().AsStorage()); + var pfs = new PartitionFileSystem(); + pfs.Initialize(mods.ExefsContainers[0].Path.OpenRead().AsStorage()).ThrowIfFailure(); + exefs = pfs; return true; } diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs index 599025e3..1ef52a00 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs @@ -26,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy try { LocalStorage storage = new(pfsPath, FileAccess.Read, FileMode.Open); - using SharedRef nsp = new(new PartitionFileSystem(storage)); + var pfs = new PartitionFileSystem(); + using SharedRef nsp = new(pfs); + pfs.Initialize(storage).ThrowIfFailure(); ImportTitleKeysFromNsp(nsp.Get, context.Device.System.KeySet); @@ -90,7 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy try { - PartitionFileSystem nsp = new(pfsFile.AsStorage()); + PartitionFileSystem nsp = new(); + nsp.Initialize(pfsFile.AsStorage()).ThrowIfFailure(); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs index 4c5c5624..66020d57 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -1,6 +1,7 @@ using LibHac; using LibHac.Common; using LibHac.Fs; +using LibHac.Fs.Fsa; using Path = LibHac.FsSrv.Sf.Path; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy @@ -202,6 +203,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy return (ResultCode)result.Value; } + [CommandCmif(16)] + public ResultCode GetFileSystemAttribute(ServiceCtx context) + { + Result result = _fileSystem.Get.GetFileSystemAttribute(out FileSystemAttribute attribute); + + context.ResponseData.Write(SpanHelpers.AsReadOnlyByteSpan(in attribute)); + + return (ResultCode)result.Value; + } + protected override void Dispose(bool isDisposing) { if (isDisposing) diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index 644e1a17..24dd1e9b 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -1380,7 +1380,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs [CommandCmif(1016)] public ResultCode FlushAccessLogOnSdCard(ServiceCtx context) { - return (ResultCode)_baseFileSystemProxy.Get.FlushAccessLogOnSdCard().Value; + // Logging the access log to the SD card isn't implemented, meaning this function will be a no-op since + // there's nothing to flush. Return success until it's implemented. + // return (ResultCode)_baseFileSystemProxy.Get.FlushAccessLogOnSdCard().Value; + return ResultCode.Success; } [CommandCmif(1017)] diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs index 6de99131..50f7d585 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs @@ -20,7 +20,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions private static readonly DownloadableContentJsonSerializerContext _contentSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - internal static (bool, ProcessResult) TryLoad(this PartitionFileSystem partitionFileSystem, Switch device, string path, out string errorMessage) + internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, string path, out string errorMessage) + where TMetaData : PartitionFileSystemMetaCore, new() + where TFormat : IPartitionFileSystemFormat + where THeader : unmanaged, IPartitionFileSystemHeader + where TEntry : unmanaged, IPartitionFileSystemEntry { errorMessage = null; @@ -91,7 +95,8 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions string updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected; if (File.Exists(updatePath)) { - PartitionFileSystem updatePartitionFileSystem = new(new FileStream(updatePath, FileMode.Open, FileAccess.Read).AsStorage()); + PartitionFileSystem updatePartitionFileSystem = new(); + updatePartitionFileSystem.Initialize(new FileStream(updatePath, FileMode.Open, FileAccess.Read).AsStorage()).ThrowIfFailure(); device.Configuration.VirtualFileSystem.ImportTickets(updatePartitionFileSystem); diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index 51cbb6f9..220b868d 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -69,7 +69,8 @@ namespace Ryujinx.HLE.Loaders.Processes public bool LoadNsp(string path) { FileStream file = new(path, FileMode.Open, FileAccess.Read); - PartitionFileSystem partitionFileSystem = new(file.AsStorage()); + PartitionFileSystem partitionFileSystem = new(); + partitionFileSystem.Initialize(file.AsStorage()).ThrowIfFailure(); (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, out string errorMessage); diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs index 292a5c12..c229b174 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs @@ -1,8 +1,8 @@ using LibHac.Account; using LibHac.Common; using LibHac.Fs; +using LibHac.Fs.Fsa; using LibHac.Fs.Shim; -using LibHac.FsSystem; using LibHac.Loader; using LibHac.Ncm; using LibHac.Ns; @@ -33,7 +33,7 @@ namespace Ryujinx.HLE.Loaders.Processes // TODO: Remove this workaround when ASLR is implemented. private const ulong CodeStartOffset = 0x500000UL; - public static LibHac.Result RegisterProgramMapInfo(Switch device, PartitionFileSystem partitionFileSystem) + public static LibHac.Result RegisterProgramMapInfo(Switch device, IFileSystem partitionFileSystem) { ulong applicationId = 0; int programCount = 0; diff --git a/src/Ryujinx.Ui.Common/App/ApplicationData.cs b/src/Ryujinx.Ui.Common/App/ApplicationData.cs index e6130bda..1be883ee 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationData.cs +++ b/src/Ryujinx.Ui.Common/App/ApplicationData.cs @@ -65,7 +65,7 @@ namespace Ryujinx.Ui.App.Common if (extension is ".nsp" or ".xci") { - PartitionFileSystem pfs; + IFileSystem pfs; if (extension == ".xci") { @@ -75,7 +75,9 @@ namespace Ryujinx.Ui.App.Common } else { - pfs = new PartitionFileSystem(file.AsStorage()); + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; } foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) diff --git a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs index 36b2b727..2f688126 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs @@ -174,7 +174,7 @@ namespace Ryujinx.Ui.App.Common { try { - PartitionFileSystem pfs; + IFileSystem pfs; bool isExeFs = false; @@ -186,7 +186,9 @@ namespace Ryujinx.Ui.App.Common } else { - pfs = new PartitionFileSystem(file.AsStorage()); + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application. bool hasMainNca = false; @@ -500,7 +502,7 @@ namespace Ryujinx.Ui.App.Common ApplicationCountUpdated?.Invoke(null, e); } - private void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem controlFs, out string titleId) + private void GetControlFsAndTitleId(IFileSystem pfs, out IFileSystem controlFs, out string titleId) { (_, _, Nca controlNca) = GetGameData(_virtualFileSystem, pfs, 0); @@ -563,7 +565,7 @@ namespace Ryujinx.Ui.App.Common { try { - PartitionFileSystem pfs; + IFileSystem pfs; bool isExeFs = false; @@ -575,7 +577,9 @@ namespace Ryujinx.Ui.App.Common } else { - pfs = new PartitionFileSystem(file.AsStorage()); + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) { @@ -827,7 +831,7 @@ namespace Ryujinx.Ui.App.Common return false; } - public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex) + public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, IFileSystem pfs, int programIndex) { Nca mainNca = null; Nca patchNca = null; @@ -931,7 +935,8 @@ namespace Ryujinx.Ui.App.Common if (File.Exists(updatePath)) { FileStream file = new(updatePath, FileMode.Open, FileAccess.Read); - PartitionFileSystem nsp = new(file.AsStorage()); + PartitionFileSystem nsp = new(); + nsp.Initialize(file.AsStorage()).ThrowIfFailure(); return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex); } diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs index ea60421f..5af181b0 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs +++ b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs @@ -211,7 +211,7 @@ namespace Ryujinx.Ui.Widgets (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") || (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci")) { - PartitionFileSystem pfs; + IFileSystem pfs; if (System.IO.Path.GetExtension(_titleFilePath) == ".xci") { @@ -221,7 +221,9 @@ namespace Ryujinx.Ui.Widgets } else { - pfs = new PartitionFileSystem(file.AsStorage()); + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; } foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.cs b/src/Ryujinx/Ui/Windows/DlcWindow.cs index 74aef00f..9f717946 100644 --- a/src/Ryujinx/Ui/Windows/DlcWindow.cs +++ b/src/Ryujinx/Ui/Windows/DlcWindow.cs @@ -88,7 +88,8 @@ namespace Ryujinx.Ui.Windows using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath); - PartitionFileSystem pfs = new(containerFile.AsStorage()); + PartitionFileSystem pfs = new(); + pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure(); _virtualFileSystem.ImportTickets(pfs); @@ -153,7 +154,8 @@ namespace Ryujinx.Ui.Windows using FileStream containerFile = File.OpenRead(containerPath); - PartitionFileSystem pfs = new(containerFile.AsStorage()); + PartitionFileSystem pfs = new(); + pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure(); bool containsDlc = false; _virtualFileSystem.ImportTickets(pfs); diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs b/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs index 044f7e95..51918eea 100644 --- a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs +++ b/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs @@ -90,7 +90,8 @@ namespace Ryujinx.Ui.Windows { using FileStream file = new(path, FileMode.Open, FileAccess.Read); - PartitionFileSystem nsp = new(file.AsStorage()); + PartitionFileSystem nsp = new(); + nsp.Initialize(file.AsStorage()).ThrowIfFailure(); try {