From 3dafc66c36bb842559913e624fc35d4d4f7c9dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 6 May 2018 18:00:59 +0200 Subject: [PATCH] ESFormats: Migrate to new filesystem interface --- Source/Core/Core/IOS/ES/ES.cpp | 8 +-- Source/Core/Core/IOS/ES/ES.h | 4 +- Source/Core/Core/IOS/ES/Formats.cpp | 69 +++++++++++---------- Source/Core/Core/IOS/ES/Formats.h | 16 +++-- Source/Core/Core/IOS/ES/NandUtils.cpp | 17 +++-- Source/Core/Core/IOS/ES/TitleContents.cpp | 2 +- Source/Core/Core/IOS/ES/TitleManagement.cpp | 15 +++-- 7 files changed, 75 insertions(+), 56 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index d29d6a6d53..cf0e18c494 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -161,7 +161,7 @@ IPCCommandResult ES::GetTitleId(const IOCtlVRequest& request) static bool UpdateUIDAndGID(Kernel& kernel, const IOS::ES::TMDReader& tmd) { - IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; + IOS::ES::UIDSys uid_sys{kernel.GetFS()}; const u64 title_id = tmd.GetTitleId(); const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); if (!uid) @@ -174,9 +174,9 @@ static bool UpdateUIDAndGID(Kernel& kernel, const IOS::ES::TMDReader& tmd) return true; } -static ReturnCode CheckIsAllowedToSetUID(const u32 caller_uid) +static ReturnCode CheckIsAllowedToSetUID(Kernel& kernel, const u32 caller_uid) { - IOS::ES::UIDSys uid_map{Common::FromWhichRoot::FROM_SESSION_ROOT}; + IOS::ES::UIDSys uid_map{kernel.GetFS()}; const u32 system_menu_uid = uid_map.GetOrInsertUIDForTitle(Titles::SYSTEM_MENU); if (!system_menu_uid) return ES_SHORT_READ; @@ -190,7 +190,7 @@ IPCCommandResult ES::SetUID(u32 uid, const IOCtlVRequest& request) const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); - const s32 ret = CheckIsAllowedToSetUID(uid); + const s32 ret = CheckIsAllowedToSetUID(m_ios, uid); if (ret < 0) { ERROR_LOG(IOS_ES, "SetUID: Permission check failed with error %d", ret); diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index ac5998e805..e345511ee9 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -336,8 +336,8 @@ private: void FinishAllStaleImports(); std::string GetContentPath(u64 title_id, const IOS::ES::Content& content, - const IOS::ES::SharedContentMap& map = IOS::ES::SharedContentMap{ - Common::FROM_SESSION_ROOT}) const; + const IOS::ES::SharedContentMap& map) const; + std::string GetContentPath(u64 title_id, const IOS::ES::Content& content) const; // TODO: reuse the FS code. struct OpenedContent diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index d5f5ee17f0..ec69c3e1fd 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -19,13 +19,13 @@ #include "Common/Assert.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/File.h" -#include "Common/FileUtil.h" #include "Common/Logging/Log.h" +#include "Common/NandPaths.h" #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/CommonTitles.h" #include "Core/IOS/Device.h" +#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/IOS.h" #include "Core/IOS/IOSC.h" @@ -489,15 +489,15 @@ struct SharedContentMap::Entry std::array sha1; }; -SharedContentMap::SharedContentMap(Common::FromWhichRoot root) : m_root(root) +static const std::string CONTENT_MAP_PATH = "/shared1/content.map"; +SharedContentMap::SharedContentMap(std::shared_ptr fs) : m_fs{fs} { 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)) + const auto file = + fs->OpenFile(HLE::PID_KERNEL, HLE::PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read); + while (file && file->Read(&entry, 1)) { m_entries.push_back(entry); m_last_id++; @@ -515,7 +515,7 @@ SharedContentMap::GetFilenameFromSHA1(const std::array& sha1) const return {}; const std::string id_string(it->id.begin(), it->id.end()); - return Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id_string.c_str()); + return StringFromFormat("/shared1/%s.app", id_string.c_str()); } std::vector> SharedContentMap::GetHashes() const @@ -541,7 +541,7 @@ std::string SharedContentMap::AddSharedContent(const std::array& sha1) m_entries.push_back(entry); WriteEntries(); - filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str()); + filename = StringFromFormat("/shared1/%s.app", id.c_str()); m_last_id++; return *filename; } @@ -556,45 +556,49 @@ bool SharedContentMap::DeleteSharedContent(const std::array& sha1) bool SharedContentMap::WriteEntries() const { - // Temporary files in ES are only 12 characters long (excluding /tmp/). - const std::string temp_path = Common::RootUserPath(m_root) + "/tmp/shared1/cont"; - File::CreateFullPath(temp_path); + // Temporary files are only 12 characters long and must match the final file name + const std::string temp_path = "/tmp/content.map"; + m_fs->CreateFile(HLE::PID_KERNEL, HLE::PID_KERNEL, temp_path, 0, HLE::FS::Mode::ReadWrite, + HLE::FS::Mode::ReadWrite, HLE::FS::Mode::None); // Atomically write the new content map. { - File::IOFile file(temp_path, "w+b"); - if (!file.WriteArray(m_entries.data(), m_entries.size())) + const auto file = + m_fs->OpenFile(HLE::PID_KERNEL, HLE::PID_KERNEL, temp_path, HLE::FS::Mode::Write); + if (!file || !file->Write(m_entries.data(), m_entries.size())) return false; - File::CreateFullPath(m_file_path); } - return File::RenameSync(temp_path, m_file_path); + return m_fs->Rename(HLE::PID_KERNEL, HLE::PID_KERNEL, temp_path, CONTENT_MAP_PATH) == + HLE::FS::ResultCode::Success; } -static std::pair ReadUidSysEntry(File::IOFile& file) +static std::pair ReadUidSysEntry(const HLE::FS::FileHandle& file) { u64 title_id = 0; - if (!file.ReadBytes(&title_id, sizeof(title_id))) + if (!file.Read(&title_id, 1)) return {}; u32 uid = 0; - if (!file.ReadBytes(&uid, sizeof(uid))) + if (!file.Read(&uid, 1)) return {}; return {Common::swap32(uid), Common::swap64(title_id)}; } -UIDSys::UIDSys(Common::FromWhichRoot root) +static const std::string UID_MAP_PATH = "/sys/uid.sys"; +UIDSys::UIDSys(std::shared_ptr fs) : m_fs{fs} { - m_file_path = Common::RootUserPath(root) + "/sys/uid.sys"; - - File::IOFile file(m_file_path, "rb"); - while (true) + if (const auto file = + fs->OpenFile(HLE::PID_KERNEL, HLE::PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read)) { - const std::pair entry = ReadUidSysEntry(file); - if (!entry.first && !entry.second) - break; + while (true) + { + const std::pair entry = ReadUidSysEntry(*file); + if (!entry.first && !entry.second) + break; - m_entries.insert(std::move(entry)); + m_entries.insert(std::move(entry)); + } } if (m_entries.empty()) @@ -633,11 +637,10 @@ u32 UIDSys::GetOrInsertUIDForTitle(const u64 title_id) const u64 swapped_title_id = Common::swap64(title_id); const u32 swapped_uid = Common::swap32(uid); - File::CreateFullPath(m_file_path); - File::IOFile file(m_file_path, "ab"); - - if (!file.WriteBytes(&swapped_title_id, sizeof(title_id)) || - !file.WriteBytes(&swapped_uid, sizeof(uid))) + const auto file = + m_fs->OpenFile(HLE::PID_KERNEL, HLE::PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::ReadWrite); + if (!file || !file->Seek(0, HLE::FS::SeekMode::End) || !file->Write(&swapped_title_id, 1) || + !file->Write(&swapped_uid, 1)) { ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys"); return 0; diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index bb8ccd4eae..1b1c1bbcb0 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -10,12 +10,12 @@ #include #include #include +#include #include #include #include #include "Common/CommonTypes.h" -#include "Common/NandPaths.h" #include "Core/IOS/Device.h" #include "Core/IOS/IOSC.h" #include "DiscIO/Enums.h" @@ -24,6 +24,11 @@ class PointerWrap; namespace IOS { +namespace HLE::FS +{ +class FileSystem; +} + namespace ES { enum class TitleType : u32 @@ -249,7 +254,7 @@ public: class SharedContentMap final { public: - explicit SharedContentMap(Common::FromWhichRoot root); + explicit SharedContentMap(std::shared_ptr fs); ~SharedContentMap(); std::optional GetFilenameFromSHA1(const std::array& sha1) const; @@ -261,23 +266,22 @@ private: bool WriteEntries() const; struct Entry; - Common::FromWhichRoot m_root; u32 m_last_id = 0; - std::string m_file_path; std::vector m_entries; + std::shared_ptr m_fs; }; class UIDSys final { public: - explicit UIDSys(Common::FromWhichRoot root); + explicit UIDSys(std::shared_ptr fs); u32 GetUIDFromTitle(u64 title_id) const; u32 GetOrInsertUIDForTitle(u64 title_id); u32 GetNextUID() const; private: - std::string m_file_path; + std::shared_ptr m_fs; std::map m_entries; }; diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index 1b332bf97b..cf378ca902 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -169,7 +169,7 @@ std::vector ES::GetStoredContentsFromTMD(const IOS::ES::TMDRea if (!tmd.IsValid()) return {}; - const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; + const IOS::ES::SharedContentMap map{m_ios.GetFS()}; const std::vector contents = tmd.GetContents(); std::vector stored_contents; @@ -196,7 +196,7 @@ u32 ES::GetSharedContentsCount() const std::vector> ES::GetSharedContents() const { - const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; + const IOS::ES::SharedContentMap map{m_ios.GetFS()}; return map.GetHashes(); } @@ -213,7 +213,7 @@ bool ES::InitImport(u64 title_id) } } - IOS::ES::UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT}; + IOS::ES::UIDSys uid_sys{m_ios.GetFS()}; uid_sys.GetOrInsertUIDForTitle(title_id); // IOS moves the title content directory to /import if the TMD exists during an import. @@ -307,11 +307,20 @@ std::string ES::GetContentPath(const u64 title_id, const IOS::ES::Content& conte const IOS::ES::SharedContentMap& content_map) const { if (content.IsShared()) - return content_map.GetFilenameFromSHA1(content.sha1).value_or(""); + { + const std::string path = content_map.GetFilenameFromSHA1(content.sha1).value_or(""); + return path.empty() ? "" : Common::RootUserPath(Common::FROM_SESSION_ROOT) + path; + } return Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) + StringFromFormat("/%08x.app", content.id); } + +std::string ES::GetContentPath(const u64 title_id, const IOS::ES::Content& content) const +{ + IOS::ES::SharedContentMap map{m_ios.GetFS()}; + return GetContentPath(title_id, content, map); +} } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/TitleContents.cpp b/Source/Core/Core/IOS/ES/TitleContents.cpp index 8e7cbb616e..8ea71f3bf4 100644 --- a/Source/Core/Core/IOS/ES/TitleContents.cpp +++ b/Source/Core/Core/IOS/ES/TitleContents.cpp @@ -78,7 +78,7 @@ IPCCommandResult ES::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - IOS::ES::UIDSys uid_map{Common::FROM_SESSION_ROOT}; + IOS::ES::UIDSys uid_map{m_ios.GetFS()}; const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId()); if (caller_uid != 0 && caller_uid != uid) return GetDefaultReply(ES_EACCES); diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 1bb9a1a752..fa9fe2228b 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -21,6 +21,7 @@ #include "Core/CommonTitles.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/Formats.h" +#include "Core/IOS/FS/FileSystem.h" namespace IOS { @@ -373,8 +374,9 @@ ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd) std::string content_path; if (content_info.IsShared()) { - IOS::ES::SharedContentMap shared_content{Common::FROM_SESSION_ROOT}; - content_path = shared_content.AddSharedContent(content_info.sha1); + IOS::ES::SharedContentMap shared_content{m_ios.GetFS()}; + content_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + + shared_content.AddSharedContent(content_info.sha1); } else { @@ -424,7 +426,7 @@ ReturnCode ES::ImportTitleDone(Context& context) // Make sure all listed, non-optional contents have been imported. const u64 title_id = context.title_import_export.tmd.GetTitleId(); const std::vector contents = context.title_import_export.tmd.GetContents(); - const IOS::ES::SharedContentMap shared_content_map{Common::FROM_SESSION_ROOT}; + const IOS::ES::SharedContentMap shared_content_map{m_ios.GetFS()}; const bool has_all_required_contents = std::all_of(contents.cbegin(), contents.cend(), [&](const IOS::ES::Content& content) { if (content.IsOptional()) @@ -785,7 +787,7 @@ IPCCommandResult ES::ExportTitleDone(Context& context, const IOCtlVRequest& requ ReturnCode ES::DeleteSharedContent(const std::array& sha1) const { - IOS::ES::SharedContentMap map{Common::FromWhichRoot::FROM_SESSION_ROOT}; + IOS::ES::SharedContentMap map{m_ios.GetFS()}; const auto content_path = map.GetFilenameFromSHA1(sha1); if (!content_path) return ES_EINVAL; @@ -810,8 +812,9 @@ ReturnCode ES::DeleteSharedContent(const std::array& sha1) const return ES_EINVAL; // Delete the shared content and update the content map. - if (!File::Delete(*content_path)) - return FS_ENOENT; + const auto delete_result = m_ios.GetFS()->Delete(0, 0, *content_path); + if (delete_result != FS::ResultCode::Success) + return FS::ConvertResult(delete_result); if (!map.DeleteSharedContent(sha1)) return ES_EIO;