diff --git a/src/citra_qt/game_list_worker.cpp b/src/citra_qt/game_list_worker.cpp index a20ae4794..f03244637 100644 --- a/src/citra_qt/game_list_worker.cpp +++ b/src/citra_qt/game_list_worker.cpp @@ -46,13 +46,15 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign const bool is_dir = FileUtil::IsDirectory(physical_name); if (!is_dir && HasSupportedFileExtension(physical_name)) { std::unique_ptr loader = Loader::GetLoader(physical_name); - if (!loader) + if (!loader) { return true; + } bool executable = false; - loader->IsExecutable(executable); - if (!executable) + const auto res = loader->IsExecutable(executable); + if (!executable && res != Loader::ResultStatus::ErrorEncrypted) { return true; + } u64 program_id = 0; loader->ReadProgramId(program_id); diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp index 056f7a901..cb8a2d513 100644 --- a/src/core/file_sys/ncch_container.cpp +++ b/src/core/file_sys/ncch_container.cpp @@ -133,8 +133,39 @@ Loader::ResultStatus NCCHContainer::OpenFile(const std::string& filepath, u32 nc return Loader::ResultStatus::Success; } +Loader::ResultStatus NCCHContainer::LoadHeader() { + if (has_header) { + return Loader::ResultStatus::Success; + } + if (!file.IsOpen()) { + return Loader::ResultStatus::Error; + } + + // Reset read pointer in case this file has been read before. + file.Seek(ncch_offset, SEEK_SET); + + if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) { + return Loader::ResultStatus::Error; + } + + // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... + if (Loader::MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { + LOG_DEBUG(Service_FS, "Only loading the first (bootable) NCCH within the NCSD file!"); + ncch_offset += 0x4000; + file.Seek(ncch_offset, SEEK_SET); + file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); + } + + // Verify we are loading the correct file type... + if (Loader::MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic) { + return Loader::ResultStatus::ErrorInvalidFormat; + } + + has_header = true; + return Loader::ResultStatus::Success; +} + Loader::ResultStatus NCCHContainer::Load() { - LOG_INFO(Service_FS, "Loading NCCH from file {}", filepath); if (is_loaded) return Loader::ResultStatus::Success; @@ -697,7 +728,7 @@ Loader::ResultStatus NCCHContainer::ReadOverrideRomFS(std::shared_ptr> Ticket::GetTitleKey() const { std::memcpy(ctr.data(), &ticket_body.title_id, sizeof(u64)); HW::AES::SelectCommonKeyIndex(ticket_body.common_key_index); if (!HW::AES::IsNormalKeyAvailable(HW::AES::KeySlotID::TicketCommonKey)) { + LOG_ERROR(Service_FS, "CommonKey {} missing", ticket_body.common_key_index); return {}; } auto key = HW::AES::GetNormalKey(HW::AES::KeySlotID::TicketCommonKey); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 65b9c3e01..31df828e3 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -373,6 +374,37 @@ InstallStatus InstallCIA(const std::string& path, installFile.Close(); LOG_INFO(Service_AM, "Installed {} successfully.", path); + + const FileUtil::DirectoryEntryCallable callback = + [&callback](u64* num_entries_out, const std::string& directory, + const std::string& virtual_name) -> bool { + const std::string physical_name = directory + DIR_SEP + virtual_name; + const bool is_dir = FileUtil::IsDirectory(physical_name); + if (!is_dir) { + std::unique_ptr loader = Loader::GetLoader(physical_name); + if (!loader) { + return true; + } + + bool executable = false; + const auto res = loader->IsExecutable(executable); + if (res == Loader::ResultStatus::ErrorEncrypted) { + return false; + } + return true; + } else { + return FileUtil::ForeachDirectoryEntry(nullptr, physical_name, callback); + } + }; + if (!FileUtil::ForeachDirectoryEntry( + nullptr, + GetTitlePath( + Service::AM::GetTitleMediaType(container.GetTitleMetadata().GetTitleID()), + container.GetTitleMetadata().GetTitleID()), + callback)) { + LOG_ERROR(Service_AM, "CIA {} contained encrypted files.", path); + return InstallStatus::ErrorEncrypted; + } return InstallStatus::Success; }