ES: Use new filesystem interface in TitleManagement
This commit is contained in:
parent
9ee2654be6
commit
923b450268
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue