From 9c065c013eb677c1b425b82f1af6195acd3058f8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 14 Apr 2020 13:53:45 -0400 Subject: [PATCH 1/4] file_sys: control_metadata: Expose device_save_data_size. --- src/core/file_sys/control_metadata.cpp | 4 ++++ src/core/file_sys/control_metadata.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index f155a1341..63cd2eead 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -95,6 +95,10 @@ u32 NACP::GetSupportedLanguages() const { return raw.supported_languages; } +u64 NACP::GetDeviceSaveDataSize() const { + return raw.device_save_data_size; +} + std::vector NACP::GetRawBytes() const { std::vector out(sizeof(RawNACP)); std::memcpy(out.data(), &raw, sizeof(RawNACP)); diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 2d8c251ac..e37b2fadf 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -113,6 +113,7 @@ public: u32 GetSupportedLanguages() const; std::vector GetRawBytes() const; bool GetUserAccountSwitchLock() const; + u64 GetDeviceSaveDataSize() const; private: RawNACP raw{}; From ab9ddab0a21fa447f8cd93df0d529069e5a1cae0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 14 Apr 2020 15:00:57 -0400 Subject: [PATCH 2/4] file_sys: savefata_factory: Update to support DeviceSaveData. --- src/core/file_sys/savedata_factory.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index f3def93ab..adfd2c1a4 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -57,7 +57,8 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User - desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0); + (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) && + desc.title_id == 0 && desc.save_id == 0); } } // Anonymous namespace @@ -139,8 +140,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ 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 && title_id == 0) { - title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { + if (title_id == 0) { + title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + } } std::string out = GetSaveDataSpaceIdPath(space); From 551c61bf2781250d2817a7429a7a6c4b98ed7dc4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 14 Apr 2020 15:08:13 -0400 Subject: [PATCH 3/4] yuzu: game_list: Fix 'Open Save Data Location' for device saves. --- src/yuzu/game_list.cpp | 8 +++--- src/yuzu/game_list.h | 2 +- src/yuzu/main.cpp | 64 ++++++++++++++++++++++++++++-------------- src/yuzu/main.h | 2 +- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index dccbabcbf..bfb600df0 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -488,11 +488,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string pat auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); - connect(open_save_location, &QAction::triggered, [this, program_id]() { - emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); + connect(open_save_location, &QAction::triggered, [this, program_id, path]() { + emit OpenFolderRequested(GameListOpenTarget::SaveData, path); }); - connect(open_lfs_location, &QAction::triggered, [this, program_id]() { - emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); + connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() { + emit OpenFolderRequested(GameListOpenTarget::ModData, path); }); connect(open_transferable_shader_cache, &QAction::triggered, [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 878d94413..a38cb2fc3 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -73,7 +73,7 @@ public: signals: void GameChosen(QString game_path); void ShouldCancelWorker(); - void OpenFolderRequested(u64 program_id, GameListOpenTarget target); + void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path); void OpenTransferableShaderCacheRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path); void CopyTIDRequested(u64 program_id); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e8a1d49..437464797 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1154,40 +1154,62 @@ void GMainWindow::OnGameListLoadFile(QString game_path) { BootGame(game_path); } -void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { +void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path) { std::string path; QString open_target; + + const auto v_file = Core::GetGameFileFromPath(vfs, game_path); + const auto loader = Loader::GetLoader(v_file); + FileSys::NACP control{}; + u64 program_id{}; + + loader->ReadControlData(control); + loader->ReadProgramId(program_id); + + const bool has_user_save{control.GetDefaultNormalSaveSize() > 0}; + const bool has_device_save{control.GetDeviceSaveDataSize() > 0}; + + ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?"); + switch (target) { case GameListOpenTarget::SaveData: { open_target = tr("Save Data"); const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); ASSERT(program_id != 0); - const auto select_profile = [this] { - QtProfileSelectionDialog dialog(this); - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); - dialog.setWindowModality(Qt::WindowModal); + if (has_user_save) { + // User save data + const auto select_profile = [this] { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); - if (dialog.exec() == QDialog::Rejected) { - return -1; + if (dialog.exec() == QDialog::Rejected) { + return -1; + } + + return dialog.GetIndex(); + }; + + const auto index = select_profile(); + if (index == -1) { + return; } - return dialog.GetIndex(); - }; - - const auto index = select_profile(); - if (index == -1) { - return; + Service::Account::ProfileManager manager; + const auto user_id = manager.GetUser(static_cast(index)); + ASSERT(user_id); + path = nand_dir + FileSys::SaveDataFactory::GetFullPath( + FileSys::SaveDataSpaceId::NandUser, + FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0); + } else { + // Device save data + path = nand_dir + FileSys::SaveDataFactory::GetFullPath( + FileSys::SaveDataSpaceId::NandUser, + FileSys::SaveDataType::SaveData, program_id, {}, 0); } - Service::Account::ProfileManager manager; - const auto user_id = manager.GetUser(static_cast(index)); - ASSERT(user_id); - path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, - FileSys::SaveDataType::SaveData, - program_id, user_id->uuid, 0); - if (!FileUtil::Exists(path)) { FileUtil::CreateFullPath(path); FileUtil::CreateDir(path); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 60b17c54a..1495a1b26 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -183,7 +183,7 @@ private slots: void OnMenuReportCompatibility(); /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); - void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); + void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); void OnTransferableShaderCacheOpenFile(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); void OnGameListCopyTID(u64 program_id); From 47b97b95773e1cf1c4acd387ce4011b34cb67180 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 14 Apr 2020 15:34:59 -0400 Subject: [PATCH 4/4] service: fsp_srv: Stub implementation of OpenMultiCommitManager. --- src/core/hle/service/filesystem/fsp_srv.cpp | 38 ++++++++++++++++++++- src/core/hle/service/filesystem/fsp_srv.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f6503fe2f..20c331b77 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -767,7 +767,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) {1014, nullptr, "OutputMultiProgramTagAccessLog"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, - {1200, nullptr, "OpenMultiCommitManager"}, + {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, {1300, nullptr, "OpenBisWiper"}, }; // clang-format on @@ -988,4 +988,40 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { rb.Push(access_log_program_index); } +class IMultiCommitManager final : public ServiceFramework { +public: + explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") { + static const FunctionInfo functions[] = { + {1, &IMultiCommitManager::Add, "Add"}, + {2, &IMultiCommitManager::Commit, "Commit"}, + }; + RegisterHandlers(functions); + } + +private: + FileSys::VirtualFile backend; + + void Add(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Commit(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } +}; + +void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::make_shared()); +} + } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index d52b55999..dfb3e395b 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -50,6 +50,7 @@ private: void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); + void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); FileSystemController& fsc;