mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
IOS/ES: Implement ES_DeleteSharedContent
This commit is contained in:
parent
a0e4bb4aa6
commit
2e8e420623
@ -471,6 +471,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||||||
return DeleteTicket(request);
|
return DeleteTicket(request);
|
||||||
case IOCTL_ES_DELETETITLECONTENT:
|
case IOCTL_ES_DELETETITLECONTENT:
|
||||||
return DeleteTitleContent(request);
|
return DeleteTitleContent(request);
|
||||||
|
case IOCTL_ES_DELETESHAREDCONTENT:
|
||||||
|
return DeleteSharedContent(request);
|
||||||
case IOCTL_ES_GETSTOREDTMDSIZE:
|
case IOCTL_ES_GETSTOREDTMDSIZE:
|
||||||
return GetStoredTMDSize(request);
|
return GetStoredTMDSize(request);
|
||||||
case IOCTL_ES_GETSTOREDTMD:
|
case IOCTL_ES_GETSTOREDTMD:
|
||||||
@ -503,7 +505,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||||||
return GetBoot2Version(request);
|
return GetBoot2Version(request);
|
||||||
|
|
||||||
case IOCTL_ES_VERIFYSIGN:
|
case IOCTL_ES_VERIFYSIGN:
|
||||||
case IOCTL_ES_DELETESHAREDCONTENT:
|
|
||||||
case IOCTL_ES_UNKNOWN_3B:
|
case IOCTL_ES_UNKNOWN_3B:
|
||||||
case IOCTL_ES_UNKNOWN_3C:
|
case IOCTL_ES_UNKNOWN_3C:
|
||||||
case IOCTL_ES_UNKNOWN_3D:
|
case IOCTL_ES_UNKNOWN_3D:
|
||||||
|
@ -114,6 +114,7 @@ public:
|
|||||||
ReturnCode DeleteTitle(u64 title_id);
|
ReturnCode DeleteTitle(u64 title_id);
|
||||||
ReturnCode DeleteTitleContent(u64 title_id) const;
|
ReturnCode DeleteTitleContent(u64 title_id) const;
|
||||||
ReturnCode DeleteTicket(const u8* ticket_view);
|
ReturnCode DeleteTicket(const u8* ticket_view);
|
||||||
|
ReturnCode DeleteSharedContent(const std::array<u8, 20>& sha1) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
@ -209,6 +210,7 @@ private:
|
|||||||
IPCCommandResult DeleteTitle(const IOCtlVRequest& request);
|
IPCCommandResult DeleteTitle(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
|
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
|
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
|
||||||
|
IPCCommandResult DeleteSharedContent(const IOCtlVRequest& request);
|
||||||
|
|
||||||
// Device identity and encryption
|
// Device identity and encryption
|
||||||
IPCCommandResult GetConsoleID(const IOCtlVRequest& request);
|
IPCCommandResult GetConsoleID(const IOCtlVRequest& request);
|
||||||
|
@ -423,16 +423,34 @@ std::string SharedContentMap::AddSharedContent(const std::array<u8, 20>& sha1)
|
|||||||
entry.sha1 = sha1;
|
entry.sha1 = sha1;
|
||||||
m_entries.push_back(entry);
|
m_entries.push_back(entry);
|
||||||
|
|
||||||
File::CreateFullPath(m_file_path);
|
WriteEntries();
|
||||||
|
|
||||||
File::IOFile file(m_file_path, "ab");
|
|
||||||
file.WriteArray(&entry, 1);
|
|
||||||
|
|
||||||
filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str());
|
filename = Common::RootUserPath(m_root) + StringFromFormat("/shared1/%s.app", id.c_str());
|
||||||
m_last_id++;
|
m_last_id++;
|
||||||
return filename;
|
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)
|
static std::pair<u32, u64> ReadUidSysEntry(File::IOFile& file)
|
||||||
{
|
{
|
||||||
u64 title_id = 0;
|
u64 title_id = 0;
|
||||||
|
@ -212,9 +212,12 @@ public:
|
|||||||
|
|
||||||
std::string GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
|
std::string GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
|
||||||
std::string AddSharedContent(const std::array<u8, 20>& sha1);
|
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;
|
std::vector<std::array<u8, 20>> GetHashes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool WriteEntries() const;
|
||||||
|
|
||||||
struct Entry;
|
struct Entry;
|
||||||
Common::FromWhichRoot m_root;
|
Common::FromWhichRoot m_root;
|
||||||
u32 m_last_id = 0;
|
u32 m_last_id = 0;
|
||||||
|
@ -622,6 +622,51 @@ IPCCommandResult ES::ExportTitleDone(Context& context, const IOCtlVRequest& requ
|
|||||||
{
|
{
|
||||||
return GetDefaultReply(ExportTitleDone(context));
|
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 Device
|
||||||
} // namespace HLE
|
} // namespace HLE
|
||||||
} // namespace IOS
|
} // namespace IOS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user