/* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include namespace ams::ncm { PackageSystemUpdateTask::~PackageSystemUpdateTask() { if (m_context_path.GetLength() > 0) { fs::DeleteFile(m_context_path); } this->Inactivate(); } void PackageSystemUpdateTask::Inactivate() { if (m_gamecard_content_meta_database_active) { InactivateContentMetaDatabase(StorageId::GameCard); m_gamecard_content_meta_database_active = false; } } Result PackageSystemUpdateTask::Initialize(const char *package_root, const char *context_path, void *buffer, size_t buffer_size, bool requires_exfat_driver, FirmwareVariationId firmware_variation_id) { /* Set the firmware variation id. */ this->SetFirmwareVariationId(firmware_variation_id); /* Activate the game card content meta database. */ R_TRY(ActivateContentMetaDatabase(StorageId::GameCard)); m_gamecard_content_meta_database_active = true; auto meta_db_guard = SCOPE_GUARD { this->Inactivate(); }; /* Open the game card content meta database. */ OpenContentMetaDatabase(std::addressof(m_package_db), StorageId::GameCard); ContentMetaDatabaseBuilder builder(std::addressof(m_package_db)); /* Cleanup and build the content meta database. */ R_TRY(builder.Cleanup()); R_TRY(builder.BuildFromPackage(package_root)); /* Create a new context file. */ fs::DeleteFile(context_path); R_TRY(FileInstallTaskData::Create(context_path, GameCardMaxContentMetaCount)); auto context_guard = SCOPE_GUARD { fs::DeleteFile(context_path); }; /* Initialize data. */ R_TRY(m_data.Initialize(context_path)); /* Initialize PackageInstallTaskBase. */ u32 config = !requires_exfat_driver ? InstallConfig_SystemUpdate : InstallConfig_SystemUpdate | InstallConfig_RequiresExFatDriver; R_TRY(PackageInstallTaskBase::Initialize(package_root, buffer, buffer_size, StorageId::BuiltInSystem, std::addressof(m_data), config)); /* Cancel guards. */ context_guard.Cancel(); meta_db_guard.Cancel(); /* Set the context path. */ m_context_path.Assign(context_path); R_SUCCEED(); } util::optional PackageSystemUpdateTask::GetSystemUpdateMetaKey() { StorageContentMetaKey storage_keys[0x10]; s32 ofs = 0; s32 count = 0; do { /* List content meta keys. */ if (R_FAILED(this->ListContentMetaKey(std::addressof(count), storage_keys, util::size(storage_keys), ofs, ListContentMetaKeyFilter::All))) { break; } /* Add listed keys to the offset. */ ofs += count; /* Check if any of these keys are for a SystemUpdate. */ for (s32 i = 0; i < count; i++) { const ContentMetaKey &key = storage_keys[i].key; if (key.type == ContentMetaType::SystemUpdate) { return key; } } } while (count > 0); return util::nullopt; } Result PackageSystemUpdateTask::GetInstallContentMetaInfo(InstallContentMetaInfo *out, const ContentMetaKey &key) { /* Get the content info for the key. */ ContentInfo info; R_TRY(this->GetContentInfoOfContentMeta(std::addressof(info), key)); /* Create a new install content meta info. */ *out = InstallContentMetaInfo::MakeUnverifiable(info.GetId(), info.GetSize(), key); R_SUCCEED(); } Result PackageSystemUpdateTask::PrepareInstallContentMetaData() { /* Obtain a SystemUpdate key. */ ContentMetaKey key; auto list_count = m_package_db.ListContentMeta(std::addressof(key), 1, ContentMetaType::SystemUpdate); R_UNLESS(list_count.written > 0, ncm::ResultSystemUpdateNotFoundInPackage()); /* Get the content info for the key. */ ContentInfo info; R_TRY(this->GetContentInfoOfContentMeta(std::addressof(info), key)); /* Prepare the content meta. */ R_RETURN(this->PrepareContentMeta(InstallContentMetaInfo::MakeUnverifiable(info.GetId(), info.GetSize(), key), key, util::nullopt)); } Result PackageSystemUpdateTask::PrepareDependency() { R_RETURN(this->PrepareSystemUpdateDependency()); } Result PackageSystemUpdateTask::GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key) { s32 ofs = 0; while (true) { /* List content infos. */ s32 count; ContentInfo info; R_TRY(m_package_db.ListContentInfo(std::addressof(count), std::addressof(info), 1, key, ofs++)); /* No content infos left to list. */ if (count == 0) { break; } /* Check if the info is for meta content. */ if (info.GetType() == ContentType::Meta) { *out = info; R_SUCCEED(); } } /* Not found. */ R_THROW(ncm::ResultContentInfoNotFound()); } }