From 7b17163a7adf398c948fbcd9e6ff078e616c8edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 13 Mar 2017 12:33:50 +0100 Subject: [PATCH] IOS/ES: Move shared content map, uid.sys code These are all specific to ES and belong there. The SharedContentMap and UIDSys classes were also modernised. --- Source/Core/Core/IOS/ES/ES.cpp | 2 +- Source/Core/Core/IOS/ES/Formats.cpp | 130 ++++++++++++++++++ Source/Core/Core/IOS/ES/Formats.h | 32 +++++ Source/Core/Core/IOS/ES/NandUtils.cpp | 5 +- Source/Core/Core/IOS/ES/TitleManagement.cpp | 8 +- Source/Core/DiscIO/NANDContentLoader.cpp | 139 +------------------- Source/Core/DiscIO/NANDContentLoader.h | 46 ------- 7 files changed, 176 insertions(+), 186 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 4ef6020020..5f2eb983ec 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -494,7 +494,7 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic if (!tmd_file.WriteBytes(tmd_bytes.data(), tmd_bytes.size())) ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND."); } - DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; + IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; uid_sys.AddTitle(tmd.GetTitleId()); // DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager. // clear the cache to avoid content access mismatches. diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index ab24da1002..bab82dada1 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -13,9 +13,12 @@ #include #include +#include "Common/Assert.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Crypto/AES.h" +#include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/ec_wii.h" @@ -345,5 +348,132 @@ s32 TicketReader::Unpersonalise() std::copy(key.cbegin(), key.cend(), ticket_begin + offsetof(Ticket, title_key)); return IOSC_OK; } + +struct SharedContentMap::Entry +{ + // ID string + std::array id; + // Binary SHA1 hash + std::array sha1; +}; + +SharedContentMap::SharedContentMap(Common::FromWhichRoot root) : m_root(root) +{ + static_assert(sizeof(Entry) == 28, "SharedContentMap::Entry has the wrong size"); + + m_file_path = Common::RootUserPath(root) + "/shared1/content.map"; + + File::IOFile file(m_file_path, "rb"); + Entry entry; + while (file.ReadArray(&entry, 1)) + { + m_entries.push_back(entry); + m_last_id++; + } +} + +SharedContentMap::~SharedContentMap() = default; + +std::string SharedContentMap::GetFilenameFromSHA1(const std::array& sha1) const +{ + const auto it = std::find_if(m_entries.begin(), m_entries.end(), + [&sha1](const auto& entry) { return entry.sha1 == sha1; }); + if (it == m_entries.end()) + return "unk"; + + const std::string id_string(it->id.begin(), it->id.end()); + return Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id_string.c_str()); +} + +std::string SharedContentMap::AddSharedContent(const std::array& sha1) +{ + std::string filename = GetFilenameFromSHA1(sha1); + if (filename != "unk") + return filename; + + const std::string id = StringFromFormat("%08x", m_last_id); + Entry entry; + std::copy(id.cbegin(), id.cend(), entry.id.begin()); + entry.sha1 = sha1; + m_entries.push_back(entry); + + File::CreateFullPath(m_file_path); + + File::IOFile file(m_file_path, "ab"); + file.WriteArray(&entry, 1); + + filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str()); + m_last_id++; + return filename; +} + +static std::pair ReadUidSysEntry(File::IOFile& file) +{ + u64 title_id = 0; + if (!file.ReadBytes(&title_id, sizeof(title_id))) + return {}; + + u32 uid = 0; + if (!file.ReadBytes(&uid, sizeof(uid))) + return {}; + + return {Common::swap32(uid), Common::swap64(title_id)}; +} + +UIDSys::UIDSys(Common::FromWhichRoot root) +{ + m_file_path = Common::RootUserPath(root) + "/sys/uid.sys"; + + File::IOFile file(m_file_path, "rb"); + while (true) + { + const std::pair entry = ReadUidSysEntry(file); + if (!entry.first && !entry.second) + break; + + m_entries.insert(std::move(entry)); + } + + if (m_entries.empty()) + { + AddTitle(TITLEID_SYSMENU); + } +} + +u32 UIDSys::GetUIDFromTitle(u64 title_id) +{ + const auto it = std::find_if(m_entries.begin(), m_entries.end(), + [title_id](const auto& entry) { return entry.second == title_id; }); + return (it == m_entries.end()) ? 0 : it->first; +} + +u32 UIDSys::GetNextUID() const +{ + if (m_entries.empty()) + return 0x00001000; + return m_entries.rbegin()->first + 1; +} + +void UIDSys::AddTitle(u64 title_id) +{ + if (GetUIDFromTitle(title_id)) + { + INFO_LOG(IOS_ES, "Title %016" PRIx64 " already exists in uid.sys", title_id); + return; + } + + u32 uid = GetNextUID(); + m_entries.insert({uid, title_id}); + + // Byte swap before writing. + title_id = Common::swap64(title_id); + uid = Common::swap32(uid); + + File::CreateFullPath(m_file_path); + File::IOFile file(m_file_path, "ab"); + + if (!file.WriteBytes(&title_id, sizeof(title_id)) || !file.WriteBytes(&uid, sizeof(uid))) + ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys"); +} } // namespace ES } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 740c2f7646..a994ff8bc2 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -13,6 +13,7 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" +#include "Common/NandPaths.h" #include "DiscIO/Enums.h" namespace IOS @@ -194,5 +195,36 @@ public: private: std::vector m_bytes; }; + +class SharedContentMap final +{ +public: + explicit SharedContentMap(Common::FromWhichRoot root); + ~SharedContentMap(); + + std::string GetFilenameFromSHA1(const std::array& sha1) const; + std::string AddSharedContent(const std::array& sha1); + +private: + struct Entry; + Common::FromWhichRoot m_root; + u32 m_last_id = 0; + std::string m_file_path; + std::vector m_entries; +}; + +class UIDSys final +{ +public: + explicit UIDSys(Common::FromWhichRoot root); + + u32 GetUIDFromTitle(u64 title_id); + void AddTitle(u64 title_id); + u32 GetNextUID() const; + +private: + std::string m_file_path; + std::map m_entries; +}; } // namespace ES } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index b30609a255..51576d9c4e 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -15,7 +15,6 @@ #include "Common/StringUtil.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/ES/NandUtils.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { @@ -142,7 +141,7 @@ std::vector GetStoredContentsFromTMD(const TMDReader& tmd) if (!tmd.IsValid()) return {}; - const DiscIO::CSharedContent shared{Common::FROM_SESSION_ROOT}; + const IOS::ES::SharedContentMap shared{Common::FROM_SESSION_ROOT}; const std::vector contents = tmd.GetContents(); std::vector stored_contents; @@ -151,7 +150,7 @@ std::vector GetStoredContentsFromTMD(const TMDReader& tmd) [&tmd, &shared](const auto& content) { if (content.IsShared()) { - const std::string path = shared.GetFilenameFromSHA1(content.sha1.data()); + const std::string path = shared.GetFilenameFromSHA1(content.sha1); return path != "unk" && File::Exists(path); } return File::Exists( diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index dd327ee1cb..eaeee998e5 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -102,7 +102,7 @@ IPCCommandResult ES::AddTMD(const IOCtlVRequest& request) if (!m_addtitle_tmd.IsValid()) return GetDefaultReply(ES_INVALID_TMD); - DiscIO::cUIDsys uid_sys{Common::FROM_CONFIGURED_ROOT}; + IOS::ES::UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT}; uid_sys.AddTitle(m_addtitle_tmd.GetTitleId()); return GetDefaultReply(IPC_SUCCESS); @@ -124,7 +124,7 @@ IPCCommandResult ES::AddTitleStart(const IOCtlVRequest& request) return GetDefaultReply(ES_INVALID_TMD); } - DiscIO::cUIDsys uid_sys{Common::FROM_CONFIGURED_ROOT}; + IOS::ES::UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT}; uid_sys.AddTitle(m_addtitle_tmd.GetTitleId()); // TODO: check and use the other vectors. @@ -281,8 +281,8 @@ IPCCommandResult ES::AddTitleFinish(const IOCtlVRequest& request) std::string content_path; if (content_info.IsShared()) { - DiscIO::CSharedContent shared_content{Common::FROM_SESSION_ROOT}; - content_path = shared_content.AddSharedContent(content_info.sha1.data()); + IOS::ES::SharedContentMap shared_content{Common::FROM_SESSION_ROOT}; + content_path = shared_content.AddSharedContent(content_info.sha1); } else { diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 559fd86eb2..58594d6fc5 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -25,6 +25,8 @@ #include "Common/NandPaths.h" #include "Common/StringUtil.h" #include "Common/Swap.h" +// TODO: kill this dependency. +#include "Core/IOS/ES/Formats.h" #include "DiscIO/WiiWad.h" @@ -32,61 +34,6 @@ namespace DiscIO { CNANDContentData::~CNANDContentData() = default; -CSharedContent::CSharedContent(Common::FromWhichRoot root) : m_root(root) -{ - m_Elements.clear(); - m_LastID = 0; - m_ContentMap = Common::RootUserPath(root) + "/shared1/content.map"; - - File::IOFile pFile(m_ContentMap, "rb"); - SElement Element; - while (pFile.ReadArray(&Element, 1)) - { - m_Elements.push_back(Element); - m_LastID++; - } -} - -std::string CSharedContent::GetFilenameFromSHA1(const u8* hash) const -{ - for (const auto& Element : m_Elements) - { - if (memcmp(hash, Element.SHA1Hash, 20) == 0) - { - return StringFromFormat( - "%s/shared1/%c%c%c%c%c%c%c%c.app", Common::RootUserPath(m_root).c_str(), - Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3], - Element.FileName[4], Element.FileName[5], Element.FileName[6], Element.FileName[7]); - } - } - return "unk"; -} - -std::string CSharedContent::AddSharedContent(const u8* hash) -{ - std::string filename = GetFilenameFromSHA1(hash); - - if (strcasecmp(filename.c_str(), "unk") == 0) - { - std::string id = StringFromFormat("%08x", m_LastID); - SElement Element; - memcpy(Element.FileName, id.c_str(), 8); - memcpy(Element.SHA1Hash, hash, 20); - m_Elements.push_back(Element); - - File::CreateFullPath(m_ContentMap); - - File::IOFile pFile(m_ContentMap, "ab"); - pFile.WriteArray(&Element, 1); - - filename = - StringFromFormat("%s/shared1/%s.app", Common::RootUserPath(m_root).c_str(), id.c_str()); - m_LastID++; - } - - return filename; -} - CNANDContentDataFile::CNANDContentDataFile(const std::string& filename) : m_filename{filename} { } @@ -238,7 +185,7 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector& data_ap u32 data_app_offset = 0; const std::vector title_key = m_ticket.GetTitleKey(); - CSharedContent shared_content{Common::FromWhichRoot::FROM_SESSION_ROOT}; + IOS::ES::SharedContentMap shared_content{Common::FromWhichRoot::FROM_SESSION_ROOT}; for (size_t i = 0; i < contents.size(); ++i) { @@ -261,7 +208,7 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector& data_ap { std::string filename; if (content.IsShared()) - filename = shared_content.GetFilenameFromSHA1(content.sha1.data()); + filename = shared_content.GetFilenameFromSHA1(content.sha1); else filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.id); @@ -328,78 +275,6 @@ void CNANDContentLoader::RemoveTitle() const } } -cUIDsys::cUIDsys(Common::FromWhichRoot root) -{ - m_Elements.clear(); - m_LastUID = 0x00001000; - m_UidSys = Common::RootUserPath(root) + "/sys/uid.sys"; - - File::IOFile pFile(m_UidSys, "rb"); - SElement Element; - while (pFile.ReadArray(&Element, 1)) - { - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - m_Elements.push_back(Element); - } - pFile.Close(); - - if (m_Elements.empty()) - { - *(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU); - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - - File::CreateFullPath(m_UidSys); - pFile.Open(m_UidSys, "wb"); - if (!pFile.WriteArray(&Element, 1)) - ERROR_LOG(DISCIO, "Failed to write to %s", m_UidSys.c_str()); - } -} - -u32 cUIDsys::GetUIDFromTitle(u64 title_id) -{ - for (auto& Element : m_Elements) - { - if (Common::swap64(title_id) == *(u64*)&(Element.titleID)) - { - return Common::swap32(Element.UID); - } - } - return 0; -} - -void cUIDsys::AddTitle(u64 title_id) -{ - if (GetUIDFromTitle(title_id)) - { - INFO_LOG(DISCIO, "Title %08x%08x, already exists in uid.sys", (u32)(title_id >> 32), - (u32)title_id); - return; - } - - SElement Element; - *(u64*)&(Element.titleID) = Common::swap64(title_id); - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - m_Elements.push_back(Element); - - File::CreateFullPath(m_UidSys); - File::IOFile pFile(m_UidSys, "ab"); - - if (!pFile.WriteArray(&Element, 1)) - ERROR_LOG(DISCIO, "fwrite failed"); -} - -void cUIDsys::GetTitleIDs(std::vector& title_ids, bool owned) -{ - for (auto& Element : m_Elements) - { - if ((owned && - Common::CheckTitleTIK(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)) || - (!owned && - Common::CheckTitleTMD(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT))) - title_ids.push_back(Common::swap64(Element.titleID)); - } -} - u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) { if (filename.find(".wad") == std::string::npos) @@ -426,12 +301,12 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) const auto& raw_tmd = content_loader.GetTMD().GetRawTMD(); tmd_file.WriteBytes(raw_tmd.data(), raw_tmd.size()); - CSharedContent shared_content{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; + IOS::ES::SharedContentMap shared_content{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; for (const auto& content : content_loader.GetContent()) { std::string app_filename; if (content.m_metadata.IsShared()) - app_filename = shared_content.AddSharedContent(content.m_metadata.sha1.data()); + app_filename = shared_content.AddSharedContent(content.m_metadata.sha1); else app_filename = StringFromFormat("%s%08x.app", content_path.c_str(), content.m_metadata.id); @@ -460,7 +335,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) return 0; } - cUIDsys uid_sys{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; + IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; uid_sys.AddTitle(title_id); ClearCache(); diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h index 5b428bf5b4..6e6a5d77e8 100644 --- a/Source/Core/DiscIO/NANDContentLoader.h +++ b/Source/Core/DiscIO/NANDContentLoader.h @@ -123,50 +123,4 @@ private: std::unordered_map> m_map; }; - -class CSharedContent final -{ -public: - explicit CSharedContent(Common::FromWhichRoot root); - - std::string GetFilenameFromSHA1(const u8* hash) const; - std::string AddSharedContent(const u8* hash); - -private: -#pragma pack(push, 1) - struct SElement - { - u8 FileName[8]; - u8 SHA1Hash[20]; - }; -#pragma pack(pop) - - Common::FromWhichRoot m_root; - u32 m_LastID; - std::string m_ContentMap; - std::vector m_Elements; -}; - -class cUIDsys final -{ -public: - explicit cUIDsys(Common::FromWhichRoot root); - - u32 GetUIDFromTitle(u64 title_id); - void AddTitle(u64 title_id); - void GetTitleIDs(std::vector& title_ids, bool owned = false); - -private: -#pragma pack(push, 1) - struct SElement - { - u8 titleID[8]; - u8 UID[4]; - }; -#pragma pack(pop) - - u32 m_LastUID; - std::string m_UidSys; - std::vector m_Elements; -}; }