From a819b230d0c4a0a3274bc0446a71df6454d49762 Mon Sep 17 00:00:00 2001 From: Collecting Date: Fri, 23 Jan 2026 23:25:39 +0100 Subject: [PATCH 1/2] fix(filesystem): Re-organize Path Ordering Signed-off-by: Collecting --- .../hle/service/filesystem/filesystem.cpp | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 056ca8d70..36fe52216 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -422,15 +422,30 @@ std::shared_ptr FileSystemController::CreateSaveDataFa const auto rw_mode = FileSys::OpenMode::ReadWrite; auto vfs = system.GetFilesystem(); + // 1. Priority 1: Mirrored Path Override (Forces NAND) + if (Settings::values.mirrored_save_paths.count(program_id)) { + LOG_INFO(Service_FS, + "Save Path: Mirroring detected for Program ID {:016X}. Forcing use of NAND " + "directory for syncing.", + program_id); + const auto nand_directory = + vfs->OpenDirectory(Common::FS::GetCitronPathString(CitronPath::NANDDir), rw_mode); + return std::make_shared(system, program_id, + std::move(nand_directory)); + } + std::string custom_path_str; - // 1. Priority 1: Global Override - if (Settings::values.global_custom_save_path_enabled.GetValue()) { - custom_path_str = Settings::values.global_custom_save_path.GetValue(); - } // 2. Priority 2: Individual Game Override - else if (Settings::values.custom_save_paths.count(program_id)) { + if (Settings::values.custom_save_paths.count(program_id)) { custom_path_str = Settings::values.custom_save_paths.at(program_id); + LOG_INFO(Service_FS, "Save Path: Using Per-Game Custom Path for Program ID {:016X}: {}", + program_id, custom_path_str); + } + // 3. Priority 3: Global Override + else if (Settings::values.global_custom_save_path_enabled.GetValue()) { + custom_path_str = Settings::values.global_custom_save_path.GetValue(); + LOG_INFO(Service_FS, "Save Path: Using Global Custom Save Path: {}", custom_path_str); } // If any custom logic is hit, use that path but KEEP NAND as backup target @@ -438,17 +453,21 @@ std::shared_ptr FileSystemController::CreateSaveDataFa const std::filesystem::path custom_path = custom_path_str; if (Common::FS::IsDir(custom_path)) { auto custom_save_directory = vfs->OpenDirectory(custom_path_str, rw_mode); - auto nand_directory = vfs->OpenDirectory(Common::FS::GetCitronPathString(CitronPath::NANDDir), rw_mode); + auto nand_directory = + vfs->OpenDirectory(Common::FS::GetCitronPathString(CitronPath::NANDDir), rw_mode); return std::make_shared( system, program_id, std::move(custom_save_directory), std::move(nand_directory)); } } - // 3. Fallback: Standard NAND - const auto nand_directory = vfs->OpenDirectory(Common::FS::GetCitronPathString(CitronPath::NANDDir), rw_mode); - return std::make_shared(system, program_id, std::move(nand_directory)); - } + // 4. Fallback: Standard NAND + LOG_INFO(Service_FS, "Save Path: No custom paths found. Falling back to default NAND."); + const auto nand_directory = + vfs->OpenDirectory(Common::FS::GetCitronPathString(CitronPath::NANDDir), rw_mode); + return std::make_shared(system, program_id, + std::move(nand_directory)); +} Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { LOG_TRACE(Service_FS, "Opening SDMC"); From 3bf14973000d5195f2d18037554386918aa44f3a Mon Sep 17 00:00:00 2001 From: Collecting Date: Fri, 23 Jan 2026 23:26:36 +0100 Subject: [PATCH 2/2] fix(ui): Ensure Paths are properly displayed when checking paths Signed-off-by: Collecting --- src/citron/main.cpp | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/citron/main.cpp b/src/citron/main.cpp index 6f020c20d..86b7e9251 100644 --- a/src/citron/main.cpp +++ b/src/citron/main.cpp @@ -2426,13 +2426,38 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target case GameListOpenTarget::SaveData: { open_target = tr("Save Data"); - if (Settings::values.custom_save_paths.count(program_id)) { + // 1. Check for Mirrored Path FIRST (opens the external directory) + if (Settings::values.mirrored_save_paths.count(program_id)) { + const std::string& mirrored_path_str = + Settings::values.mirrored_save_paths.at(program_id); + if (!mirrored_path_str.empty() && Common::FS::IsDir(mirrored_path_str)) { + LOG_INFO(Frontend, "Opening mirrored save data path for program_id={:016x}", + program_id); + QDesktopServices::openUrl( + QUrl::fromLocalFile(QString::fromStdString(mirrored_path_str))); + return; + } + } + // 2. Check for Per-Game Custom Path + else if (Settings::values.custom_save_paths.count(program_id)) { const std::string& custom_path_str = Settings::values.custom_save_paths.at(program_id); - const std::filesystem::path custom_path = custom_path_str; - - if (!custom_path_str.empty() && Common::FS::IsDir(custom_path)) { - LOG_INFO(Frontend, "Opening custom save data path for program_id={:016x}", program_id); - QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(custom_path_str))); + if (!custom_path_str.empty() && Common::FS::IsDir(custom_path_str)) { + LOG_INFO(Frontend, "Opening custom save data path for program_id={:016x}", + program_id); + QDesktopServices::openUrl( + QUrl::fromLocalFile(QString::fromStdString(custom_path_str))); + return; + } + } + // 3. Check for Global Custom Save Path + else if (Settings::values.global_custom_save_path_enabled.GetValue()) { + const std::string& global_path_str = + Settings::values.global_custom_save_path.GetValue(); + if (!global_path_str.empty() && Common::FS::IsDir(global_path_str)) { + LOG_INFO(Frontend, "Opening global custom save data path for program_id={:016x}", + program_id); + QDesktopServices::openUrl( + QUrl::fromLocalFile(QString::fromStdString(global_path_str))); return; } }