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)
{
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);

View File

@ -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

View File

@ -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<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");
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<u8, 20>& 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<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);
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<u8, 20>& 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<u32, u64> ReadUidSysEntry(File::IOFile& file)
static std::pair<u32, u64> 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<HLE::FS::FileSystem> 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<u32, u64> entry = ReadUidSysEntry(file);
if (!entry.first && !entry.second)
break;
while (true)
{
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())
@ -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;

View File

@ -10,12 +10,12 @@
#include <array>
#include <cstddef>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#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<HLE::FS::FileSystem> fs);
~SharedContentMap();
std::optional<std::string> GetFilenameFromSHA1(const std::array<u8, 20>& 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<Entry> m_entries;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
};
class UIDSys final
{
public:
explicit UIDSys(Common::FromWhichRoot root);
explicit UIDSys(std::shared_ptr<HLE::FS::FileSystem> fs);
u32 GetUIDFromTitle(u64 title_id) const;
u32 GetOrInsertUIDForTitle(u64 title_id);
u32 GetNextUID() const;
private:
std::string m_file_path;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
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())
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();
std::vector<IOS::ES::Content> stored_contents;
@ -196,7 +196,7 @@ u32 ES::GetSharedContentsCount() 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();
}
@ -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

View File

@ -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);

View File

@ -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<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 =
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<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);
if (!content_path)
return ES_EINVAL;
@ -810,8 +812,9 @@ ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& 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;