Merge pull request #5454 from leoetlino/es-delete-shared-content
IOS/ES: Implement ES_DeleteSharedContent
This commit is contained in:
commit
7af05fd9e6
|
@ -471,6 +471,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
return DeleteTicket(request);
|
||||
case IOCTL_ES_DELETETITLECONTENT:
|
||||
return DeleteTitleContent(request);
|
||||
case IOCTL_ES_DELETESHAREDCONTENT:
|
||||
return DeleteSharedContent(request);
|
||||
case IOCTL_ES_GETSTOREDTMDSIZE:
|
||||
return GetStoredTMDSize(request);
|
||||
case IOCTL_ES_GETSTOREDTMD:
|
||||
|
@ -503,7 +505,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
return GetBoot2Version(request);
|
||||
|
||||
case IOCTL_ES_VERIFYSIGN:
|
||||
case IOCTL_ES_DELETESHAREDCONTENT:
|
||||
case IOCTL_ES_UNKNOWN_3B:
|
||||
case IOCTL_ES_UNKNOWN_3C:
|
||||
case IOCTL_ES_UNKNOWN_3D:
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
ReturnCode DeleteTitle(u64 title_id);
|
||||
ReturnCode DeleteTitleContent(u64 title_id) const;
|
||||
ReturnCode DeleteTicket(const u8* ticket_view);
|
||||
ReturnCode DeleteSharedContent(const std::array<u8, 20>& sha1) const;
|
||||
|
||||
private:
|
||||
enum
|
||||
|
@ -209,6 +210,7 @@ private:
|
|||
IPCCommandResult DeleteTitle(const IOCtlVRequest& request);
|
||||
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
|
||||
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
|
||||
IPCCommandResult DeleteSharedContent(const IOCtlVRequest& request);
|
||||
|
||||
// Device identity and encryption
|
||||
IPCCommandResult GetConsoleID(const IOCtlVRequest& request);
|
||||
|
|
|
@ -434,16 +434,34 @@ std::string SharedContentMap::AddSharedContent(const std::array<u8, 20>& sha1)
|
|||
entry.sha1 = sha1;
|
||||
m_entries.push_back(entry);
|
||||
|
||||
File::CreateFullPath(m_file_path);
|
||||
|
||||
File::IOFile file(m_file_path, "ab");
|
||||
file.WriteArray(&entry, 1);
|
||||
|
||||
WriteEntries();
|
||||
filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str());
|
||||
m_last_id++;
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool SharedContentMap::DeleteSharedContent(const std::array<u8, 20>& sha1)
|
||||
{
|
||||
m_entries.erase(std::remove_if(m_entries.begin(), m_entries.end(),
|
||||
[&sha1](const auto& entry) { return entry.sha1 == sha1; }),
|
||||
m_entries.end());
|
||||
return WriteEntries();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Atomically write the new content map.
|
||||
File::IOFile file(temp_path, "w+b");
|
||||
if (!file.WriteArray(m_entries.data(), m_entries.size()))
|
||||
return false;
|
||||
File::CreateFullPath(m_file_path);
|
||||
return File::RenameSync(temp_path, m_file_path);
|
||||
}
|
||||
|
||||
static std::pair<u32, u64> ReadUidSysEntry(File::IOFile& file)
|
||||
{
|
||||
u64 title_id = 0;
|
||||
|
|
|
@ -213,9 +213,12 @@ public:
|
|||
|
||||
std::string GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
|
||||
std::string AddSharedContent(const std::array<u8, 20>& sha1);
|
||||
bool DeleteSharedContent(const std::array<u8, 20>& sha1);
|
||||
std::vector<std::array<u8, 20>> GetHashes() const;
|
||||
|
||||
private:
|
||||
bool WriteEntries() const;
|
||||
|
||||
struct Entry;
|
||||
Common::FromWhichRoot m_root;
|
||||
u32 m_last_id = 0;
|
||||
|
|
|
@ -622,6 +622,51 @@ IPCCommandResult ES::ExportTitleDone(Context& context, const IOCtlVRequest& requ
|
|||
{
|
||||
return GetDefaultReply(ExportTitleDone(context));
|
||||
}
|
||||
|
||||
ReturnCode ES::DeleteSharedContent(const std::array<u8, 20>& sha1) const
|
||||
{
|
||||
IOS::ES::SharedContentMap map{Common::FromWhichRoot::FROM_SESSION_ROOT};
|
||||
const std::string content_path = map.GetFilenameFromSHA1(sha1);
|
||||
if (content_path == "unk")
|
||||
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) {
|
||||
if (!IOS::ES::IsTitleType(id, IOS::ES::TitleType::System))
|
||||
return false;
|
||||
|
||||
const auto tmd = IOS::ES::FindInstalledTMD(id);
|
||||
if (!tmd.IsValid())
|
||||
return true;
|
||||
|
||||
const auto contents = tmd.GetContents();
|
||||
return std::any_of(contents.begin(), contents.end(),
|
||||
[&sha1](const auto& content) { return content.sha1 == sha1; });
|
||||
});
|
||||
|
||||
// Any shared content used by a system title cannot be deleted.
|
||||
if (is_used_by_system_title)
|
||||
return ES_EINVAL;
|
||||
|
||||
// Delete the shared content and update the content map.
|
||||
if (!File::Delete(content_path))
|
||||
return FS_ENOENT;
|
||||
|
||||
if (!map.DeleteSharedContent(sha1))
|
||||
return ES_EIO;
|
||||
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
IPCCommandResult ES::DeleteSharedContent(const IOCtlVRequest& request)
|
||||
{
|
||||
std::array<u8, 20> sha1;
|
||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
|
||||
return GetDefaultReply(ES_EINVAL);
|
||||
Memory::CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
||||
return GetDefaultReply(DeleteSharedContent(sha1));
|
||||
}
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
||||
|
|
Loading…
Reference in New Issue