diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index deaa03def1..34a14b632d 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -44,7 +44,7 @@ namespace Ryujinx.Common.Configuration static AppDataManager() { - KeysDirPathUser = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch"); + KeysDirPathUser = FileSystemUtils.ResolveFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch"), true); } public static void Initialize(string baseDirPath) @@ -56,23 +56,23 @@ namespace Ryujinx.Common.Configuration appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); } - string userProfilePath = Path.Combine(appDataPath, DefaultBaseDir); - string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir); + string userProfilePath = FileSystemUtils.ResolveFullPath(Path.Combine(appDataPath, DefaultBaseDir), true); + DirectoryInfo portableInfo = FileSystemUtils.GetActualDirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir)); // On macOS, check for a portable directory next to the app bundle as well. - if (OperatingSystem.IsMacOS() && !Directory.Exists(portablePath)) + if (OperatingSystem.IsMacOS() && !portableInfo.Exists) { string bundlePath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..")); // Make sure we're actually running within an app bundle. if (bundlePath.EndsWith(".app")) { - portablePath = Path.GetFullPath(Path.Combine(bundlePath, "..", DefaultPortableDir)); + portableInfo = FileSystemUtils.GetActualDirectoryInfo(Path.Combine(bundlePath, "..", DefaultPortableDir)); } } - if (Directory.Exists(portablePath)) + if (portableInfo.Exists) { - BaseDirPath = portablePath; + BaseDirPath = portableInfo.FullName; Mode = LaunchMode.Portable; } else @@ -83,24 +83,19 @@ namespace Ryujinx.Common.Configuration if (baseDirPath != null && baseDirPath != userProfilePath) { - if (!Directory.Exists(baseDirPath)) + DirectoryInfo baseDirInfo = FileSystemUtils.GetActualDirectoryInfo(baseDirPath); + + if (!baseDirInfo.Exists) { Logger.Error?.Print(LogClass.Application, $"Custom Data Directory '{baseDirPath}' does not exist. Falling back to {Mode}..."); } else { - BaseDirPath = baseDirPath; + BaseDirPath = baseDirInfo.FullName; Mode = LaunchMode.Custom; } } - BaseDirPath = Path.GetFullPath(BaseDirPath); // convert relative paths - - if (IsPathSymlink(BaseDirPath)) - { - Logger.Warning?.Print(LogClass.Application, $"Application data directory is a symlink. This may be unintended."); - } - SetupBasePaths(); } @@ -217,16 +212,16 @@ namespace Ryujinx.Common.Configuration } } - return logDir; + return FileSystemUtils.ResolveFullPath(logDir, true); } private static void SetupBasePaths() { Directory.CreateDirectory(BaseDirPath); LogsDirPath = SetUpLogsDir(); - Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir)); - Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir)); - Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir)); + Directory.CreateDirectory(GamesDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, GamesDir), true)); + Directory.CreateDirectory(ProfilesDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, ProfilesDir), true)); + Directory.CreateDirectory(KeysDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, KeysDir), true)); } // Check if existing old baseDirPath is a symlink, to prevent possible errors. @@ -320,7 +315,7 @@ namespace Ryujinx.Common.Configuration } } - public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName; - public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere")).FullName; + public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, DefaultModsDir), true)).FullName; + public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere"), true)).FullName; } } diff --git a/src/Ryujinx.Gtk3/UI/MainWindow.cs b/src/Ryujinx.Gtk3/UI/MainWindow.cs index cba2d239fa..8aa5fef7a3 100644 --- a/src/Ryujinx.Gtk3/UI/MainWindow.cs +++ b/src/Ryujinx.Gtk3/UI/MainWindow.cs @@ -15,6 +15,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; +using Ryujinx.Common.Utilities; using Ryujinx.Cpu; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL.Multithreading; @@ -920,7 +921,7 @@ namespace Ryujinx.UI if (application.Path.StartsWith("@SystemContent")) { - application.Path = VirtualFileSystem.SwitchPathToSystemPath(application.Path); + application.Path = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(application.Path), false); isFirmwareTitle = true; } diff --git a/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs index d9ecd47b76..7af87a7114 100644 --- a/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs @@ -7,6 +7,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.UI.Common.Configuration; using SixLabors.ImageSharp; @@ -119,10 +120,10 @@ namespace Ryujinx.UI.Windows } string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); - string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath); - if (!string.IsNullOrWhiteSpace(avatarPath)) + if (!string.IsNullOrWhiteSpace(contentPath)) { + string avatarPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(contentPath), false); using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open); Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index e6c0fce081..1cb08c4050 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -349,18 +349,15 @@ namespace Ryujinx.HLE.FileSystem return false; } - string installedPath = VirtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath); + FileInfo installedInfo = FileSystemUtils.GetActualFileInfo(VirtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath)); - if (!string.IsNullOrWhiteSpace(installedPath)) + if (installedInfo.Exists) { - if (File.Exists(installedPath)) - { - using FileStream file = new(installedPath, FileMode.Open, FileAccess.Read); - Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage()); - bool contentCheck = nca.Header.ContentType == contentType; + using FileStream file = new(installedInfo.FullName, FileMode.Open, FileAccess.Read); + Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage()); + bool contentCheck = nca.Header.ContentType == contentType; - return contentCheck; - } + return contentCheck; } return false; @@ -941,9 +938,9 @@ namespace Ryujinx.HLE.FileSystem { if (entry.ContentType == NcaContentType.Data) { - var path = VirtualFileSystem.SwitchPathToSystemPath(entry.ContentPath); + var fileInfo = FileSystemUtils.GetActualFileInfo(VirtualFileSystem.SwitchPathToSystemPath(entry.ContentPath)); - using FileStream fileStream = File.OpenRead(path); + using FileStream fileStream = fileInfo.OpenRead(); Nca nca = new(_virtualFileSystem.KeySet, fileStream.AsStorage()); if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index d98ba182f7..ecdd6ea83e 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -14,6 +14,7 @@ using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS; using System; using System.Buffers.Text; @@ -22,14 +23,15 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using Path = System.IO.Path; +using SpanHelpers = LibHac.Common.SpanHelpers; namespace Ryujinx.HLE.FileSystem { public class VirtualFileSystem : IDisposable { - public static readonly string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe"); - public static readonly string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system"); - public static readonly string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user"); + public static readonly string SafeNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "safe"), true); + public static readonly string SystemNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "system"), true); + public static readonly string UserNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "user"), true); public KeySet KeySet { get; private set; } public EmulatedGameCard GameCard { get; private set; } @@ -61,7 +63,9 @@ namespace Ryujinx.HLE.FileSystem public void LoadRomFs(ulong pid, string fileName) { - var romfsStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); + FileInfo fileInfo = FileSystemUtils.GetActualFileInfo(fileName); + + var romfsStream = fileInfo.Open(FileMode.Open, FileAccess.Read); _romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) => { @@ -111,8 +115,8 @@ namespace Ryujinx.HLE.FileSystem return fullPath; } - internal static string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir); - public static string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir); + internal static string GetSdCardPath() => FileSystemUtils.ResolveFullPath(MakeFullPath(AppDataManager.DefaultSdcardDir), true); + public static string GetNandPath() => FileSystemUtils.ResolveFullPath(MakeFullPath(AppDataManager.DefaultNandDir), true); public static string SwitchPathToSystemPath(string switchPath) { @@ -236,23 +240,23 @@ namespace Ryujinx.HLE.FileSystem void LoadSetAtPath(string basePath) { - string localKeyFile = Path.Combine(basePath, "prod.keys"); - string localTitleKeyFile = Path.Combine(basePath, "title.keys"); - string localConsoleKeyFile = Path.Combine(basePath, "console.keys"); + FileInfo localKeyFile = FileSystemUtils.GetActualFileInfo(Path.Combine(basePath, "prod.keys")); + FileInfo localTitleKeyFile = FileSystemUtils.GetActualFileInfo(Path.Combine(basePath, "title.keys")); + FileInfo localConsoleKeyFile = FileSystemUtils.GetActualFileInfo(Path.Combine(basePath, "console.keys")); - if (File.Exists(localKeyFile)) + if (localKeyFile.Exists) { - keyFile = localKeyFile; + keyFile = localKeyFile.FullName; } - if (File.Exists(localTitleKeyFile)) + if (localTitleKeyFile.Exists) { - titleKeyFile = localTitleKeyFile; + titleKeyFile = localTitleKeyFile.FullName; } - if (File.Exists(localConsoleKeyFile)) + if (localConsoleKeyFile.Exists) { - consoleKeyFile = localConsoleKeyFile; + consoleKeyFile = localConsoleKeyFile.FullName; } } diff --git a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index 7ee9b9e907..eeec1c0fc4 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -6,6 +6,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.SystemState; using System; @@ -107,14 +108,20 @@ namespace Ryujinx.HLE.HOS.Applets.Error private static string CleanText(string value) { - return CleanTextRegex().Replace(value, "").Replace("\0", ""); + return CleanTextRegex().Replace(value, string.Empty).Replace("\0", string.Empty); } private string GetMessageText(uint module, uint description, string key) { string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data); - using LibHac.Fs.IStorage ncaFileStream = new LocalStorage(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open); + if (string.IsNullOrWhiteSpace(binaryTitleContentPath)) + { + return string.Empty; + } + + string binaryTitleFullPath = FileSystemUtils.ResolveFullPath(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(binaryTitleContentPath), false); + using LibHac.Fs.IStorage ncaFileStream = new LocalStorage(binaryTitleFullPath, FileAccess.Read, FileMode.Open); Nca nca = new(_horizon.Device.FileSystem.KeySet, ncaFileStream); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel); string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage); @@ -131,7 +138,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error } else { - return ""; + return string.Empty; } } @@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error { string buttonsText = GetMessageText(module, description, key); - return (buttonsText == "") ? null : buttonsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + return (buttonsText == string.Empty) ? null : buttonsText.Split(["\r\n", "\r", "\n"], StringSplitOptions.None); } private void ParseErrorCommonArg() @@ -156,7 +163,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error string message = GetMessageText(module, description, "DlgMsg"); - if (message == "") + if (message == string.Empty) { message = "An error has occured.\n\n" + "Please try again later.\n\n" @@ -193,7 +200,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error // TODO: Handle the LanguageCode to return the translated "OK" and "Details". - if (detailsText.Trim() != "") + if (detailsText.Trim() != string.Empty) { buttons.Add("Details"); } diff --git a/src/Ryujinx.HLE/HOS/HorizonFsClient.cs b/src/Ryujinx.HLE/HOS/HorizonFsClient.cs index 3dbafa88b1..353baa747c 100644 --- a/src/Ryujinx.HLE/HOS/HorizonFsClient.cs +++ b/src/Ryujinx.HLE/HOS/HorizonFsClient.cs @@ -3,6 +3,7 @@ using LibHac.Fs.Fsa; using LibHac.FsSystem; using LibHac.Ncm; using LibHac.Tools.FsSystem.NcaUtils; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.Horizon; using Ryujinx.Horizon.Common; @@ -39,19 +40,18 @@ namespace Ryujinx.HLE.HOS public Result MountSystemData(string mountName, ulong dataId) { string contentPath = _system.ContentManager.GetInstalledContentPath(dataId, StorageId.BuiltInSystem, NcaContentType.PublicData); - string installPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath); - if (!string.IsNullOrWhiteSpace(installPath)) + if (!string.IsNullOrWhiteSpace(contentPath)) { - string ncaPath = installPath; + FileInfo ncaInfo = FileSystemUtils.GetActualFileInfo(VirtualFileSystem.SwitchPathToSystemPath(contentPath)); - if (File.Exists(ncaPath)) + if (ncaInfo.Exists) { LocalStorage ncaStorage = null; try { - ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); + ncaStorage = new LocalStorage(ncaInfo.FullName, FileAccess.Read, FileMode.Open); Nca nca = new(_system.KeySet, ncaStorage); diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 9a7fdcc16d..cf96b0705a 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -5,6 +5,7 @@ using LibHac.Ns; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Memory; @@ -654,14 +655,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati { if (Interlocked.Exchange(ref _jitLoaded, 1) == 0) { - string jitPath = context.Device.System.ContentManager.GetInstalledContentPath(0x010000000000003B, StorageId.BuiltInSystem, NcaContentType.Program); - string filePath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(jitPath); + const ulong JitApplicationId = 0x010000000000003B; + string jitPath = context.Device.System.ContentManager.GetInstalledContentPath(JitApplicationId, StorageId.BuiltInSystem, NcaContentType.Program); - if (string.IsNullOrWhiteSpace(filePath)) + if (string.IsNullOrWhiteSpace(jitPath)) { - throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)"); + throw new InvalidSystemResourceException($"JIT ({JitApplicationId:X16}) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)"); } + string filePath = FileSystemUtils.ResolveFullPath(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(jitPath), false); + context.Device.LoadNca(filePath); // FIXME: Most likely not how this should be done? diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index 24dd1e9be8..a131c36688 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using System; using System.IO; @@ -18,6 +19,7 @@ using static Ryujinx.HLE.Utilities.StringUtils; using GameCardHandle = System.UInt32; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IStorage = LibHac.FsSrv.Sf.IStorage; +using SpanHelpers = LibHac.Common.SpanHelpers; namespace Ryujinx.HLE.HOS.Services.Fs { @@ -52,13 +54,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs ulong titleId = context.RequestData.ReadUInt64(); #pragma warning restore IDE0059 string switchPath = ReadUtf8String(context); - string fullPath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(switchPath); + FileInfo realPathInfo = FileSystemUtils.GetActualFileInfo(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(switchPath)); - if (!File.Exists(fullPath)) + if (!realPathInfo.Exists) { - if (fullPath.Contains('.')) + if (realPathInfo.FullName.Contains('.')) { - ResultCode result = FileSystemProxyHelper.OpenFileSystemFromInternalFile(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); + ResultCode result = FileSystemProxyHelper.OpenFileSystemFromInternalFile(context, realPathInfo.FullName, out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { @@ -71,12 +73,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs return ResultCode.PathDoesNotExist; } - FileStream fileStream = new(fullPath, FileMode.Open, FileAccess.Read); - string extension = System.IO.Path.GetExtension(fullPath); + FileStream fileStream = realPathInfo.Open(FileMode.Open, FileAccess.Read); + string extension = realPathInfo.Extension.ToLower(); if (extension == ".nca") { - ResultCode result = FileSystemProxyHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem); + ResultCode result = FileSystemProxyHelper.OpenNcaFs(context, realPathInfo.FullName, fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { @@ -87,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs } else if (extension == ".nsp") { - ResultCode result = FileSystemProxyHelper.OpenNsp(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); + ResultCode result = FileSystemProxyHelper.OpenNsp(context, realPathInfo.FullName, out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { @@ -832,17 +834,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs if (installedStorage != StorageId.None) { string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, contentType); - string installPath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(contentPath); - if (!string.IsNullOrWhiteSpace(installPath)) + if (!string.IsNullOrWhiteSpace(contentPath)) { - string ncaPath = installPath; + FileInfo ncaInfo = FileSystemUtils.GetActualFileInfo(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(contentPath)); - if (File.Exists(ncaPath)) + if (ncaInfo.Exists) { try { - LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); + LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaInfo.FullName, FileAccess.Read, FileMode.Open); Nca nca = new(context.Device.System.KeySet, ncaStorage); LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); using var sharedStorage = new SharedRef(romfsStorage); @@ -859,12 +860,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs } else { - throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`."); + throw new FileNotFoundException($"No Nca found at path `{ncaInfo.FullName}`."); } } else { - throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}."); + throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found at path {contentPath}."); } } diff --git a/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs b/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs index 641795890f..57b3d65ed5 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs @@ -6,6 +6,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel.Memory; @@ -65,10 +66,10 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename)) { string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.BuiltInSystem, NcaContentType.Data); - string fontPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath); - if (!string.IsNullOrWhiteSpace(fontPath)) + if (!string.IsNullOrWhiteSpace(contentPath)) { + string fontPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(contentPath), false); byte[] data; using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open)) diff --git a/src/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs b/src/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs index 65748be332..29db67d858 100644 --- a/src/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs @@ -7,6 +7,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.SystemState; using System; using System.IO; @@ -305,7 +306,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings return null; } - string firmwareTitlePath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(contentPath); + string firmwareTitlePath = FileSystemUtils.ResolveFullPath(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(contentPath), false); using IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read); Nca firmwareContent = new(device.System.KeySet, firmwareStorage); diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Proxy/DnsMitmResolver.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Proxy/DnsMitmResolver.cs index d17a999dc9..d7995c779f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Proxy/DnsMitmResolver.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Proxy/DnsMitmResolver.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Services.Sockets.Nsd; using System; using System.Collections.Generic; @@ -21,12 +22,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy { string sdPath = FileSystem.VirtualFileSystem.GetSdCardPath(); string filePath = FileSystem.VirtualFileSystem.GetFullPath(sdPath, HostsFilePath); + FileInfo fileInfo = new FileInfo(filePath).GetActualFileInfo(); _mitmHostEntries.Clear(); - if (File.Exists(filePath)) + if (fileInfo.Exists) { - using FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read); + using FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read); using StreamReader reader = new(fileStream); while (!reader.EndOfStream) @@ -92,9 +94,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy return new IPHostEntry { - AddressList = new[] { hostEntry.Value }, + AddressList = [hostEntry.Value], HostName = hostEntry.Key, - Aliases = Array.Empty(), + Aliases = [], }; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs b/src/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs index 5d2e06a4fc..04055b5643 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs @@ -8,6 +8,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Ssl.Types; @@ -122,7 +123,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl if (HasCertStoreTitle()) { - using LocalStorage ncaFile = new(VirtualFileSystem.SwitchPathToSystemPath(GetCertStoreTitleContentPath()), FileAccess.Read, FileMode.Open); + string certStorePath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(GetCertStoreTitleContentPath()), false); + using LocalStorage ncaFile = new(certStorePath, FileAccess.Read, FileMode.Open); Nca nca = new(_virtualFileSystem.KeySet, ncaFile); diff --git a/src/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/src/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs index abf3cd7d63..4fb7d4b75c 100644 --- a/src/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs @@ -7,6 +7,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; @@ -89,7 +90,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { if (HasTimeZoneBinaryTitle()) { - using IStorage ncaFileStream = new LocalStorage(VirtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open); + string timeZoneBinPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), false); + using IStorage ncaFileStream = new LocalStorage(timeZoneBinPath, FileAccess.Read, FileMode.Open); Nca nca = new(_virtualFileSystem.KeySet, ncaFileStream); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); @@ -129,7 +131,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone List<(int Offset, string Location, string Abbr)> outList = new(); var now = DateTimeOffset.Now.ToUnixTimeSeconds(); - using (IStorage ncaStorage = new LocalStorage(VirtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), FileAccess.Read, FileMode.Open)) + string tzBinaryPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), false); + using (IStorage ncaStorage = new LocalStorage(tzBinaryPath, FileAccess.Read, FileMode.Open)) using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel)) { foreach (string locName in LocationNameCache) @@ -264,7 +267,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone return ResultCode.TimeZoneNotFound; } - ncaFile = new LocalStorage(VirtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open); + string timeZoneBinPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), false); + ncaFile = new LocalStorage(timeZoneBinPath, FileAccess.Read, FileMode.Open); Nca nca = new(_virtualFileSystem.KeySet, ncaFile); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index 540e90a25e..32cedf88c3 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -523,13 +523,12 @@ namespace Ryujinx.UI.App.Common return; } - var fileInfo = new FileInfo(app); + var fileInfo = FileSystemUtils.GetActualFileInfo(app); string extension = fileInfo.Extension.ToLower(); if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && extension is ".nsp" or ".pfs0" or ".xci" or ".nca" or ".nro" or ".nso") { - var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; - applicationPaths.Add(fullPath); + applicationPaths.Add(fileInfo.FullName); numApplicationsFound++; } } diff --git a/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs index b07bf78b94..f7bd1c6522 100644 --- a/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs @@ -8,6 +8,7 @@ using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Ava.UI.Models; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using SkiaSharp; using System; @@ -105,10 +106,10 @@ namespace Ryujinx.Ava.UI.ViewModels } string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); - string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath); - if (!string.IsNullOrWhiteSpace(avatarPath)) + if (!string.IsNullOrWhiteSpace(contentPath)) { + string avatarPath = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(contentPath), false); using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open); Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);