Handle symlinks correctly when resolving file paths

This commit is contained in:
TSR Berry 2024-07-11 00:47:56 +02:00
commit eb7fb9da74
No known key found for this signature in database
GPG key ID: 52353C0A4CCA15E2
16 changed files with 116 additions and 97 deletions

View file

@ -44,7 +44,7 @@ namespace Ryujinx.Common.Configuration
static AppDataManager() 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) public static void Initialize(string baseDirPath)
@ -56,23 +56,23 @@ namespace Ryujinx.Common.Configuration
appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
} }
string userProfilePath = Path.Combine(appDataPath, DefaultBaseDir); string userProfilePath = FileSystemUtils.ResolveFullPath(Path.Combine(appDataPath, DefaultBaseDir), true);
string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir); DirectoryInfo portableInfo = FileSystemUtils.GetActualDirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir));
// On macOS, check for a portable directory next to the app bundle as well. // 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, "..", "..")); string bundlePath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", ".."));
// Make sure we're actually running within an app bundle. // Make sure we're actually running within an app bundle.
if (bundlePath.EndsWith(".app")) 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; Mode = LaunchMode.Portable;
} }
else else
@ -83,24 +83,19 @@ namespace Ryujinx.Common.Configuration
if (baseDirPath != null && baseDirPath != userProfilePath) 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}..."); Logger.Error?.Print(LogClass.Application, $"Custom Data Directory '{baseDirPath}' does not exist. Falling back to {Mode}...");
} }
else else
{ {
BaseDirPath = baseDirPath; BaseDirPath = baseDirInfo.FullName;
Mode = LaunchMode.Custom; 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(); SetupBasePaths();
} }
@ -217,16 +212,16 @@ namespace Ryujinx.Common.Configuration
} }
} }
return logDir; return FileSystemUtils.ResolveFullPath(logDir, true);
} }
private static void SetupBasePaths() private static void SetupBasePaths()
{ {
Directory.CreateDirectory(BaseDirPath); Directory.CreateDirectory(BaseDirPath);
LogsDirPath = SetUpLogsDir(); LogsDirPath = SetUpLogsDir();
Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir)); Directory.CreateDirectory(GamesDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, GamesDir), true));
Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir)); Directory.CreateDirectory(ProfilesDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, ProfilesDir), true));
Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir)); Directory.CreateDirectory(KeysDirPath = FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, KeysDir), true));
} }
// Check if existing old baseDirPath is a symlink, to prevent possible errors. // 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 GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, DefaultModsDir), true)).FullName;
public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere")).FullName; public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(FileSystemUtils.ResolveFullPath(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere"), true)).FullName;
} }
} }

View file

@ -15,6 +15,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop; using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
@ -920,7 +921,7 @@ namespace Ryujinx.UI
if (application.Path.StartsWith("@SystemContent")) if (application.Path.StartsWith("@SystemContent"))
{ {
application.Path = VirtualFileSystem.SwitchPathToSystemPath(application.Path); application.Path = FileSystemUtils.ResolveFullPath(VirtualFileSystem.SwitchPathToSystemPath(application.Path), false);
isFirmwareTitle = true; isFirmwareTitle = true;
} }

View file

@ -7,6 +7,7 @@ using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.UI.Common.Configuration; using Ryujinx.UI.Common.Configuration;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
@ -119,10 +120,10 @@ namespace Ryujinx.UI.Windows
} }
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); 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); using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open);
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);

View file

@ -349,18 +349,15 @@ namespace Ryujinx.HLE.FileSystem
return false; 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(installedInfo.FullName, FileMode.Open, FileAccess.Read);
{ Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage());
using FileStream file = new(installedPath, FileMode.Open, FileAccess.Read); bool contentCheck = nca.Header.ContentType == contentType;
Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage());
bool contentCheck = nca.Header.ContentType == contentType;
return contentCheck; return contentCheck;
}
} }
return false; return false;
@ -941,9 +938,9 @@ namespace Ryujinx.HLE.FileSystem
{ {
if (entry.ContentType == NcaContentType.Data) 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()); Nca nca = new(_virtualFileSystem.KeySet, fileStream.AsStorage());
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)

View file

@ -14,6 +14,7 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
using System.Buffers.Text; using System.Buffers.Text;
@ -22,14 +23,15 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Path = System.IO.Path; using Path = System.IO.Path;
using SpanHelpers = LibHac.Common.SpanHelpers;
namespace Ryujinx.HLE.FileSystem namespace Ryujinx.HLE.FileSystem
{ {
public class VirtualFileSystem : IDisposable public class VirtualFileSystem : IDisposable
{ {
public static readonly string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe"); public static readonly string SafeNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "safe"), true);
public static readonly string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system"); public static readonly string SystemNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "system"), true);
public static readonly string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user"); public static readonly string UserNandPath = FileSystemUtils.ResolveFullPath(Path.Combine(AppDataManager.DefaultNandDir, "user"), true);
public KeySet KeySet { get; private set; } public KeySet KeySet { get; private set; }
public EmulatedGameCard GameCard { get; private set; } public EmulatedGameCard GameCard { get; private set; }
@ -61,7 +63,9 @@ namespace Ryujinx.HLE.FileSystem
public void LoadRomFs(ulong pid, string fileName) 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) => _romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
{ {
@ -111,8 +115,8 @@ namespace Ryujinx.HLE.FileSystem
return fullPath; return fullPath;
} }
internal static string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir); internal static string GetSdCardPath() => FileSystemUtils.ResolveFullPath(MakeFullPath(AppDataManager.DefaultSdcardDir), true);
public static string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir); public static string GetNandPath() => FileSystemUtils.ResolveFullPath(MakeFullPath(AppDataManager.DefaultNandDir), true);
public static string SwitchPathToSystemPath(string switchPath) public static string SwitchPathToSystemPath(string switchPath)
{ {
@ -236,23 +240,23 @@ namespace Ryujinx.HLE.FileSystem
void LoadSetAtPath(string basePath) void LoadSetAtPath(string basePath)
{ {
string localKeyFile = Path.Combine(basePath, "prod.keys"); FileInfo localKeyFile = FileSystemUtils.GetActualFileInfo(Path.Combine(basePath, "prod.keys"));
string localTitleKeyFile = Path.Combine(basePath, "title.keys"); FileInfo localTitleKeyFile = FileSystemUtils.GetActualFileInfo(Path.Combine(basePath, "title.keys"));
string localConsoleKeyFile = Path.Combine(basePath, "console.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;
} }
} }

View file

@ -6,6 +6,7 @@ using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
@ -107,14 +108,20 @@ namespace Ryujinx.HLE.HOS.Applets.Error
private static string CleanText(string value) 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) private string GetMessageText(uint module, uint description, string key)
{ {
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data); 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); Nca nca = new(_horizon.Device.FileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel);
string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage); string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage);
@ -131,7 +138,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
} }
else else
{ {
return ""; return string.Empty;
} }
} }
@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
{ {
string buttonsText = GetMessageText(module, description, key); 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() private void ParseErrorCommonArg()
@ -156,7 +163,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
string message = GetMessageText(module, description, "DlgMsg"); string message = GetMessageText(module, description, "DlgMsg");
if (message == "") if (message == string.Empty)
{ {
message = "An error has occured.\n\n" message = "An error has occured.\n\n"
+ "Please try again later.\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". // TODO: Handle the LanguageCode to return the translated "OK" and "Details".
if (detailsText.Trim() != "") if (detailsText.Trim() != string.Empty)
{ {
buttons.Add("Details"); buttons.Add("Details");
} }

View file

@ -3,6 +3,7 @@ using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.Horizon; using Ryujinx.Horizon;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
@ -39,19 +40,18 @@ namespace Ryujinx.HLE.HOS
public Result MountSystemData(string mountName, ulong dataId) public Result MountSystemData(string mountName, ulong dataId)
{ {
string contentPath = _system.ContentManager.GetInstalledContentPath(dataId, StorageId.BuiltInSystem, NcaContentType.PublicData); 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; LocalStorage ncaStorage = null;
try try
{ {
ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); ncaStorage = new LocalStorage(ncaInfo.FullName, FileAccess.Read, FileMode.Open);
Nca nca = new(_system.KeySet, ncaStorage); Nca nca = new(_system.KeySet, ncaStorage);

View file

@ -5,6 +5,7 @@ using LibHac.Ns;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory; 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) if (Interlocked.Exchange(ref _jitLoaded, 1) == 0)
{ {
string jitPath = context.Device.System.ContentManager.GetInstalledContentPath(0x010000000000003B, StorageId.BuiltInSystem, NcaContentType.Program); const ulong JitApplicationId = 0x010000000000003B;
string filePath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(jitPath); 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); context.Device.LoadNca(filePath);
// FIXME: Most likely not how this should be done? // FIXME: Most likely not how this should be done?

View file

@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
using System; using System;
using System.IO; using System.IO;
@ -18,6 +19,7 @@ using static Ryujinx.HLE.Utilities.StringUtils;
using GameCardHandle = System.UInt32; using GameCardHandle = System.UInt32;
using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem;
using IStorage = LibHac.FsSrv.Sf.IStorage; using IStorage = LibHac.FsSrv.Sf.IStorage;
using SpanHelpers = LibHac.Common.SpanHelpers;
namespace Ryujinx.HLE.HOS.Services.Fs namespace Ryujinx.HLE.HOS.Services.Fs
{ {
@ -52,13 +54,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs
ulong titleId = context.RequestData.ReadUInt64(); ulong titleId = context.RequestData.ReadUInt64();
#pragma warning restore IDE0059 #pragma warning restore IDE0059
string switchPath = ReadUtf8String(context); 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) if (result == ResultCode.Success)
{ {
@ -71,12 +73,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return ResultCode.PathDoesNotExist; return ResultCode.PathDoesNotExist;
} }
FileStream fileStream = new(fullPath, FileMode.Open, FileAccess.Read); FileStream fileStream = realPathInfo.Open(FileMode.Open, FileAccess.Read);
string extension = System.IO.Path.GetExtension(fullPath); string extension = realPathInfo.Extension.ToLower();
if (extension == ".nca") 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) if (result == ResultCode.Success)
{ {
@ -87,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
} }
else if (extension == ".nsp") 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) if (result == ResultCode.Success)
{ {
@ -832,17 +834,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs
if (installedStorage != StorageId.None) if (installedStorage != StorageId.None)
{ {
string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, contentType); 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 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); Nca nca = new(context.Device.System.KeySet, ncaStorage);
LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(romfsStorage); using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(romfsStorage);
@ -859,12 +860,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
} }
else else
{ {
throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`."); throw new FileNotFoundException($"No Nca found at path `{ncaInfo.FullName}`.");
} }
} }
else 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}.");
} }
} }

View file

@ -6,6 +6,7 @@ using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Kernel.Memory; 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)) if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename))
{ {
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.BuiltInSystem, NcaContentType.Data); 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; byte[] data;
using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open)) using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open))

View file

@ -7,6 +7,7 @@ using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
using System.IO; using System.IO;
@ -305,7 +306,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
return null; 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); using IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read);
Nca firmwareContent = new(device.System.KeySet, firmwareStorage); Nca firmwareContent = new(device.System.KeySet, firmwareStorage);

View file

@ -1,4 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Sockets.Nsd; using Ryujinx.HLE.HOS.Services.Sockets.Nsd;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -21,12 +22,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy
{ {
string sdPath = FileSystem.VirtualFileSystem.GetSdCardPath(); string sdPath = FileSystem.VirtualFileSystem.GetSdCardPath();
string filePath = FileSystem.VirtualFileSystem.GetFullPath(sdPath, HostsFilePath); string filePath = FileSystem.VirtualFileSystem.GetFullPath(sdPath, HostsFilePath);
FileInfo fileInfo = new FileInfo(filePath).GetActualFileInfo();
_mitmHostEntries.Clear(); _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); using StreamReader reader = new(fileStream);
while (!reader.EndOfStream) while (!reader.EndOfStream)
@ -92,9 +94,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy
return new IPHostEntry return new IPHostEntry
{ {
AddressList = new[] { hostEntry.Value }, AddressList = [hostEntry.Value],
HostName = hostEntry.Key, HostName = hostEntry.Key,
Aliases = Array.Empty<string>(), Aliases = [],
}; };
} }
} }

View file

@ -8,6 +8,7 @@ using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Ssl.Types; using Ryujinx.HLE.HOS.Services.Ssl.Types;
@ -122,7 +123,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
if (HasCertStoreTitle()) 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); Nca nca = new(_virtualFileSystem.KeySet, ncaFile);

View file

@ -7,6 +7,7 @@ using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@ -89,7 +90,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
if (HasTimeZoneBinaryTitle()) 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); Nca nca = new(_virtualFileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); 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(); List<(int Offset, string Location, string Abbr)> outList = new();
var now = DateTimeOffset.Now.ToUnixTimeSeconds(); 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)) using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel))
{ {
foreach (string locName in LocationNameCache) foreach (string locName in LocationNameCache)
@ -264,7 +267,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return ResultCode.TimeZoneNotFound; 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); Nca nca = new(_virtualFileSystem.KeySet, ncaFile);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel);

View file

@ -523,13 +523,12 @@ namespace Ryujinx.UI.App.Common
return; return;
} }
var fileInfo = new FileInfo(app); var fileInfo = FileSystemUtils.GetActualFileInfo(app);
string extension = fileInfo.Extension.ToLower(); string extension = fileInfo.Extension.ToLower();
if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && extension is ".nsp" or ".pfs0" or ".xci" or ".nca" or ".nro" or ".nso") 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(fileInfo.FullName);
applicationPaths.Add(fullPath);
numApplicationsFound++; numApplicationsFound++;
} }
} }

View file

@ -8,6 +8,7 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using SkiaSharp; using SkiaSharp;
using System; using System;
@ -105,10 +106,10 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); 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); using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open);
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);