ESFormats: Migrate to new filesystem interface

This commit is contained in:
Léo Lam 2018-05-06 18:00:59 +02:00
parent 5dbf6cd0c9
commit 3dafc66c36
7 changed files with 75 additions and 56 deletions

View File

@ -161,7 +161,7 @@ IPCCommandResult ES::GetTitleId(const IOCtlVRequest& request)
static bool UpdateUIDAndGID(Kernel& kernel, const IOS::ES::TMDReader& tmd) 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 u64 title_id = tmd.GetTitleId();
const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id);
if (!uid) if (!uid)
@ -174,9 +174,9 @@ static bool UpdateUIDAndGID(Kernel& kernel, const IOS::ES::TMDReader& tmd)
return true; 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); const u32 system_menu_uid = uid_map.GetOrInsertUIDForTitle(Titles::SYSTEM_MENU);
if (!system_menu_uid) if (!system_menu_uid)
return ES_SHORT_READ; 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 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) if (ret < 0)
{ {
ERROR_LOG(IOS_ES, "SetUID: Permission check failed with error %d", ret); ERROR_LOG(IOS_ES, "SetUID: Permission check failed with error %d", ret);

View File

@ -336,8 +336,8 @@ private:
void FinishAllStaleImports(); void FinishAllStaleImports();
std::string GetContentPath(u64 title_id, const IOS::ES::Content& content, std::string GetContentPath(u64 title_id, const IOS::ES::Content& content,
const IOS::ES::SharedContentMap& map = IOS::ES::SharedContentMap{ const IOS::ES::SharedContentMap& map) const;
Common::FROM_SESSION_ROOT}) const; std::string GetContentPath(u64 title_id, const IOS::ES::Content& content) const;
// TODO: reuse the FS code. // TODO: reuse the FS code.
struct OpenedContent struct OpenedContent

View File

@ -19,13 +19,13 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/NandPaths.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/CommonTitles.h" #include "Core/CommonTitles.h"
#include "Core/IOS/Device.h" #include "Core/IOS/Device.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/IOS.h" #include "Core/IOS/IOS.h"
#include "Core/IOS/IOSC.h" #include "Core/IOS/IOSC.h"
@ -489,15 +489,15 @@ struct SharedContentMap::Entry
std::array<u8, 20> sha1; std::array<u8, 20> sha1;
}; };
SharedContentMap::SharedContentMap(Common::FromWhichRoot root) : m_root(root) static const std::string CONTENT_MAP_PATH = "/shared1/content.map";
SharedContentMap::SharedContentMap(std::shared_ptr<HLE::FS::FileSystem> fs) : m_fs{fs}
{ {
static_assert(sizeof(Entry) == 28, "SharedContentMap::Entry has the wrong size"); 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; 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_entries.push_back(entry);
m_last_id++; m_last_id++;
@ -515,7 +515,7 @@ SharedContentMap::GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const
return {}; return {};
const std::string id_string(it->id.begin(), it->id.end()); 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<std::array<u8, 20>> SharedContentMap::GetHashes() const std::vector<std::array<u8, 20>> SharedContentMap::GetHashes() const
@ -541,7 +541,7 @@ std::string SharedContentMap::AddSharedContent(const std::array<u8, 20>& sha1)
m_entries.push_back(entry); m_entries.push_back(entry);
WriteEntries(); WriteEntries();
filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str()); filename = StringFromFormat("/shared1/%s.app", id.c_str());
m_last_id++; m_last_id++;
return *filename; return *filename;
} }
@ -556,45 +556,49 @@ bool SharedContentMap::DeleteSharedContent(const std::array<u8, 20>& sha1)
bool SharedContentMap::WriteEntries() const bool SharedContentMap::WriteEntries() const
{ {
// Temporary files in ES are only 12 characters long (excluding /tmp/). // Temporary files are only 12 characters long and must match the final file name
const std::string temp_path = Common::RootUserPath(m_root) + "/tmp/shared1/cont"; const std::string temp_path = "/tmp/content.map";
File::CreateFullPath(temp_path); 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. // Atomically write the new content map.
{ {
File::IOFile file(temp_path, "w+b"); const auto file =
if (!file.WriteArray(m_entries.data(), m_entries.size())) 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; 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<u32, u64> ReadUidSysEntry(File::IOFile& file) static std::pair<u32, u64> ReadUidSysEntry(const HLE::FS::FileHandle& file)
{ {
u64 title_id = 0; u64 title_id = 0;
if (!file.ReadBytes(&title_id, sizeof(title_id))) if (!file.Read(&title_id, 1))
return {}; return {};
u32 uid = 0; u32 uid = 0;
if (!file.ReadBytes(&uid, sizeof(uid))) if (!file.Read(&uid, 1))
return {}; return {};
return {Common::swap32(uid), Common::swap64(title_id)}; 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<HLE::FS::FileSystem> fs) : m_fs{fs}
{ {
m_file_path = Common::RootUserPath(root) + "/sys/uid.sys"; if (const auto file =
fs->OpenFile(HLE::PID_KERNEL, HLE::PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read))
File::IOFile file(m_file_path, "rb");
while (true)
{ {
const std::pair<u32, u64> entry = ReadUidSysEntry(file); while (true)
if (!entry.first && !entry.second) {
break; const std::pair<u32, u64> 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()) 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 u64 swapped_title_id = Common::swap64(title_id);
const u32 swapped_uid = Common::swap32(uid); const u32 swapped_uid = Common::swap32(uid);
File::CreateFullPath(m_file_path); const auto file =
File::IOFile file(m_file_path, "ab"); 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) ||
if (!file.WriteBytes(&swapped_title_id, sizeof(title_id)) || !file->Write(&swapped_uid, 1))
!file.WriteBytes(&swapped_uid, sizeof(uid)))
{ {
ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys"); ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys");
return 0; return 0;

View File

@ -10,12 +10,12 @@
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <map> #include <map>
#include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/NandPaths.h"
#include "Core/IOS/Device.h" #include "Core/IOS/Device.h"
#include "Core/IOS/IOSC.h" #include "Core/IOS/IOSC.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
@ -24,6 +24,11 @@ class PointerWrap;
namespace IOS namespace IOS
{ {
namespace HLE::FS
{
class FileSystem;
}
namespace ES namespace ES
{ {
enum class TitleType : u32 enum class TitleType : u32
@ -249,7 +254,7 @@ public:
class SharedContentMap final class SharedContentMap final
{ {
public: public:
explicit SharedContentMap(Common::FromWhichRoot root); explicit SharedContentMap(std::shared_ptr<HLE::FS::FileSystem> fs);
~SharedContentMap(); ~SharedContentMap();
std::optional<std::string> GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const; std::optional<std::string> GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
@ -261,23 +266,22 @@ private:
bool WriteEntries() const; bool WriteEntries() const;
struct Entry; struct Entry;
Common::FromWhichRoot m_root;
u32 m_last_id = 0; u32 m_last_id = 0;
std::string m_file_path;
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
}; };
class UIDSys final class UIDSys final
{ {
public: public:
explicit UIDSys(Common::FromWhichRoot root); explicit UIDSys(std::shared_ptr<HLE::FS::FileSystem> fs);
u32 GetUIDFromTitle(u64 title_id) const; u32 GetUIDFromTitle(u64 title_id) const;
u32 GetOrInsertUIDForTitle(u64 title_id); u32 GetOrInsertUIDForTitle(u64 title_id);
u32 GetNextUID() const; u32 GetNextUID() const;
private: private:
std::string m_file_path; std::shared_ptr<HLE::FS::FileSystem> m_fs;
std::map<u32, u64> m_entries; std::map<u32, u64> m_entries;
}; };

View File

@ -169,7 +169,7 @@ std::vector<IOS::ES::Content> ES::GetStoredContentsFromTMD(const IOS::ES::TMDRea
if (!tmd.IsValid()) if (!tmd.IsValid())
return {}; return {};
const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; const IOS::ES::SharedContentMap map{m_ios.GetFS()};
const std::vector<IOS::ES::Content> contents = tmd.GetContents(); const std::vector<IOS::ES::Content> contents = tmd.GetContents();
std::vector<IOS::ES::Content> stored_contents; std::vector<IOS::ES::Content> stored_contents;
@ -196,7 +196,7 @@ u32 ES::GetSharedContentsCount() const
std::vector<std::array<u8, 20>> ES::GetSharedContents() const std::vector<std::array<u8, 20>> ES::GetSharedContents() const
{ {
const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; const IOS::ES::SharedContentMap map{m_ios.GetFS()};
return map.GetHashes(); 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); uid_sys.GetOrInsertUIDForTitle(title_id);
// IOS moves the title content directory to /import if the TMD exists during an import. // 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 const IOS::ES::SharedContentMap& content_map) const
{ {
if (content.IsShared()) 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) + return Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) +
StringFromFormat("/%08x.app", content.id); 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 Device
} // namespace HLE } // namespace HLE
} // namespace IOS } // namespace IOS

View File

@ -78,7 +78,7 @@ IPCCommandResult ES::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest&
if (!m_title_context.active) if (!m_title_context.active)
return GetDefaultReply(ES_EINVAL); 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()); const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
if (caller_uid != 0 && caller_uid != uid) if (caller_uid != 0 && caller_uid != uid)
return GetDefaultReply(ES_EACCES); return GetDefaultReply(ES_EACCES);

View File

@ -21,6 +21,7 @@
#include "Core/CommonTitles.h" #include "Core/CommonTitles.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/IOS/ES/Formats.h" #include "Core/IOS/ES/Formats.h"
#include "Core/IOS/FS/FileSystem.h"
namespace IOS namespace IOS
{ {
@ -373,8 +374,9 @@ ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd)
std::string content_path; std::string content_path;
if (content_info.IsShared()) if (content_info.IsShared())
{ {
IOS::ES::SharedContentMap shared_content{Common::FROM_SESSION_ROOT}; IOS::ES::SharedContentMap shared_content{m_ios.GetFS()};
content_path = shared_content.AddSharedContent(content_info.sha1); content_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) +
shared_content.AddSharedContent(content_info.sha1);
} }
else else
{ {
@ -424,7 +426,7 @@ ReturnCode ES::ImportTitleDone(Context& context)
// Make sure all listed, non-optional contents have been imported. // Make sure all listed, non-optional contents have been imported.
const u64 title_id = context.title_import_export.tmd.GetTitleId(); const u64 title_id = context.title_import_export.tmd.GetTitleId();
const std::vector<IOS::ES::Content> contents = context.title_import_export.tmd.GetContents(); const std::vector<IOS::ES::Content> 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 = const bool has_all_required_contents =
std::all_of(contents.cbegin(), contents.cend(), [&](const IOS::ES::Content& content) { std::all_of(contents.cbegin(), contents.cend(), [&](const IOS::ES::Content& content) {
if (content.IsOptional()) if (content.IsOptional())
@ -785,7 +787,7 @@ IPCCommandResult ES::ExportTitleDone(Context& context, const IOCtlVRequest& requ
ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& sha1) const ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& 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); const auto content_path = map.GetFilenameFromSHA1(sha1);
if (!content_path) if (!content_path)
return ES_EINVAL; return ES_EINVAL;
@ -810,8 +812,9 @@ ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& sha1) const
return ES_EINVAL; return ES_EINVAL;
// Delete the shared content and update the content map. // Delete the shared content and update the content map.
if (!File::Delete(*content_path)) const auto delete_result = m_ios.GetFS()->Delete(0, 0, *content_path);
return FS_ENOENT; if (delete_result != FS::ResultCode::Success)
return FS::ConvertResult(delete_result);
if (!map.DeleteSharedContent(sha1)) if (!map.DeleteSharedContent(sha1))
return ES_EIO; return ES_EIO;