From 4a6ba5807343b668861efbd8367e39640cafc9f4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:23:44 -0500 Subject: [PATCH 1/7] vfs: Add reinterpret_casts to WriteArray and Object Allows these functions to compile when T is not u8. --- src/core/file_sys/vfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index e5641b255..954094772 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -150,7 +150,7 @@ public: template std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); - return Write(data, number_elements * sizeof(T), offset); + return Write(reinterpret_cast(data), number_elements * sizeof(T), offset); } // Writes size bytes starting at memory location data to offset in file. @@ -166,7 +166,7 @@ public: template std::size_t WriteObject(const T& data, std::size_t offset = 0) { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); - return Write(&data, sizeof(T), offset); + return Write(reinterpret_cast(&data), sizeof(T), offset); } // Renames the file to name. Returns whether or not the operation was successsful. From 5c4259ec1a499528e132b1d41f7559f73bfd1143 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:25:32 -0500 Subject: [PATCH 2/7] control_metadata: Use value member instead of unique_ptr to store struct Serves no actual purpose in this instance besides making NACP's copy assignment deleted, which is not intended behavior. --- src/core/file_sys/control_metadata.cpp | 20 +++++++++++--------- src/core/file_sys/control_metadata.h | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index e065e592f..fe2077f94 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -36,18 +36,20 @@ std::string LanguageEntry::GetDeveloperName() const { developer_name.size()); } -NACP::NACP(VirtualFile file) : raw(std::make_unique()) { - file->ReadObject(raw.get()); +NACP::NACP() : raw{} {} + +NACP::NACP(VirtualFile file) { + file->ReadObject(&raw); } NACP::~NACP() = default; const LanguageEntry& NACP::GetLanguageEntry(Language language) const { if (language != Language::Default) { - return raw->language_entries.at(static_cast(language)); + return raw.language_entries.at(static_cast(language)); } - for (const auto& language_entry : raw->language_entries) { + for (const auto& language_entry : raw.language_entries) { if (!language_entry.GetApplicationName().empty()) return language_entry; } @@ -65,21 +67,21 @@ std::string NACP::GetDeveloperName(Language language) const { } u64 NACP::GetTitleId() const { - return raw->title_id; + return raw.title_id; } u64 NACP::GetDLCBaseTitleId() const { - return raw->dlc_base_title_id; + return raw.dlc_base_title_id; } std::string NACP::GetVersionString() const { - return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), - raw->version_string.size()); + return Common::StringFromFixedZeroTerminatedBuffer(raw.version_string.data(), + raw.version_string.size()); } std::vector NACP::GetRawBytes() const { std::vector out(sizeof(RawNACP)); - std::memcpy(out.data(), raw.get(), sizeof(RawNACP)); + std::memcpy(out.data(), &raw, sizeof(RawNACP)); return out; } } // namespace FileSys diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index bfaad46b4..d5c2ed2b5 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -72,6 +72,7 @@ extern const std::array LANGUAGE_NAMES; // These store application name, dev name, title id, and other miscellaneous data. class NACP { public: + explicit NACP(); explicit NACP(VirtualFile file); ~NACP(); @@ -84,7 +85,7 @@ public: std::vector GetRawBytes() const; private: - std::unique_ptr raw; + RawNACP raw; }; } // namespace FileSys From 417e1ef09cfcf9157e260721d3059e73f0eca73e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:25:55 -0500 Subject: [PATCH 3/7] control_metadata: Update NACP fields with latest Switchbrew data --- src/core/file_sys/control_metadata.cpp | 8 ++++++++ src/core/file_sys/control_metadata.h | 27 ++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index fe2077f94..9624df054 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -79,6 +79,14 @@ std::string NACP::GetVersionString() const { raw.version_string.size()); } +u64 NACP::GetDefaultNormalSaveSize() const { + return raw.normal_save_data_size; +} + +u64 NACP::GetDefaultJournalSaveSize() const { + return raw.journal_sava_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 d5c2ed2b5..9bc2720c9 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -28,17 +28,30 @@ static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size. // The raw file format of a NACP file. struct RawNACP { std::array language_entries; - INSERT_PADDING_BYTES(0x38); + std::array isbn; + u8 startup_user_account; + INSERT_PADDING_BYTES(2); + u32_le application_attribute; + u32_le supported_languages; + u32_le parental_control; + bool screenshot_enabled; + u8 video_capture_mode; + bool data_loss_confirmation; + INSERT_PADDING_BYTES(1); u64_le title_id; - INSERT_PADDING_BYTES(0x20); + std::array rating_age; std::array version_string; u64_le dlc_base_title_id; u64_le title_id_2; - INSERT_PADDING_BYTES(0x28); + u64_le normal_save_data_size; + u64_le journal_sava_data_size; + INSERT_PADDING_BYTES(0x18); u64_le product_code; - u64_le title_id_3; - std::array title_id_array; - INSERT_PADDING_BYTES(0x8); + std::array local_communication; + u8 logo_type; + u8 logo_handling; + bool runtime_add_on_content_install; + INSERT_PADDING_BYTES(5); u64_le title_id_update; std::array bcat_passphrase; INSERT_PADDING_BYTES(0xEC0); @@ -82,6 +95,8 @@ public: u64 GetTitleId() const; u64 GetDLCBaseTitleId() const; std::string GetVersionString() const; + u64 GetDefaultNormalSaveSize() const; + u64 GetDefaultJournalSaveSize() const; std::vector GetRawBytes() const; private: From 0756f29a2c99070a6c676b39d797015d140ad7ac Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:27:50 -0500 Subject: [PATCH 4/7] loader: Add accessor for game control data --- src/core/loader/loader.h | 10 +++++++--- src/core/loader/nsp.cpp | 4 ++-- src/core/loader/nsp.h | 2 +- src/core/loader/xci.cpp | 5 +++-- src/core/loader/xci.h | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 0838e303b..cfd67adc0 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -15,6 +15,10 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/vfs.h" +namespace FileSys { +class NACP; +} // namespace FileSys + namespace Kernel { struct AddressMapping; class Process; @@ -245,11 +249,11 @@ public: } /** - * Get the developer of the application - * @param developer Reference to store the application developer into + * Get the control data (CNMT) of the application + * @param control Reference to store the application control data into * @return ResultStatus result of function */ - virtual ResultStatus ReadDeveloper(std::string& developer) { + virtual ResultStatus ReadControlData(FileSys::NACP& control) { return ResultStatus::ErrorNotImplemented; } diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index b4ab88ae8..4d4b44571 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -152,10 +152,10 @@ ResultStatus AppLoader_NSP::ReadTitle(std::string& title) { return ResultStatus::Success; } -ResultStatus AppLoader_NSP::ReadDeveloper(std::string& developer) { +ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) { if (nacp_file == nullptr) return ResultStatus::ErrorNoControl; - developer = nacp_file->GetDeveloperName(); + nacp = *nacp_file; return ResultStatus::Success; } } // namespace Loader diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 2b1e0719b..32eb0193d 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -43,7 +43,7 @@ public: ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadIcon(std::vector& buffer) override; ResultStatus ReadTitle(std::string& title) override; - ResultStatus ReadDeveloper(std::string& developer) override; + ResultStatus ReadControlData(FileSys::NACP& nacp) override; private: std::unique_ptr nsp; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index bd5a83b49..e67e43c69 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -121,10 +121,11 @@ ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { return ResultStatus::Success; } -ResultStatus AppLoader_XCI::ReadDeveloper(std::string& developer) { +ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { if (nacp_file == nullptr) return ResultStatus::ErrorNoControl; - developer = nacp_file->GetDeveloperName(); + control = *nacp_file; return ResultStatus::Success; } + } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 15d1b1a23..9d3923f62 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -43,7 +43,7 @@ public: ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadIcon(std::vector& buffer) override; ResultStatus ReadTitle(std::string& title) override; - ResultStatus ReadDeveloper(std::string& developer) override; + ResultStatus ReadControlData(FileSys::NACP& control) override; private: std::unique_ptr xci; From 4082c4eda6d8282abf0ba7763ed4fd66ecd176f1 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:28:51 -0500 Subject: [PATCH 5/7] savedata_factory: Partially implement IVFC save sizes using files This stores a file in the save directory called '.yuzu_save_size' which stores the two save sizes (normal area and journaled area) sequentially as u64s. --- src/core/file_sys/savedata_factory.cpp | 30 ++++++++++++++++++++++++++ src/core/file_sys/savedata_factory.h | 8 +++++++ 2 files changed, 38 insertions(+) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index d63b7f19b..54f5b698a 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -13,6 +13,8 @@ namespace FileSys { +constexpr const char* SAVE_DATA_SIZE_FILENAME = ".yuzu_save_size"; + std::string SaveDataDescriptor::DebugInfo() const { return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]", static_cast(type), title_id, user_id[1], user_id[0], save_id); @@ -132,4 +134,32 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ } } +SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, + u128 user_id) const { + const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + const auto dir = GetOrCreateDirectoryRelative(this->dir, path); + + const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME); + if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) + return {0, 0}; + + SaveDataSize out; + if (size_file->ReadObject(&out) != sizeof(SaveDataSize)) + return {0, 0}; + return out; +} + +void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, + SaveDataSize new_value) { + const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + const auto dir = GetOrCreateDirectoryRelative(this->dir, path); + + const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME); + if (size_file == nullptr) + return; + + size_file->Resize(sizeof(SaveDataSize)); + size_file->WriteObject(new_value); +} + } // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index bd4919610..3a1caf292 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -46,6 +46,11 @@ struct SaveDataDescriptor { }; static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size."); +struct SaveDataSize { + u64 normal; + u64 journal; +}; + /// File system interface to the SaveData archive class SaveDataFactory { public: @@ -60,6 +65,9 @@ public: static std::string GetFullPath(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, SaveDataSize new_value); + private: VirtualDir dir; }; From 2e6b67a079593e810dd7f27cd4388fef385b9c99 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Dec 2018 20:29:36 -0500 Subject: [PATCH 6/7] filesystem: Populate save data sizes from control data --- .../hle/service/filesystem/filesystem.cpp | 47 +++++++++++++++++++ src/core/hle/service/filesystem/filesystem.h | 6 +++ 2 files changed, 53 insertions(+) diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index b1490e6fa..c6da2df43 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -8,18 +8,23 @@ #include "common/file_util.h" #include "core/core.h" #include "core/file_sys/bis_factory.h" +#include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" #include "core/file_sys/mode.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_offset.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_ldr.h" #include "core/hle/service/filesystem/fsp_pr.h" #include "core/hle/service/filesystem/fsp_srv.h" +#include "core/loader/loader.h" namespace Service::FileSystem { @@ -28,6 +33,10 @@ namespace Service::FileSystem { // TODO(DarkLordZach): Eventually make this configurable in settings. constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; +// A default size for normal/journal save data size if application control metadata cannot be found. +// This should be large enough to satisfy even the most extreme requirements (~4.2GB) +constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; + static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, std::string_view dir_name_) { std::string dir_name(FileUtil::SanitizePath(dir_name_)); @@ -341,6 +350,44 @@ ResultVal OpenSDMC() { return sdmc_factory->Open(); } +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) { + if (save_data_factory == nullptr) { + return {0, 0}; + } + + const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); + + if (value.normal == 0 && value.journal == 0) { + FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; + + FileSys::NACP nacp; + const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp); + + if (res != Loader::ResultStatus::Success) { + FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()}; + auto [nacp_unique, discard] = pm.GetControlMetadata(); + + if (nacp_unique != nullptr) { + new_size = {nacp_unique->GetDefaultNormalSaveSize(), + nacp_unique->GetDefaultJournalSaveSize()}; + } + } else { + new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; + } + + WriteSaveDataSize(type, title_id, user_id, new_size); + return new_size; + } + + return value; +} + +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value) { + if (save_data_factory != nullptr) + save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); +} + FileSys::RegisteredCacheUnion GetUnionContents() { return FileSys::RegisteredCacheUnion{ {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}}; diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 965414be0..6fd5e7b23 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -21,9 +21,11 @@ class SDMCFactory; enum class ContentRecordType : u8; enum class Mode : u32; enum class SaveDataSpaceId : u8; +enum class SaveDataType : u8; enum class StorageId : u8; struct SaveDataDescriptor; +struct SaveDataSize; } // namespace FileSys namespace Service { @@ -48,6 +50,10 @@ ResultVal OpenSaveData(FileSys::SaveDataSpaceId space, ResultVal OpenSaveDataSpace(FileSys::SaveDataSpaceId space); ResultVal OpenSDMC(); +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value); + FileSys::RegisteredCacheUnion GetUnionContents(); FileSys::RegisteredCache* GetSystemNANDContents(); From c643f364b4c81543782009ce4bb5a87021fe35ed Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 10 Dec 2018 22:17:45 -0500 Subject: [PATCH 7/7] am: Implement GetSaveDataSize and ExtendSaveData These functions come in a pair and are needed by Smash Ultimate, Minecraft, and Skyrim, amongst others. --- src/core/file_sys/control_metadata.cpp | 2 +- src/core/file_sys/control_metadata.h | 2 +- src/core/file_sys/savedata_factory.cpp | 2 +- src/core/hle/service/am/am.cpp | 47 ++++++++++++++++++- src/core/hle/service/am/am.h | 2 + .../configuration/configure_per_general.cpp | 6 +-- 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index 9624df054..83c184750 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -36,7 +36,7 @@ std::string LanguageEntry::GetDeveloperName() const { developer_name.size()); } -NACP::NACP() : raw{} {} +NACP::NACP() = default; NACP::NACP(VirtualFile file) { file->ReadObject(&raw); diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 9bc2720c9..7b9cdc910 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -100,7 +100,7 @@ public: std::vector GetRawBytes() const; private: - RawNACP raw; + RawNACP raw{}; }; } // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 54f5b698a..1913dc956 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -13,7 +13,7 @@ namespace FileSys { -constexpr const char* SAVE_DATA_SIZE_FILENAME = ".yuzu_save_size"; +constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; std::string SaveDataDescriptor::DebugInfo() const { return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]", diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 5fc02a521..d13ce4dca 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -8,6 +8,7 @@ #include #include "audio_core/audio_renderer.h" #include "core/core.h" +#include "core/file_sys/savedata_factory.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -865,8 +866,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, {24, nullptr, "GetLaunchStorageInfoForDebug"}, - {25, nullptr, "ExtendSaveData"}, - {26, nullptr, "GetSaveDataSize"}, + {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, + {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, @@ -1043,6 +1044,48 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { rb.Push(0); } +void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw()}; + const auto new_normal_size{rp.PopRaw()}; + const auto new_journal_size{rp.PopRaw()}; + + LOG_DEBUG(Service_AM, + "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " + "new_journal={:016X}", + static_cast(type), user_id[1], user_id[0], new_normal_size, new_journal_size); + + FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id, + {new_normal_size, new_journal_size}); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + + // The following value is used upon failure to help the system recover. + // Since we always succeed, this should be 0. + rb.Push(0); +} + +void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw()}; + + LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast(type), + user_id[1], user_id[0]); + + const auto size = + FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.Push(size.normal); + rb.Push(size.journal); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr nvflinger) { auto message_queue = std::make_shared(); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 34c45fadf..b6113cfdd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -206,6 +206,8 @@ private: void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); void NotifyRunning(Kernel::HLERequestContext& ctx); void GetPseudoDeviceId(Kernel::HLERequestContext& ctx); + void ExtendSaveData(Kernel::HLERequestContext& ctx); + void GetSaveDataSize(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_general.cpp index 5ca493b6d..dffaba5ed 100644 --- a/src/yuzu/configuration/configure_per_general.cpp +++ b/src/yuzu/configuration/configure_per_general.cpp @@ -108,9 +108,9 @@ void ConfigurePerGameGeneral::loadConfiguration() { if (loader->ReadTitle(title) == Loader::ResultStatus::Success) ui->display_name->setText(QString::fromStdString(title)); - std::string developer; - if (loader->ReadDeveloper(developer) == Loader::ResultStatus::Success) - ui->display_developer->setText(QString::fromStdString(developer)); + FileSys::NACP nacp; + if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) + ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName())); ui->display_version->setText(QStringLiteral("1.0.0")); }