IOS/ES: Make sure all contents are imported
This adds a check to ImportTitleDone to make sure all required contents that are listed in the TMD have been imported before allowing to finish the import. Not checking for this could allow titles to be left in an inconsistent state.
This commit is contained in:
parent
4d08e90f26
commit
3613f33c9b
|
@ -61,6 +61,11 @@ bool Content::IsShared() const
|
||||||
return (type & 0x8000) != 0;
|
return (type & 0x8000) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Content::IsOptional() const
|
||||||
|
{
|
||||||
|
return (type & 0x4000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
SignedBlobReader::SignedBlobReader(const std::vector<u8>& bytes) : m_bytes(bytes)
|
SignedBlobReader::SignedBlobReader(const std::vector<u8>& bytes) : m_bytes(bytes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ static_assert(sizeof(TMDHeader) == 0x1e4, "TMDHeader has the wrong size");
|
||||||
struct Content
|
struct Content
|
||||||
{
|
{
|
||||||
bool IsShared() const;
|
bool IsShared() const;
|
||||||
|
bool IsOptional() const;
|
||||||
u32 id;
|
u32 id;
|
||||||
u16 index;
|
u16 index;
|
||||||
u16 type;
|
u16 type;
|
||||||
|
|
|
@ -353,13 +353,31 @@ ReturnCode ES::ImportTitleDone(Context& context)
|
||||||
if (!context.title_import.tmd.IsValid() || context.title_import.content_id != 0xFFFFFFFF)
|
if (!context.title_import.tmd.IsValid() || context.title_import.content_id != 0xFFFFFFFF)
|
||||||
return ES_EINVAL;
|
return ES_EINVAL;
|
||||||
|
|
||||||
|
// Make sure all listed, non-optional contents have been imported.
|
||||||
|
const u64 title_id = context.title_import.tmd.GetTitleId();
|
||||||
|
const std::vector<IOS::ES::Content> contents = context.title_import.tmd.GetContents();
|
||||||
|
const IOS::ES::SharedContentMap shared_content_map{Common::FROM_SESSION_ROOT};
|
||||||
|
const bool has_all_required_contents =
|
||||||
|
std::all_of(contents.cbegin(), contents.cend(), [&](const IOS::ES::Content& content) {
|
||||||
|
if (content.IsOptional())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (content.IsShared())
|
||||||
|
return shared_content_map.GetFilenameFromSHA1(content.sha1).has_value();
|
||||||
|
|
||||||
|
return File::Exists(Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) +
|
||||||
|
StringFromFormat("%08x.app", content.id));
|
||||||
|
});
|
||||||
|
if (!has_all_required_contents)
|
||||||
|
return ES_EINVAL;
|
||||||
|
|
||||||
if (!WriteImportTMD(context.title_import.tmd))
|
if (!WriteImportTMD(context.title_import.tmd))
|
||||||
return ES_EIO;
|
return ES_EIO;
|
||||||
|
|
||||||
if (!FinishImport(context.title_import.tmd))
|
if (!FinishImport(context.title_import.tmd))
|
||||||
return ES_EIO;
|
return ES_EIO;
|
||||||
|
|
||||||
INFO_LOG(IOS_ES, "ImportTitleDone: title %016" PRIx64, context.title_import.tmd.GetTitleId());
|
INFO_LOG(IOS_ES, "ImportTitleDone: title %016" PRIx64, title_id);
|
||||||
context.title_import.tmd.SetBytes({});
|
context.title_import.tmd.SetBytes({});
|
||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue