From ae453ab6a829942a0db25b59e2cf97b5f7f1ecf9 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 16 Oct 2022 22:58:44 -0400 Subject: [PATCH] savedata_factory: Detect future save data paths Enable compatibility for new account/device save paths planned on a future implementation. --- src/core/file_sys/savedata_factory.cpp | 58 ++++++++++++++++++++++---- src/core/file_sys/savedata_factory.h | 4 +- src/yuzu/main.cpp | 10 +++-- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 8c1b2523cb..1567da2310 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/uuid.h" #include "core/core.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/vfs.h" @@ -59,6 +60,36 @@ bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataA attr.title_id == 0 && attr.save_id == 0); } +std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, + u128 user_id) { + // Only detect nand user saves. + const auto space_id_path = [space_id]() -> std::string_view { + switch (space_id) { + case SaveDataSpaceId::NandUser: + return "/user/save"; + default: + return ""; + } + }(); + + if (space_id_path.empty()) { + return ""; + } + + Common::UUID uuid; + std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID)); + + // Only detect account/device saves from the future location. + switch (type) { + case SaveDataType::SaveData: + return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id); + case SaveDataType::DeviceSaveData: + return fmt::format("{}/device/{:016X}/1", space_id_path, title_id); + default: + return ""; + } +} + } // Anonymous namespace std::string SaveDataAttribute::DebugInfo() const { @@ -82,7 +113,7 @@ ResultVal SaveDataFactory::Create(SaveDataSpaceId space, PrintSaveDataAttributeWarnings(meta); const auto save_directory = - GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); + GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); auto out = dir->CreateDirectoryRelative(save_directory); @@ -99,7 +130,7 @@ ResultVal SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { const auto save_directory = - GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); + GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); auto out = dir->GetDirectoryRelative(save_directory); @@ -134,9 +165,9 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { } } -std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space, - SaveDataType type, u64 title_id, u128 user_id, - u64 save_id) { +std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, + SaveDataSpaceId space, SaveDataType type, u64 title_id, + u128 user_id, u64 save_id) { // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should // be interpreted as the title id of the current process. if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { @@ -145,6 +176,17 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s } } + // For compat with a future impl. + if (std::string future_path = + GetFutureSaveDataPath(space, type, title_id & ~(0xFFULL), user_id); + !future_path.empty()) { + // Check if this location exists, and prefer it over the old. + if (const auto future_dir = dir->GetDirectoryRelative(future_path); future_dir != nullptr) { + LOG_INFO(Service_FS, "Using save at new location: {}", future_path); + return future_path; + } + } + std::string out = GetSaveDataSpaceIdPath(space); switch (type) { @@ -167,7 +209,8 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const { - const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + const auto path = + GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME); @@ -185,7 +228,8 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value) const { - const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + const auto path = + GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME); diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index a763b94c88..d3633ef039 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -95,8 +95,8 @@ public: VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); - static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type, - u64 title_id, u128 user_id, u64 save_id); + static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, + SaveDataType type, u64 title_id, u128 user_id, u64 save_id); SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a94624be63..d05c7ece80 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1895,6 +1895,8 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target case GameListOpenTarget::SaveData: { open_target = tr("Save Data"); const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); + auto vfs_nand_dir = + vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); if (has_user_save) { // User save data @@ -1921,15 +1923,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target ASSERT(user_id); const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( - *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, - program_id, user_id->AsU128(), 0); + *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, + FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); } else { // Device save data const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( - *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, - program_id, {}, 0); + *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, + FileSys::SaveDataType::SaveData, program_id, {}, 0); path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); }