ESFormats: Migrate to new filesystem interface
This commit is contained in:
parent
5dbf6cd0c9
commit
3dafc66c36
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue