IOS/ES: Make NandUtils member functions

In the future, NAND filesystem access will be limited to one IOS
instance, for safety reasons and to make it possible to consider
supporting NAND images. This means that any code accessing the NAND
filesystem must go through the FS device, both for code that is
external to IOS and internal.

Because we don't want to introduce any singleton, this requires
internal IOS code that needs NAND access to be part of an IOS device
class, so they can access the FS device easily.

Making some of the internal ES implementation functions member
functions also prevents them from being (mis)used outside of IOS,
since they cannot be called everywhere anymore.
This commit is contained in:
Léo Lam 2017-06-06 22:51:46 +02:00
parent c7316c89db
commit 47e0a1656e
9 changed files with 91 additions and 121 deletions

View File

@ -438,7 +438,6 @@
<ClInclude Include="IOS\DI\DI.h" />
<ClInclude Include="IOS\ES\ES.h" />
<ClInclude Include="IOS\ES\Formats.h" />
<ClInclude Include="IOS\ES\NandUtils.h" />
<ClInclude Include="IOS\FS\FileIO.h" />
<ClInclude Include="IOS\FS\FS.h" />
<ClInclude Include="IOS\Network\ICMPLin.h" />

View File

@ -1385,9 +1385,6 @@
<ClInclude Include="IOS\ES\ES.h">
<Filter>IOS\ES</Filter>
</ClInclude>
<ClInclude Include="IOS\ES\NandUtils.h">
<Filter>IOS\ES</Filter>
</ClInclude>
<ClInclude Include="IOS\FS\FileIO.h">
<Filter>IOS\FS</Filter>
</ClInclude>

View File

@ -19,7 +19,6 @@
#include "Core/ConfigManager.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/ES/NandUtils.h"
#include "DiscIO/NANDContentLoader.h"
namespace IOS
@ -35,26 +34,6 @@ static TitleContext s_title_context;
// Title to launch after IOS has been reset and reloaded (similar to /sys/launch.sys).
static u64 s_title_to_launch;
static void FinishAllStaleImports()
{
const std::vector<u64> titles = IOS::ES::GetTitleImports();
for (const u64& title_id : titles)
{
const IOS::ES::TMDReader tmd = IOS::ES::FindImportTMD(title_id);
if (!tmd.IsValid())
{
File::DeleteDirRecursively(Common::GetImportTitlePath(title_id) + "/content");
continue;
}
FinishImport(tmd);
}
const std::string import_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/import";
File::DeleteDirRecursively(import_dir);
File::CreateDir(import_dir);
}
ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
{
FinishAllStaleImports();
@ -193,7 +172,7 @@ IPCCommandResult ES::SetUID(u32 uid, const IOCtlVRequest& request)
return GetDefaultReply(ret);
}
const auto tmd = IOS::ES::FindInstalledTMD(title_id);
const auto tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);

View File

@ -97,6 +97,20 @@ public:
s32 ipc_fd = -1;
};
IOS::ES::TMDReader FindImportTMD(u64 title_id) const;
IOS::ES::TMDReader FindInstalledTMD(u64 title_id) const;
// Get installed titles (in /title) without checking for TMDs at all.
std::vector<u64> GetInstalledTitles() const;
// Get titles which are being imported (in /import) without checking for TMDs at all.
std::vector<u64> GetTitleImports() const;
// Get titles for which there is a ticket (in /ticket).
std::vector<u64> GetTitlesWithTickets() const;
std::vector<IOS::ES::Content> GetStoredContentsFromTMD(const IOS::ES::TMDReader& tmd) const;
u32 GetSharedContentsCount() const;
std::vector<std::array<u8, 20>> GetSharedContents() const;
// Title management
ReturnCode ImportTicket(const std::vector<u8>& ticket_bytes);
ReturnCode ImportTmd(Context& context, const std::vector<u8>& tmd_bytes);
@ -284,6 +298,16 @@ private:
bool LaunchPPCTitle(u64 title_id, bool skip_reload);
static TitleContext& GetTitleContext();
// Start a title import.
bool InitImport(u64 title_id);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const IOS::ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const IOS::ES::TMDReader& tmd);
// Finish stale imports and clear the import directory.
void FinishStaleImport(u64 title_id);
void FinishAllStaleImports();
static const DiscIO::NANDContentLoader& AccessContentDevice(u64 title_id);
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cctype>
#include <cinttypes>
#include <iterator>
@ -15,14 +16,16 @@
#include "Common/Logging/Log.h"
#include "Common/NandPaths.h"
#include "Common/StringUtil.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/ES/NandUtils.h"
namespace IOS
{
namespace ES
namespace HLE
{
static TMDReader FindTMD(u64 title_id, const std::string& tmd_path)
namespace Device
{
static IOS::ES::TMDReader FindTMD(u64 title_id, const std::string& tmd_path)
{
File::IOFile file(tmd_path, "rb");
if (!file)
@ -32,15 +35,15 @@ static TMDReader FindTMD(u64 title_id, const std::string& tmd_path)
if (!file.ReadBytes(tmd_bytes.data(), tmd_bytes.size()))
return {};
return TMDReader{std::move(tmd_bytes)};
return IOS::ES::TMDReader{std::move(tmd_bytes)};
}
TMDReader FindImportTMD(u64 title_id)
IOS::ES::TMDReader ES::FindImportTMD(u64 title_id) const
{
return FindTMD(title_id, Common::GetImportTitlePath(title_id) + "/content/title.tmd");
}
TMDReader FindInstalledTMD(u64 title_id)
IOS::ES::TMDReader ES::FindInstalledTMD(u64 title_id) const
{
return FindTMD(title_id, Common::GetTMDFileName(title_id, Common::FROM_SESSION_ROOT));
}
@ -88,17 +91,17 @@ static std::vector<u64> GetTitlesInTitleOrImport(const std::string& titles_dir)
return title_ids;
}
std::vector<u64> GetInstalledTitles()
std::vector<u64> ES::GetInstalledTitles() const
{
return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/title");
}
std::vector<u64> GetTitleImports()
std::vector<u64> ES::GetTitleImports() const
{
return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/import");
}
std::vector<u64> GetTitlesWithTickets()
std::vector<u64> ES::GetTitlesWithTickets() const
{
const std::string tickets_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/ticket";
if (!File::IsDirectory(tickets_dir))
@ -138,15 +141,15 @@ std::vector<u64> GetTitlesWithTickets()
return title_ids;
}
std::vector<Content> GetStoredContentsFromTMD(const TMDReader& tmd)
std::vector<IOS::ES::Content> ES::GetStoredContentsFromTMD(const IOS::ES::TMDReader& tmd) const
{
if (!tmd.IsValid())
return {};
const IOS::ES::SharedContentMap shared{Common::FROM_SESSION_ROOT};
const std::vector<Content> contents = tmd.GetContents();
const std::vector<IOS::ES::Content> contents = tmd.GetContents();
std::vector<Content> stored_contents;
std::vector<IOS::ES::Content> stored_contents;
std::copy_if(contents.begin(), contents.end(), std::back_inserter(stored_contents),
[&tmd, &shared](const auto& content) {
@ -163,7 +166,7 @@ std::vector<Content> GetStoredContentsFromTMD(const TMDReader& tmd)
return stored_contents;
}
u32 GetSharedContentsCount()
u32 ES::GetSharedContentsCount() const
{
const std::string shared1_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/shared1";
const auto entries = File::ScanDirectoryTree(shared1_path, false);
@ -174,13 +177,13 @@ u32 GetSharedContentsCount()
}));
}
std::vector<std::array<u8, 20>> GetSharedContents()
std::vector<std::array<u8, 20>> ES::GetSharedContents() const
{
const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT};
return map.GetHashes();
}
bool InitImport(u64 title_id)
bool ES::InitImport(u64 title_id)
{
const std::string content_dir = Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT);
const std::string data_dir = Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT);
@ -193,7 +196,7 @@ bool InitImport(u64 title_id)
}
}
UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT};
IOS::ES::UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT};
uid_sys.GetOrInsertUIDForTitle(title_id);
// IOS moves the title content directory to /import if the TMD exists during an import.
@ -211,7 +214,7 @@ bool InitImport(u64 title_id)
return true;
}
bool FinishImport(const IOS::ES::TMDReader& tmd)
bool ES::FinishImport(const IOS::ES::TMDReader& tmd)
{
const u64 title_id = tmd.GetTitleId();
const std::string import_content_dir = Common::GetImportTitlePath(title_id) + "/content";
@ -244,7 +247,7 @@ bool FinishImport(const IOS::ES::TMDReader& tmd)
return true;
}
bool WriteImportTMD(const IOS::ES::TMDReader& tmd)
bool ES::WriteImportTMD(const IOS::ES::TMDReader& tmd)
{
const std::string tmd_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/tmp/title.tmd";
File::CreateFullPath(tmd_path);
@ -258,5 +261,26 @@ bool WriteImportTMD(const IOS::ES::TMDReader& tmd)
const std::string dest = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content/title.tmd";
return File::Rename(tmd_path, dest);
}
} // namespace ES
void ES::FinishStaleImport(u64 title_id)
{
const auto import_tmd = FindImportTMD(title_id);
if (!import_tmd.IsValid())
File::DeleteDirRecursively(Common::GetImportTitlePath(title_id) + "/content");
else
FinishImport(import_tmd);
}
void ES::FinishAllStaleImports()
{
const std::vector<u64> titles = GetTitleImports();
for (const u64& title_id : titles)
FinishStaleImport(title_id);
const std::string import_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/import";
File::DeleteDirRecursively(import_dir);
File::CreateDir(import_dir);
}
} // namespace Device
} // namespace HLE
} // namespace IOS

View File

@ -1,41 +0,0 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <vector>
#include "Common/CommonTypes.h"
namespace IOS
{
namespace ES
{
struct Content;
class TMDReader;
TMDReader FindImportTMD(u64 title_id);
TMDReader FindInstalledTMD(u64 title_id);
// Get installed titles (in /title) without checking for TMDs at all.
std::vector<u64> GetInstalledTitles();
// Get titles which are being imported (in /import) without checking for TMDs at all.
std::vector<u64> GetTitleImports();
// Get titles for which there is a ticket (in /ticket).
std::vector<u64> GetTitlesWithTickets();
std::vector<Content> GetStoredContentsFromTMD(const TMDReader& tmd);
u32 GetSharedContentsCount();
std::vector<std::array<u8, 20>> GetSharedContents();
// Start a title import.
bool InitImport(u64 title_id);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const IOS::ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const IOS::ES::TMDReader& tmd);
} // namespace ES
} // namespace IOS

View File

@ -15,7 +15,6 @@
#include "Common/StringUtil.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/ES/NandUtils.h"
#include "DiscIO/NANDContentLoader.h"
namespace IOS
@ -32,7 +31,7 @@ IPCCommandResult ES::GetStoredContentsCount(const IOS::ES::TMDReader& tmd,
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
const u16 num_contents = static_cast<u16>(IOS::ES::GetStoredContentsFromTMD(tmd).size());
const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
Memory::Write_U32(num_contents, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "GetStoredContentsCount (0x%x): %u content(s) for %016" PRIx64, request.request,
@ -53,7 +52,7 @@ IPCCommandResult ES::GetStoredContents(const IOS::ES::TMDReader& tmd, const IOCt
return GetDefaultReply(ES_EINVAL);
}
const auto contents = IOS::ES::GetStoredContentsFromTMD(tmd);
const auto contents = GetStoredContentsFromTMD(tmd);
const u32 max_content_count = Memory::Read_U32(request.in_vectors[1].address);
for (u32 i = 0; i < std::min(static_cast<u32>(contents.size()), max_content_count); ++i)
Memory::Write_U32(contents[i].id, request.io_vectors[0].address + i * sizeof(u32));
@ -67,7 +66,7 @@ IPCCommandResult ES::GetStoredContentsCount(const IOCtlVRequest& request)
return GetDefaultReply(ES_EINVAL);
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(title_id);
const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return GetStoredContentsCount(tmd, request);
@ -79,7 +78,7 @@ IPCCommandResult ES::GetStoredContents(const IOCtlVRequest& request)
return GetDefaultReply(ES_EINVAL);
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(title_id);
const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return GetStoredContents(tmd, request);
@ -131,14 +130,14 @@ IPCCommandResult ES::GetTitles(const std::vector<u64>& titles, const IOCtlVReque
IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = IOS::ES::GetInstalledTitles();
const std::vector<u64> titles = GetInstalledTitles();
INFO_LOG(IOS_ES, "GetTitleCount: %zu titles", titles.size());
return GetTitleCount(titles, request);
}
IPCCommandResult ES::GetTitles(const IOCtlVRequest& request)
{
return GetTitles(IOS::ES::GetInstalledTitles(), request);
return GetTitles(GetInstalledTitles(), request);
}
IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request)
@ -147,7 +146,7 @@ IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request)
return GetDefaultReply(ES_EINVAL);
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(title_id);
const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
@ -165,7 +164,7 @@ IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request)
return GetDefaultReply(ES_EINVAL);
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(title_id);
const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
@ -184,14 +183,14 @@ IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request)
IPCCommandResult ES::GetOwnedTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = IOS::ES::GetTitlesWithTickets();
const std::vector<u64> titles = GetTitlesWithTickets();
INFO_LOG(IOS_ES, "GetOwnedTitleCount: %zu titles", titles.size());
return GetTitleCount(titles, request);
}
IPCCommandResult ES::GetOwnedTitles(const IOCtlVRequest& request)
{
return GetTitles(IOS::ES::GetTitlesWithTickets(), request);
return GetTitles(GetTitlesWithTickets(), request);
}
IPCCommandResult ES::GetBoot2Version(const IOCtlVRequest& request)
@ -211,7 +210,7 @@ IPCCommandResult ES::GetSharedContentsCount(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
const u32 count = IOS::ES::GetSharedContentsCount();
const u32 count = GetSharedContentsCount();
Memory::Write_U32(count, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "GetSharedContentsCount: %u contents", count);
@ -227,7 +226,7 @@ IPCCommandResult ES::GetSharedContents(const IOCtlVRequest& request) const
if (request.io_vectors[0].size != 20 * max_count)
return GetDefaultReply(ES_EINVAL);
const std::vector<std::array<u8, 20>> hashes = IOS::ES::GetSharedContents();
const std::vector<std::array<u8, 20>> hashes = GetSharedContents();
const u32 count = std::min(static_cast<u32>(hashes.size()), max_count);
Memory::CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count);

View File

@ -20,7 +20,6 @@
#include "Common/StringUtil.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/ES/NandUtils.h"
#include "Core/ec_wii.h"
#include "DiscIO/NANDContentLoader.h"
@ -96,7 +95,7 @@ ReturnCode ES::ImportTmd(Context& context, const std::vector<u8>& tmd_bytes)
if (!context.title_import.tmd.IsValid())
return ES_EINVAL;
if (!IOS::ES::InitImport(context.title_import.tmd.GetTitleId()))
if (!InitImport(context.title_import.tmd.GetTitleId()))
return ES_EIO;
return IPC_SUCCESS;
@ -115,15 +114,6 @@ IPCCommandResult ES::ImportTmd(Context& context, const IOCtlVRequest& request)
return GetDefaultReply(ImportTmd(context, tmd));
}
static void CleanUpStaleImport(const u64 title_id)
{
const auto import_tmd = IOS::ES::FindImportTMD(title_id);
if (!import_tmd.IsValid())
File::DeleteDirRecursively(Common::GetImportTitlePath(title_id) + "/content");
else
IOS::ES::FinishImport(import_tmd);
}
ReturnCode ES::ImportTitleInit(Context& context, const std::vector<u8>& tmd_bytes)
{
INFO_LOG(IOS_ES, "ImportTitleInit");
@ -135,9 +125,9 @@ ReturnCode ES::ImportTitleInit(Context& context, const std::vector<u8>& tmd_byte
}
// Finish a previous import (if it exists).
CleanUpStaleImport(context.title_import.tmd.GetTitleId());
FinishStaleImport(context.title_import.tmd.GetTitleId());
if (!IOS::ES::InitImport(context.title_import.tmd.GetTitleId()))
if (!InitImport(context.title_import.tmd.GetTitleId()))
return ES_EIO;
// TODO: check and use the other vectors.
@ -340,7 +330,7 @@ ReturnCode ES::ImportTitleCancel(Context& context)
if (!context.title_import.tmd.IsValid())
return ES_EINVAL;
CleanUpStaleImport(context.title_import.tmd.GetTitleId());
FinishStaleImport(context.title_import.tmd.GetTitleId());
INFO_LOG(IOS_ES, "ImportTitleCancel: title %016" PRIx64, context.title_import.tmd.GetTitleId());
context.title_import.tmd.SetBytes({});
@ -467,7 +457,7 @@ ReturnCode ES::DeleteContent(u64 title_id, u32 content_id) const
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
const auto tmd = IOS::ES::FindInstalledTMD(title_id);
const auto tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return FS_ENOENT;
@ -501,7 +491,7 @@ ReturnCode ES::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u3
if (context.title_export.valid)
return ES_EINVAL;
const auto tmd = IOS::ES::FindInstalledTMD(title_id);
const auto tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return FS_ENOENT;
@ -686,12 +676,12 @@ ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& sha1) const
return ES_EINVAL;
// Check whether the shared content is used by a system title.
const std::vector<u64> titles = IOS::ES::GetInstalledTitles();
const bool is_used_by_system_title = std::any_of(titles.begin(), titles.end(), [&sha1](u64 id) {
const std::vector<u64> titles = GetInstalledTitles();
const bool is_used_by_system_title = std::any_of(titles.begin(), titles.end(), [&](u64 id) {
if (!IOS::ES::IsTitleType(id, IOS::ES::TitleType::System))
return false;
const auto tmd = IOS::ES::FindInstalledTMD(id);
const auto tmd = FindInstalledTMD(id);
if (!tmd.IsValid())
return true;

View File

@ -16,7 +16,6 @@
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/ES/NandUtils.h"
#include "DiscIO/NANDContentLoader.h"
namespace IOS
@ -206,7 +205,7 @@ IPCCommandResult ES::GetTMDViewSize(const IOCtlVRequest& request)
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(TitleID);
const IOS::ES::TMDReader tmd = FindInstalledTMD(TitleID);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
@ -229,7 +228,7 @@ IPCCommandResult ES::GetTMDViews(const IOCtlVRequest& request)
}
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const IOS::ES::TMDReader tmd = IOS::ES::FindInstalledTMD(title_id);
const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);