From 1d61cd446016badb1dd218a2a4692b1e5e3eeb14 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 14 Mar 2015 12:00:01 -0500 Subject: [PATCH 1/2] Services/FS: Implemented DeleteExtSaveData, CreateSystemSaveData and DeleteSystemSaveData Also fixed a bug with CreateExtSaveData that made it unable to create ExtSaveData archives in the SDMC directory. --- src/core/file_sys/archive_extsavedata.cpp | 21 +++++ src/core/file_sys/archive_extsavedata.h | 10 +++ src/core/file_sys/archive_systemsavedata.cpp | 22 +++++- src/core/file_sys/archive_systemsavedata.h | 25 ++++++ src/core/hle/service/fs/archive.cpp | 74 ++++++++++++++---- src/core/hle/service/fs/archive.h | 34 ++++++++- src/core/hle/service/fs/fs_user.cpp | 80 ++++++++++++++++++-- 7 files changed, 240 insertions(+), 26 deletions(-) diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 0363c9771c..3076fa2630 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -34,6 +34,27 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } +Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { + std::vector binary_path; + binary_path.reserve(12); + + // Append each word byte by byte + + // The first word is the media type + for (unsigned i = 0; i < 4; ++i) + binary_path.push_back((media_type >> (8 * i)) & 0xFF); + + // Next is the low word + for (unsigned i = 0; i < 4; ++i) + binary_path.push_back((low >> (8 * i)) & 0xFF); + + // Next is the high word + for (unsigned i = 0; i < 4; ++i) + binary_path.push_back((high >> (8 * i)) & 0xFF); + + return { binary_path }; +} + ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared) : mount_point(GetExtDataContainerPath(mount_location, shared)) { LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index 83c6b02911..c77c04e440 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -58,4 +58,14 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) */ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared); +/** + * Constructs a FileSys::Path object that refers to the ExtData archive identified by + * the specified media type, high save id and low save id. + * @param media_type The media type where the archive is located (NAND / SDMC) + * @param high The high word of the save id for the archive + * @param low The low word of the save id for the archive + * @returns A FileSys::Path to the wanted archive + */ +Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low); + } // namespace FileSys diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 25c94cd268..4fe785c975 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -17,7 +17,7 @@ namespace FileSys { -static std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { +std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { std::vector vec_data = path.AsBinary(); const u32* data = reinterpret_cast(vec_data.data()); u32 save_low = data[1]; @@ -25,10 +25,27 @@ static std::string GetSystemSaveDataPath(const std::string& mount_point, const P return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high); } -static std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { +std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str()); } +Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { + std::vector binary_path; + binary_path.reserve(8); + + // Append each word byte by byte + + // First is the high word + for (unsigned i = 0; i < 4; ++i) + binary_path.push_back((high >> (8 * i)) & 0xFF); + + // Next is the low word + for (unsigned i = 0; i < 4; ++i) + binary_path.push_back((low >> (8 * i)) & 0xFF); + + return { binary_path }; +} + ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) : base_path(GetSystemSaveDataContainerPath(nand_path)) { } @@ -46,6 +63,7 @@ ResultVal> ArchiveFactory_SystemSaveData::Open(c ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { std::string fullpath = GetSystemSaveDataPath(base_path, path); + FileUtil::DeleteDirRecursively(fullpath); FileUtil::CreateFullPath(fullpath); return RESULT_SUCCESS; } diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index 556a2a4880..3431fed880 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h @@ -28,4 +28,29 @@ private: std::string base_path; }; +/** + * Constructs a path to the concrete SystemSaveData archive in the host filesystem based on the + * input Path and base mount point. + * @param mount_point The base mount point of the SystemSaveData archives. + * @param path The path that identifies the requested concrete SystemSaveData archive. + * @returns The complete path to the specified SystemSaveData archive in the host filesystem + */ +std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path); + +/** + * Constructs a path to the base folder to hold concrete SystemSaveData archives in the host file system. + * @param mount_point The base folder where this folder resides, ie. SDMC or NAND. + * @returns The path to the base SystemSaveData archives' folder in the host file system + */ +std::string GetSystemSaveDataContainerPath(const std::string& mount_point); + +/** + * Constructs a FileSys::Path object that refers to the SystemSaveData archive identified by + * the specified high save id and low save id. + * @param high The high word of the save id for the archive + * @param low The low word of the save id for the archive + * @returns A FileSys::Path to the wanted archive + */ +Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low); + } // namespace FileSys diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 9da2e7aa2d..b0fd834c77 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -395,28 +395,72 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { return archive_itr->second->Format(path); } -ResultCode CreateExtSaveData(u32 high, u32 low) { +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { // Construct the binary path to the archive first - std::vector binary_path; - binary_path.reserve(12); - // The first word is all zero to specify a NAND archive - for (unsigned i = 0; i < 4; ++i) - binary_path.push_back(0); - // Next is the low word - for (unsigned i = 0; i < 4; ++i) - binary_path.push_back((low >> (8 * i)) & 0xFF); - // Next is the high word - for (unsigned i = 0; i < 4; ++i) - binary_path.push_back((high >> i) & 0xFF); - FileSys::Path path(binary_path); - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - std::string base_path = FileSys::GetExtDataContainerPath(nand_directory, true); + FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast(media_type), high, low); + + std::string media_type_directory; + if (media_type == MediaType::NAND) { + media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); + } else if (media_type == MediaType::SDMC) { + media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX); + } else { + LOG_ERROR(Service_FS, "Unsupported media type %u", media_type); + return ResultCode(-1); // TODO(Subv): Find the right error code + } + + std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); if (!FileUtil::CreateFullPath(extsavedata_path)) return ResultCode(-1); // TODO(Subv): Find the right error code return RESULT_SUCCESS; } +ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { + // Construct the binary path to the archive first + FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast(media_type), high, low); + + std::string media_type_directory; + if (media_type == MediaType::NAND) { + media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); + } else if (media_type == MediaType::SDMC) { + media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX); + } else { + LOG_ERROR(Service_FS, "Unsupported media type %u", media_type); + return ResultCode(-1); // TODO(Subv): Find the right error code + } + + std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); + std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); + if (!FileUtil::DeleteDirRecursively(extsavedata_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + return RESULT_SUCCESS; +} + +ResultCode DeleteSystemSaveData(u32 high, u32 low) { + // Construct the binary path to the archive first + FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); + + std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); + std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); + if (!FileUtil::DeleteDirRecursively(systemsavedata_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + return RESULT_SUCCESS; +} + +ResultCode CreateSystemSaveData(u32 high, u32 low) { + // Construct the binary path to the archive first + FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); + + std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); + std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); + if (!FileUtil::CreateFullPath(systemsavedata_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + return RESULT_SUCCESS; +} + /// Initialize archives void ArchiveInit() { next_handle = 1; diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index c490327d02..b00f0fd607 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -35,6 +35,12 @@ enum class ArchiveIdCode : u32 { SaveDataCheck = 0x2345678A, }; +/// Media types for the archives +enum class MediaType : u32 { + NAND = 0, + SDMC = 1 +}; + typedef u64 ArchiveHandle; class File : public Kernel::Session { @@ -172,11 +178,37 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File /** * Creates a blank SharedExtSaveData archive for the specified extdata ID + * @param media_type The media type of the archive to create (NAND / SDMC) * @param high The high word of the extdata id to create * @param low The low word of the extdata id to create * @return ResultCode 0 on success or the corresponding code on error */ -ResultCode CreateExtSaveData(u32 high, u32 low); +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low); + +/** + * Deletes the SharedExtSaveData archive for the specified extdata ID + * @param media_type The media type of the archive to delete (NAND / SDMC) + * @param high The high word of the extdata id to delete + * @param low The low word of the extdata id to delete + * @return ResultCode 0 on success or the corresponding code on error + */ +ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low); + +/** + * Deletes the SystemSaveData archive folder for the specified save data id + * @param high The high word of the SystemSaveData archive to delete + * @param low The low word of the SystemSaveData archive to delete + * @return ResultCode 0 on success or the corresponding code on error + */ +ResultCode DeleteSystemSaveData(u32 high, u32 low); + +/** + * Creates the SystemSaveData archive folder for the specified save data id + * @param high The high word of the SystemSaveData archive to create + * @param low The low word of the SystemSaveData archive to create + * @return ResultCode 0 on success or the corresponding code on error + */ +ResultCode CreateSystemSaveData(u32 high, u32 low); /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index eb312496ef..02458a00b8 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -490,25 +490,45 @@ static void FormatThisUserSaveData(Service::Interface* self) { /** * FS_User::CreateExtSaveData service function * Inputs: - * 0: 0x08510242 - * 1: High word of the saveid to create - * 2: Low word of the saveid to create + * 0 : 0x08510242 + * 1 : Media type (NAND / SDMC) + * 2 : Low word of the saveid to create + * 3 : High word of the saveid to create * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ static void CreateExtSaveData(Service::Interface* self) { // TODO(Subv): Figure out the other parameters. u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 save_high = cmd_buff[1]; + MediaType media_type = static_cast(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; - // TODO(Subv): For now it is assumed that only SharedExtSaveData can be created like this - cmd_buff[1] = CreateExtSaveData(save_high, save_low).raw; + u32 save_high = cmd_buff[3]; + cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; +} + +/** + * FS_User::DeleteExtSaveData service function + * Inputs: + * 0 : 0x08520100 + * 1 : Media type (NAND / SDMC) + * 2 : Low word of the saveid to create + * 3 : High word of the saveid to create + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void DeleteExtSaveData(Service::Interface* self) { + // TODO(Subv): Figure out the other parameters. + u32* cmd_buff = Kernel::GetCommandBuffer(); + MediaType media_type = static_cast(cmd_buff[1] & 0xFF); + u32 save_low = cmd_buff[2]; + u32 save_high = cmd_buff[3]; + cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; } /** * FS_User::CardSlotIsInserted service function. * Inputs: - * 0: 0x08210000 + * 0 : 0x08210000 * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 2 : Whether there is a game card inserted into the slot or not. @@ -520,6 +540,48 @@ static void CardSlotIsInserted(Service::Interface* self) { LOG_WARNING(Service_FS, "(STUBBED) called"); } +/** + * FS_User::DeleteSystemSaveData service function. + * Inputs: + * 0 : 0x08570080 + * 1 : High word of the SystemSaveData id to delete + * 2 : Low word of the SystemSaveData id to delete + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void DeleteSystemSaveData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 savedata_high = cmd_buff[1]; + u32 savedata_low = cmd_buff[2]; + + cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw; +} + +/** + * FS_User::CreateSystemSaveData service function. + * Inputs: + * 0 : 0x08560240 + * 1 : High word of the SystemSaveData id to create + * 2 : Low word of the SystemSaveData id to create + * 3 : Unknown + * 4 : Unknown + * 5 : Unknown + * 6 : Unknown + * 7 : Unknown + * 8 : Unknown + * 9 : Unknown (Memory address) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void CreateSystemSaveData(Service::Interface* self) { + // TODO(Subv): Figure out the other parameters. + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 savedata_high = cmd_buff[1]; + u32 savedata_low = cmd_buff[2]; + + cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw; +} + const Interface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, @@ -604,7 +666,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x084F0102, nullptr, "ReadSpecialFile"}, {0x08500040, nullptr, "GetSpecialFileSize"}, {0x08510242, CreateExtSaveData, "CreateExtSaveData"}, - {0x08520100, nullptr, "DeleteExtSaveData"}, + {0x08520100, DeleteExtSaveData, "DeleteExtSaveData"}, + {0x08560240, CreateSystemSaveData, "CreateSystemSaveData"}, + {0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"}, {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, {0x08610042, nullptr, "InitializeWithSdkVersion"}, {0x08620040, nullptr, "SetPriority"}, From b9612fe9195206ab9920d697b6b20e23db8a5be4 Mon Sep 17 00:00:00 2001 From: Subv Date: Thu, 19 Mar 2015 17:39:00 -0500 Subject: [PATCH 2/2] Service/FS: Document and log some unknown values. In CreateExtSaveData, DeleteExtSaveData and CreateSystemSaveData --- src/core/hle/service/fs/fs_user.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 02458a00b8..d8d1d55475 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -494,6 +494,14 @@ static void FormatThisUserSaveData(Service::Interface* self) { * 1 : Media type (NAND / SDMC) * 2 : Low word of the saveid to create * 3 : High word of the saveid to create + * 4 : Unknown + * 5 : Unknown + * 6 : Unknown + * 7 : Unknown + * 8 : Unknown + * 9 : Unknown + * 10: Unknown + * 11: Unknown * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ @@ -503,6 +511,13 @@ static void CreateExtSaveData(Service::Interface* self) { MediaType media_type = static_cast(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; u32 save_high = cmd_buff[3]; + + LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " + "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " + "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, + cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], + cmd_buff[10], cmd_buff[11]); + cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; } @@ -513,15 +528,20 @@ static void CreateExtSaveData(Service::Interface* self) { * 1 : Media type (NAND / SDMC) * 2 : Low word of the saveid to create * 3 : High word of the saveid to create + * 4 : Unknown * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ static void DeleteExtSaveData(Service::Interface* self) { - // TODO(Subv): Figure out the other parameters. u32* cmd_buff = Kernel::GetCommandBuffer(); MediaType media_type = static_cast(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; u32 save_high = cmd_buff[3]; + u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is + + LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", + save_low, save_high, cmd_buff[1] & 0xFF, unknown); + cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; } @@ -579,6 +599,11 @@ static void CreateSystemSaveData(Service::Interface* self) { u32 savedata_high = cmd_buff[1]; u32 savedata_low = cmd_buff[2]; + LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " + "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " + "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5], + cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]); + cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw; }