From 2e8177f0c93768e1d1a7d6a830e9c68111c2afd6 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Oct 2018 14:58:09 -0400 Subject: fsp_srv: Implement command 61: OpenSaveDataInfoReaderBySaveDataSpaceId Needed by Checkpoint. Returns an object that can iterate through all savedata on the system. --- src/core/hle/service/filesystem/fsp_srv.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service/filesystem/fsp_srv.cpp') diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c1c83a11d..56102a3db 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -452,6 +452,7 @@ private: }; FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { + // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "MountContent"}, {1, &FSP_SRV::Initialize, "Initialize"}, @@ -485,7 +486,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {58, nullptr, "ReadSaveDataFileSystemExtraData"}, {59, nullptr, "WriteSaveDataFileSystemExtraData"}, {60, nullptr, "OpenSaveDataInfoReader"}, - {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, + {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, {62, nullptr, "OpenCacheStorageList"}, {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, {65, nullptr, "UpdateSaveDataMacForDebug"}, @@ -544,6 +545,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {1009, nullptr, "GetAndClearMemoryReportInfo"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, }; + // clang-format on RegisterHandlers(functions); } @@ -618,6 +620,15 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { MountSaveData(ctx); } +void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto space = rp.PopRaw(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::make_shared(space)); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); -- cgit v1.2.3 From 5ee19add1bf221bd5259e4df76089252f04ce060 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Oct 2018 14:59:17 -0400 Subject: fsp_srv: Implement ISaveDataInfoReader An object to read SaveDataInfo objects, which describe a unique save on the system. This implementation iterates through all the directories in the save data space and uses the paths to reconstruct the metadata. --- src/core/hle/service/filesystem/fsp_srv.cpp | 144 ++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) (limited to 'src/core/hle/service/filesystem/fsp_srv.cpp') diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 56102a3db..3d1c2ecda 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -11,6 +11,7 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/hex_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/directory.h" @@ -451,6 +452,149 @@ private: VfsDirectoryServiceWrapper backend; }; +class ISaveDataInfoReader final : public ServiceFramework { +public: + explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) + : ServiceFramework("ISaveDataInfoReader") { + static const FunctionInfo functions[] = { + {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, + }; + RegisterHandlers(functions); + + FindAllSaves(space); + } + + void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast(info.data() + next_entry_index); + const auto* end = reinterpret_cast(info.data() + next_entry_index + actual_entries); + const auto range_size = static_cast(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(actual_entries); + } + +private: + static u64 stoull_be(std::string_view str) { + if (str.size() != 16) + return 0; + + const auto bytes = Common::HexStringToArray<0x8>(str); + u64 out{}; + std::memcpy(&out, bytes.data(), sizeof(u64)); + + return Common::swap64(out); + } + + static std::array ArraySwap(const std::array& in) { + std::array out; + for (std::size_t i = 0; i < in.size(); ++i) { + out[0xF - i] = in[i]; + } + + return out; + } + + void FindAllSaves(FileSys::SaveDataSpaceId space) { + const auto save_root = OpenSaveDataSpace(space); + ASSERT(save_root.Succeeded()); + + for (const auto& type : (*save_root)->GetSubdirectories()) { + if (type->GetName() == "save") { + for (const auto& save_id : type->GetSubdirectories()) { + for (const auto& user_id : save_id->GetSubdirectories()) { + const auto save_id_numeric = stoull_be(save_id->GetName()); + const auto user_id_numeric = + ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName())); + if (save_id_numeric != 0) { + // System Save Data + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::SystemSaveData, + {}, + user_id_numeric, + save_id_numeric, + 0, + user_id->GetSize(), + {}, + }); + + continue; + } + + for (const auto& title_id : user_id->GetSubdirectories()) { + const auto device = + std::all_of(user_id_numeric.begin(), user_id_numeric.end(), + [](u8 val) { return val == 0; }); + info.emplace_back(SaveDataInfo{ + 0, + space, + device ? FileSys::SaveDataType::DeviceSaveData + : FileSys::SaveDataType::SaveData, + {}, + user_id_numeric, + save_id_numeric, + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + }); + } + } + } + } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { + // Temporary Storage + for (const auto& user_id : type->GetSubdirectories()) { + for (const auto& title_id : user_id->GetSubdirectories()) { + if (!title_id->GetFiles().empty() || + !title_id->GetSubdirectories().empty()) { + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::TemporaryStorage, + {}, + Common::HexStringToArray<0x10, true>(user_id->GetName()), + stoull_be(type->GetName()), + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + }); + } + } + } + } + } + } + + struct SaveDataInfo { + u64_le save_id_unknown; + FileSys::SaveDataSpaceId space; + FileSys::SaveDataType type; + INSERT_PADDING_BYTES(0x6); + std::array user_id; + u64_le save_id; + u64_le title_id; + u64_le save_image_size; + INSERT_PADDING_BYTES(0x28); + }; + static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); + + std::vector info; + u64 next_entry_index = 0; +}; + FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { // clang-format off static const FunctionInfo functions[] = { -- cgit v1.2.3 From bdaa76c0dbcf6811ae83bbca61ae103e06e93c27 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 29 Oct 2018 16:20:10 -0400 Subject: ns: Implement command 400: GetApplicationControlData Returns the raw NACP bytes and the raw icon bytes into a title-provided buffer. Pulls from Registration Cache for control data, returning all zeros should it not exist. --- src/core/hle/service/filesystem/fsp_srv.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'src/core/hle/service/filesystem/fsp_srv.cpp') diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 3d1c2ecda..b9a1d5105 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -481,9 +481,9 @@ public: // Write the data to memory ctx.WriteBuffer(begin, range_size); - IPC::ResponseBuilder rb{ctx, 4}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(actual_entries); + rb.Push(static_cast(actual_entries)); } private: @@ -498,15 +498,6 @@ private: return Common::swap64(out); } - static std::array ArraySwap(const std::array& in) { - std::array out; - for (std::size_t i = 0; i < in.size(); ++i) { - out[0xF - i] = in[i]; - } - - return out; - } - void FindAllSaves(FileSys::SaveDataSpaceId space) { const auto save_root = OpenSaveDataSpace(space); ASSERT(save_root.Succeeded()); @@ -516,8 +507,9 @@ private: for (const auto& save_id : type->GetSubdirectories()) { for (const auto& user_id : save_id->GetSubdirectories()) { const auto save_id_numeric = stoull_be(save_id->GetName()); - const auto user_id_numeric = - ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName())); + auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + if (save_id_numeric != 0) { // System Save Data info.emplace_back(SaveDataInfo{ @@ -560,12 +552,16 @@ private: for (const auto& title_id : user_id->GetSubdirectories()) { if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) { + auto user_id_numeric = + Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + info.emplace_back(SaveDataInfo{ 0, space, FileSys::SaveDataType::TemporaryStorage, {}, - Common::HexStringToArray<0x10, true>(user_id->GetName()), + user_id_numeric, stoull_be(type->GetName()), stoull_be(title_id->GetName()), title_id->GetSize(), -- cgit v1.2.3