ES: Use new filesystem interface in TitleManagement

This commit is contained in:
Léo Lam 2018-05-06 19:05:57 +02:00
parent 9ee2654be6
commit 923b450268
1 changed files with 54 additions and 61 deletions

View File

@ -13,8 +13,6 @@
#include <mbedtls/sha1.h>
#include "Common/Align.h"
#include "Common/File.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/NandPaths.h"
#include "Common/StringUtil.h"
@ -29,19 +27,22 @@ namespace HLE
{
namespace Device
{
static ReturnCode WriteTicket(const IOS::ES::TicketReader& ticket)
static ReturnCode WriteTicket(FS::FileSystem* fs, const IOS::ES::TicketReader& ticket)
{
const u64 title_id = ticket.GetTitleId();
const std::string ticket_path = Common::GetTicketFileName(title_id, Common::FROM_SESSION_ROOT);
File::CreateFullPath(ticket_path);
const std::string path = Common::GetTicketFileName(title_id);
fs->CreateFullPath(PID_KERNEL, PID_KERNEL, path, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite,
FS::Mode::None);
fs->CreateFile(PID_KERNEL, PID_KERNEL, path, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite,
FS::Mode::None);
File::IOFile ticket_file(ticket_path, "wb");
if (!ticket_file)
return ES_EIO;
const auto file = fs->OpenFile(PID_KERNEL, PID_KERNEL, path, FS::Mode::Write);
if (!file)
return FS::ConvertResult(file.Error());
const std::vector<u8>& raw_ticket = ticket.GetBytes();
return ticket_file.WriteBytes(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO;
return file->Write(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO;
}
void ES::TitleImportExportContext::DoState(PointerWrap& p)
@ -85,7 +86,7 @@ ReturnCode ES::ImportTicket(const std::vector<u8>& ticket_bytes, const std::vect
if (verify_ret != IPC_SUCCESS)
return verify_ret;
const ReturnCode write_ret = WriteTicket(ticket);
const ReturnCode write_ret = WriteTicket(m_ios.GetFS().get(), ticket);
if (write_ret != IPC_SUCCESS)
return write_ret;
@ -343,8 +344,7 @@ static bool CheckIfContentHashMatches(const std::vector<u8>& content, const IOS:
static std::string GetImportContentPath(u64 title_id, u32 content_id)
{
return Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) +
StringFromFormat("/content/%08x.app", content_id);
return Common::GetImportTitlePath(title_id) + StringFromFormat("/content/%08x.app", content_id);
}
ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd)
@ -371,38 +371,39 @@ ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd)
return ES_HASH_MISMATCH;
}
const auto fs = m_ios.GetFS();
std::string content_path;
if (content_info.IsShared())
{
IOS::ES::SharedContentMap shared_content{m_ios.GetFS()};
content_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) +
shared_content.AddSharedContent(content_info.sha1);
IOS::ES::SharedContentMap shared_content{fs};
content_path = shared_content.AddSharedContent(content_info.sha1);
}
else
{
content_path = GetImportContentPath(context.title_import_export.tmd.GetTitleId(),
context.title_import_export.content.id);
}
File::CreateFullPath(content_path);
const std::string temp_path =
Common::RootUserPath(Common::FROM_SESSION_ROOT) +
StringFromFormat("/tmp/%08x.app", context.title_import_export.content.id);
File::CreateFullPath(temp_path);
"/tmp/" + content_path.substr(content_path.find_last_of('/') + 1, std::string::npos);
fs->CreateFile(PID_KERNEL, PID_KERNEL, temp_path, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite,
FS::Mode::None);
{
File::IOFile file(temp_path, "wb");
if (!file.WriteBytes(decrypted_data.data(), content_info.size))
const auto file = fs->OpenFile(PID_KERNEL, PID_KERNEL, temp_path, FS::Mode::Write);
if (!file || !file->Write(decrypted_data.data(), content_info.size))
{
ERROR_LOG(IOS_ES, "ImportContentEnd: Failed to write to %s", temp_path.c_str());
return ES_EIO;
}
}
if (!File::Rename(temp_path, content_path))
const FS::ResultCode rename_result = fs->Rename(PID_KERNEL, PID_KERNEL, temp_path, content_path);
if (rename_result != FS::ResultCode::Success)
{
fs->Delete(PID_KERNEL, PID_KERNEL, temp_path);
ERROR_LOG(IOS_ES, "ImportContentEnd: Failed to move content to %s", content_path.c_str());
return ES_EIO;
return FS::ConvertResult(rename_result);
}
context.title_import_export.content = {};
@ -437,8 +438,9 @@ ReturnCode ES::ImportTitleDone(Context& context)
// Note: the import hasn't been finalised yet, so the whole title directory
// is still in /import, not /title.
return File::Exists(Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) +
StringFromFormat("/content/%08x.app", content.id));
const std::string path = Common::GetImportTitlePath(title_id) +
StringFromFormat("/content/%08x.app", content.id);
return m_ios.GetFS()->GetMetadata(PID_KERNEL, PID_KERNEL, path).Succeeded();
});
if (!has_all_required_contents)
return ES_EINVAL;
@ -499,17 +501,8 @@ ReturnCode ES::DeleteTitle(u64 title_id)
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_SESSION_ROOT);
if (!File::IsDirectory(title_dir))
return FS_ENOENT;
if (!File::DeleteDirRecursively(title_dir))
{
ERROR_LOG(IOS_ES, "DeleteTitle: Failed to delete title directory: %s", title_dir.c_str());
return FS_EACCESS;
}
return IPC_SUCCESS;
const std::string title_dir = Common::GetTitlePath(title_id);
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, title_dir));
}
IPCCommandResult ES::DeleteTitle(const IOCtlVRequest& request)
@ -523,6 +516,7 @@ IPCCommandResult ES::DeleteTitle(const IOCtlVRequest& request)
ReturnCode ES::DeleteTicket(const u8* ticket_view)
{
const auto fs = m_ios.GetFS();
const u64 title_id = Common::swap64(ticket_view + offsetof(IOS::ES::TicketView, title_id));
if (!CanDeleteTitle(title_id))
@ -536,24 +530,26 @@ ReturnCode ES::DeleteTicket(const u8* ticket_view)
ticket.DeleteTicket(ticket_id);
const std::vector<u8>& new_ticket = ticket.GetBytes();
const std::string ticket_path = Common::GetTicketFileName(title_id, Common::FROM_SESSION_ROOT);
const std::string ticket_path = Common::GetTicketFileName(title_id);
if (!new_ticket.empty())
{
File::IOFile ticket_file(ticket_path, "wb");
if (!ticket_file || !ticket_file.WriteBytes(new_ticket.data(), new_ticket.size()))
const auto file = fs->OpenFile(PID_KERNEL, PID_KERNEL, ticket_path, FS::Mode::ReadWrite);
if (!file || !file->Write(new_ticket.data(), new_ticket.size()))
return ES_EIO;
}
else
{
// Delete the ticket file if it is now empty.
if (new_ticket.empty())
File::Delete(ticket_path);
fs->Delete(PID_KERNEL, PID_KERNEL, ticket_path);
}
// Delete the ticket directory if it is now empty.
const std::string ticket_parent_dir =
Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) +
StringFromFormat("/ticket/%08x", static_cast<u32>(title_id >> 32));
const auto ticket_parent_dir_entries = File::ScanDirectoryTree(ticket_parent_dir, false);
if (ticket_parent_dir_entries.children.empty())
File::DeleteDir(ticket_parent_dir);
const auto ticket_parent_dir_entries =
fs->ReadDirectory(PID_KERNEL, PID_KERNEL, ticket_parent_dir);
if (ticket_parent_dir_entries && ticket_parent_dir_entries->empty())
fs->Delete(PID_KERNEL, PID_KERNEL, ticket_parent_dir);
return IPC_SUCCESS;
}
@ -573,14 +569,15 @@ ReturnCode ES::DeleteTitleContent(u64 title_id) const
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
const std::string content_dir = Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT);
if (!File::IsDirectory(content_dir))
return FS_ENOENT;
const std::string content_dir = Common::GetTitleContentPath(title_id);
const auto files = m_ios.GetFS()->ReadDirectory(PID_KERNEL, PID_KERNEL, content_dir);
if (!files)
return FS::ConvertResult(files.Error());
for (const auto& file : File::ScanDirectoryTree(content_dir, false).children)
for (const std::string& file_name : *files)
{
if (file.virtualName.size() == 12 && file.virtualName.compare(8, 4, ".app") == 0)
File::Delete(file.physicalName);
if (file_name.size() == 12 && file_name.compare(8, 4, ".app") == 0)
m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, content_dir + '/' + file_name);
}
return IPC_SUCCESS;
@ -606,13 +603,9 @@ ReturnCode ES::DeleteContent(u64 title_id, u32 content_id) const
if (!tmd.FindContentById(content_id, &content))
return ES_EINVAL;
if (!File::Delete(Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) +
StringFromFormat("/%08x.app", content_id)))
{
return FS_ENOENT;
}
return IPC_SUCCESS;
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL,
Common::GetTitleContentPath(title_id) +
StringFromFormat("/%08x.app", content_id)));
}
IPCCommandResult ES::DeleteContent(const IOCtlVRequest& request)
@ -812,7 +805,7 @@ ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& sha1) const
return ES_EINVAL;
// Delete the shared content and update the content map.
const auto delete_result = m_ios.GetFS()->Delete(0, 0, *content_path);
const auto delete_result = m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, *content_path);
if (delete_result != FS::ResultCode::Success)
return FS::ConvertResult(delete_result);