Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IOS/ES: Implement ES_GetStoredContents ioctlvs properly #5054

Merged
merged 1 commit into from
Mar 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
123 changes: 94 additions & 29 deletions Source/Core/Core/IOS/ES/ES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return AddTitleFinish(request);
case IOCTL_ES_GETDEVICEID:
return ESGetDeviceID(request);
case IOCTL_ES_GETTITLECONTENTSCNT:
return GetTitleContentsCount(request);
case IOCTL_ES_GETTITLECONTENTS:
return GetTitleContents(request);
case IOCTL_ES_OPENTITLECONTENT:
return OpenTitleContent(request);
case IOCTL_ES_OPENCONTENT:
Expand All @@ -354,6 +350,15 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
case IOCTL_ES_GETTITLES:
return GetTitles(request);

case IOCTL_ES_GETTITLECONTENTSCNT:
return GetStoredContentsCount(request);
case IOCTL_ES_GETTITLECONTENTS:
return GetStoredContents(request);
case IOCTL_ES_GETSTOREDCONTENTCNT:
return GetTMDStoredContentsCount(request);
case IOCTL_ES_GETSTOREDCONTENTS:
return GetTMDStoredContents(request);

case IOCTL_ES_GETVIEWCNT:
return GetViewCount(request);
case IOCTL_ES_GETVIEWS:
Expand Down Expand Up @@ -632,49 +637,109 @@ IPCCommandResult ES::ESGetDeviceID(const IOCtlVRequest& request)
return GetDefaultReply(IPC_SUCCESS);
}

IPCCommandResult ES::GetTitleContentsCount(const IOCtlVRequest& request)
static std::vector<IOS::ES::Content> GetStoredContentsFromTMD(const IOS::ES::TMDReader& tmd)
{
if (!request.HasNumberOfValidVectors(1, 1))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
if (!tmd.IsValid())
return {};

u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const DiscIO::CSharedContent shared{Common::FROM_SESSION_ROOT};
const std::vector<IOS::ES::Content> contents = tmd.GetContents();

std::vector<IOS::ES::Content> stored_contents;

std::copy_if(contents.begin(), contents.end(), std::back_inserter(stored_contents),
[&tmd, &shared](const auto& content) {
if (content.IsShared())
{
const std::string path = shared.GetFilenameFromSHA1(content.sha1.data());
return path != "unk" && File::Exists(path);
}
return File::Exists(
Common::GetTitleContentPath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT));
});

return stored_contents;
}

const DiscIO::CNANDContentLoader& nand_content = AccessContentDevice(TitleID);
if (!nand_content.IsValid() || !nand_content.GetTMD().IsValid())
// Used by the GetStoredContents ioctlvs. This assumes that the first output vector
// is used for the content count (u32).
IPCCommandResult ES::GetStoredContentsCount(const IOS::ES::TMDReader& tmd,
const IOCtlVRequest& request)
{
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

const u16 num_contents = nand_content.GetTMD().GetNumContents();
const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
Memory::Write_U32(num_contents, request.io_vectors[0].address);

if ((u32)(TitleID >> 32) == 0x00010000)
Memory::Write_U32(0, request.io_vectors[0].address);
else
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,
num_contents, tmd.GetTitleId());
return GetDefaultReply(IPC_SUCCESS);
}

INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",
(u32)(TitleID >> 32), (u32)TitleID, num_contents);
// Used by the GetStoredContents ioctlvs. This assumes that the second input vector is used
// for the content count and the output vector is used to store a list of content IDs (u32s).
IPCCommandResult ES::GetStoredContents(const IOS::ES::TMDReader& tmd, const IOCtlVRequest& request)
{
if (!tmd.IsValid())
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

if (request.in_vectors[1].size != sizeof(u32) ||
request.io_vectors[0].size != Memory::Read_U32(request.in_vectors[1].address) * sizeof(u32))
{
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
}

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));

return GetDefaultReply(IPC_SUCCESS);
}

IPCCommandResult ES::GetTitleContents(const IOCtlVRequest& request)
IPCCommandResult ES::GetStoredContentsCount(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id);
if (!content_loader.IsValid())
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
return GetStoredContentsCount(content_loader.GetTMD(), request);
}

const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
if (!rNANDContent.IsValid() || !rNANDContent.GetTMD().IsValid())
IPCCommandResult ES::GetStoredContents(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

for (const auto& content : rNANDContent.GetTMD().GetContents())
{
const u16 index = content.index;
Memory::Write_U32(content.id, request.io_vectors[0].address + index * 4);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", index, content.id);
}
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id);
if (!content_loader.IsValid())
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
return GetStoredContents(content_loader.GetTMD(), request);
}

return GetDefaultReply(IPC_SUCCESS);
IPCCommandResult ES::GetTMDStoredContentsCount(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
return GetStoredContentsCount(IOS::ES::TMDReader{std::move(tmd_bytes)}, request);
}

IPCCommandResult ES::GetTMDStoredContents(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
return GetStoredContents(IOS::ES::TMDReader{std::move(tmd_bytes)}, request);
}

IPCCommandResult ES::OpenTitleContent(const IOCtlVRequest& request)
Expand Down
10 changes: 8 additions & 2 deletions Source/Core/Core/IOS/ES/ES.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ class ES : public Device
IPCCommandResult AddContentFinish(const IOCtlVRequest& request);
IPCCommandResult AddTitleFinish(const IOCtlVRequest& request);
IPCCommandResult ESGetDeviceID(const IOCtlVRequest& request);
IPCCommandResult GetTitleContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetTitleContents(const IOCtlVRequest& request);
IPCCommandResult OpenTitleContent(const IOCtlVRequest& request);
IPCCommandResult OpenContent(const IOCtlVRequest& request);
IPCCommandResult ReadContent(const IOCtlVRequest& request);
Expand All @@ -175,6 +173,14 @@ class ES : public Device
IPCCommandResult GetTitleCount(const IOCtlVRequest& request);
IPCCommandResult GetTitles(const IOCtlVRequest& request);

IPCCommandResult GetStoredContentsCount(const IOS::ES::TMDReader& tmd,
const IOCtlVRequest& request);
IPCCommandResult GetStoredContents(const IOS::ES::TMDReader& tmd, const IOCtlVRequest& request);
IPCCommandResult GetStoredContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetStoredContents(const IOCtlVRequest& request);
IPCCommandResult GetTMDStoredContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetTMDStoredContents(const IOCtlVRequest& request);

IPCCommandResult GetViewCount(const IOCtlVRequest& request);
IPCCommandResult GetViews(const IOCtlVRequest& request);
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
Expand Down