From 37cb18358b2002526f6674f8986635e21a6733a9 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 9 Dec 2017 00:16:51 -0500 Subject: [PATCH 1/2] HLE/FS: Always use 0x48000 as the high dword when opening the SharedExtData archive The FS module overrides whatever value was in the saveid high dword with 0x48000 when trying to open the archive. This fixes the problem where the Home Menu would create a few SharedExtData archives with 0x48000 as the saveid high, but then try to open them with 0 as the high value and fail. --- src/core/file_sys/archive_extsavedata.cpp | 37 ++++++++++++++++++++--- src/core/file_sys/archive_extsavedata.h | 3 ++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index e401be507..9cab0d0f7 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -131,6 +131,14 @@ public: } }; +struct ExtSaveDataArchivePath { + u32_le media_type; + u32_le save_low; + u32_le save_high; +}; + +static_assert(sizeof(ExtSaveDataArchivePath) == 12, "Incorrect path size"); + std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) { std::vector vec_data = path.AsBinary(); const u32* data = reinterpret_cast(vec_data.data()); @@ -183,8 +191,27 @@ bool ArchiveFactory_ExtSaveData::Initialize() { return true; } +Path ArchiveFactory_ExtSaveData::GetCorrectedPath(const Path& path) { + if (!shared) + return path; + + static constexpr u32 SharedExtDataHigh = 0x48000; + + ExtSaveDataArchivePath new_path; + std::memcpy(&new_path, path.AsBinary().data(), sizeof(new_path)); + + // The FS module overwrites the high value of the saveid when dealing with the SharedExtSaveData + // archive. + new_path.save_high = SharedExtDataHigh; + + std::vector binary_data(sizeof(new_path)); + std::memcpy(binary_data.data(), &new_path, binary_data.size()); + + return {binary_data}; +} + ResultVal> ArchiveFactory_ExtSaveData::Open(const Path& path) { - std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; + std::string fullpath = GetExtSaveDataPath(mount_point, GetCorrectedPath(path)) + "user/"; if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData. // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist. @@ -200,14 +227,16 @@ ResultVal> ArchiveFactory_ExtSaveData::Open(cons ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { + auto corrected_path = GetCorrectedPath(path); + // These folders are always created with the ExtSaveData - std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; - std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; + std::string user_path = GetExtSaveDataPath(mount_point, corrected_path) + "user/"; + std::string boss_path = GetExtSaveDataPath(mount_point, corrected_path) + "boss/"; FileUtil::CreateFullPath(user_path); FileUtil::CreateFullPath(boss_path); // Write the format metadata - std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; + std::string metadata_path = GetExtSaveDataPath(mount_point, corrected_path) + "metadata"; FileUtil::IOFile file(metadata_path, "wb"); if (!file.IsOpen()) { diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index f705ade1c..19814b5a0 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -56,6 +56,9 @@ private: * See GetExtSaveDataPath for the code that extracts this data from an archive path. */ std::string mount_point; + + /// Returns a path with the correct SaveIdHigh value for Shared extdata paths. + Path GetCorrectedPath(const Path& path); }; /** From b54e278eeb404f757876ce30ab9df21a0c0320a0 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 9 Dec 2017 00:17:43 -0500 Subject: [PATCH 2/2] FS/ExtData: Use the ExtSaveDataArchivePath structure instead of reinterpret_cast. --- src/core/file_sys/archive_extsavedata.cpp | 31 +++++++++-------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 9cab0d0f7..77a735292 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -141,10 +141,12 @@ static_assert(sizeof(ExtSaveDataArchivePath) == 12, "Incorrect path size"); std::string GetExtSaveDataPath(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]; - u32 save_high = data[2]; - return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_high, save_low); + + ExtSaveDataArchivePath path_data; + std::memcpy(&path_data, vec_data.data(), sizeof(path_data)); + + return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), path_data.save_high, + path_data.save_low); } std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { @@ -156,22 +158,13 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) } Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { - std::vector binary_path; - binary_path.reserve(12); + ExtSaveDataArchivePath path; + path.media_type = media_type; + path.save_high = high; + path.save_low = low; - // 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); + std::vector binary_path(sizeof(path)); + std::memcpy(binary_path.data(), &path, binary_path.size()); return {binary_path}; }