diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 00207aff17..a8d72b96a8 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -356,6 +356,11 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) case IOCTL_ES_GETSTOREDCONTENTS: return GetTMDStoredContents(request); + case IOCTL_ES_GETSHAREDCONTENTCNT: + return GetSharedContentsCount(request); + case IOCTL_ES_GETSHAREDCONTENTS: + return GetSharedContents(request); + case IOCTL_ES_GETVIEWCNT: return GetTicketViewCount(request); case IOCTL_ES_GETVIEWS: diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index b0f7f25b8f..9c49d7fcd7 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -214,6 +214,8 @@ private: IPCCommandResult GetTMDStoredContents(const IOCtlVRequest& request); IPCCommandResult GetStoredTMDSize(const IOCtlVRequest& request); IPCCommandResult GetStoredTMD(const IOCtlVRequest& request); + IPCCommandResult GetSharedContentsCount(const IOCtlVRequest& request) const; + IPCCommandResult GetSharedContents(const IOCtlVRequest& request) const; // Views for tickets and TMDs IPCCommandResult GetTicketViewCount(const IOCtlVRequest& request); diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index bab82dada1..e4da96e2d0 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -385,6 +385,16 @@ std::string SharedContentMap::GetFilenameFromSHA1(const std::array& sha1 return Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id_string.c_str()); } +std::vector> SharedContentMap::GetHashes() const +{ + std::vector> hashes; + hashes.reserve(m_entries.size()); + for (const auto& content_entry : m_entries) + hashes.emplace_back(content_entry.sha1); + + return hashes; +} + std::string SharedContentMap::AddSharedContent(const std::array& sha1) { std::string filename = GetFilenameFromSHA1(sha1); diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index a994ff8bc2..d073544ad1 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -204,6 +204,7 @@ public: std::string GetFilenameFromSHA1(const std::array& sha1) const; std::string AddSharedContent(const std::array& sha1); + std::vector> GetHashes() const; private: struct Entry; diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index 3163852e79..7d60f5c5e6 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -163,6 +163,23 @@ std::vector GetStoredContentsFromTMD(const TMDReader& tmd) return stored_contents; } +u32 GetSharedContentsCount() +{ + const std::string shared1_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/shared1"; + const auto entries = File::ScanDirectoryTree(shared1_path, false); + return static_cast( + std::count_if(entries.children.begin(), entries.children.end(), [](const auto& entry) { + return !entry.isDirectory && entry.virtualName.size() == 12 && + entry.virtualName.compare(8, 4, ".app") == 0; + })); +} + +std::vector> GetSharedContents() +{ + const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; + return map.GetHashes(); +} + bool InitImport(u64 title_id) { const std::string content_dir = Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT); diff --git a/Source/Core/Core/IOS/ES/NandUtils.h b/Source/Core/Core/IOS/ES/NandUtils.h index eb78475291..3135ebc490 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.h +++ b/Source/Core/Core/IOS/ES/NandUtils.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -27,6 +28,9 @@ std::vector GetTitlesWithTickets(); std::vector GetStoredContentsFromTMD(const TMDReader& tmd); +u32 GetSharedContentsCount(); +std::vector> GetSharedContents(); + // Start a title import. bool InitImport(u64 title_id); // Clean up the import content directory and move it back to /title. diff --git a/Source/Core/Core/IOS/ES/TitleInformation.cpp b/Source/Core/Core/IOS/ES/TitleInformation.cpp index 200444c474..085174dbd5 100644 --- a/Source/Core/Core/IOS/ES/TitleInformation.cpp +++ b/Source/Core/Core/IOS/ES/TitleInformation.cpp @@ -205,6 +205,35 @@ IPCCommandResult ES::GetBoot2Version(const IOCtlVRequest& request) Memory::Write_U32(4, request.io_vectors[0].address); return GetDefaultReply(IPC_SUCCESS); } + +IPCCommandResult ES::GetSharedContentsCount(const IOCtlVRequest& request) const +{ + if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32)) + return GetDefaultReply(ES_EINVAL); + + const u32 count = IOS::ES::GetSharedContentsCount(); + Memory::Write_U32(count, request.io_vectors[0].address); + + INFO_LOG(IOS_ES, "GetSharedContentsCount: %u contents", count); + return GetDefaultReply(IPC_SUCCESS); +} + +IPCCommandResult ES::GetSharedContents(const IOCtlVRequest& request) const +{ + if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32)) + return GetDefaultReply(ES_EINVAL); + + const u32 max_count = Memory::Read_U32(request.in_vectors[0].address); + if (request.io_vectors[0].size != 20 * max_count) + return GetDefaultReply(ES_EINVAL); + + const std::vector> hashes = IOS::ES::GetSharedContents(); + const u32 count = std::min(static_cast(hashes.size()), max_count); + Memory::CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count); + + INFO_LOG(IOS_ES, "GetSharedContents: %u contents (%u requested)", count, max_count); + return GetDefaultReply(IPC_SUCCESS); +} } // namespace Device } // namespace HLE } // namespace IOS