mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 12:34:47 +00:00
ncm client: more progress
This commit is contained in:
parent
217bdc3c2f
commit
f70fecfcff
6 changed files with 405 additions and 67 deletions
|
@ -30,5 +30,6 @@
|
|||
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
|
||||
#include <stratosphere/ncm/ncm_install_task.hpp>
|
||||
#include <stratosphere/ncm/ncm_install_task_data.hpp>
|
||||
#include <stratosphere/ncm/ncm_install_task_occupied_size.hpp>
|
||||
#include <stratosphere/ncm/ncm_storage_id_utils.hpp>
|
||||
#include <stratosphere/ncm/ncm_api.hpp>
|
||||
|
|
|
@ -334,11 +334,21 @@ namespace ams::ncm {
|
|||
constexpr PackagedContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
|
||||
|
||||
size_t CalculateConvertInstallContentMetaSize() const;
|
||||
size_t CalculateConvertContentMetaSize() const;
|
||||
|
||||
void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta);
|
||||
void ConvertToInstallContentMeta(void *dst, size_t size, const InstallContentInfo &meta);
|
||||
|
||||
size_t CalculateConvertContentMetaSize() const;
|
||||
void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta);
|
||||
|
||||
Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) {
|
||||
/* TODO */
|
||||
return ResultSuccess();
|
||||
};
|
||||
|
||||
Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version) {
|
||||
/* TODO */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
size_t CountDeltaFragments() const;
|
||||
|
||||
static constexpr size_t CalculateSize(ContentMetaType type, size_t content_count, size_t content_meta_count, size_t extended_data_size) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/ncm/ncm_install_task_data.hpp>
|
||||
#include <stratosphere/ncm/ncm_install_task_occupied_size.hpp>
|
||||
|
||||
namespace ams::ncm {
|
||||
|
||||
|
@ -130,18 +131,21 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta
|
|||
Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size);
|
||||
Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary);
|
||||
InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, std::optional<bool> is_temporary);
|
||||
|
||||
Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional<ContentMetaKey> key, std::optional<u32> source_version);
|
||||
Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version);
|
||||
Result PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer);
|
||||
|
||||
Result GetContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key);
|
||||
|
||||
Result PrepareSystemUpdateDependency();
|
||||
Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key);
|
||||
Result PrepareContentMetaIfLatest(const ContentMetaKey &key);
|
||||
Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out);
|
||||
Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key);
|
||||
Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys);
|
||||
void ResetLastResult();
|
||||
s64 GetThroughput();
|
||||
|
||||
Result CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id);
|
||||
Result FindMaxRequiredApplicationVersion(u32 *out);
|
||||
Result FindMaxRequiredSystemVersion(u32 *out);
|
||||
Result ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset);
|
||||
|
||||
Result CanContinue();
|
||||
void SetFirmwareVariationId(FirmwareVariationId id);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 Adubbz, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
|
||||
|
||||
namespace ams::ncm {
|
||||
|
||||
struct InstallTaskOccupiedSize {
|
||||
ContentMetaKey key;
|
||||
s64 size;
|
||||
StorageId storage_id;
|
||||
u8 reserved[7];
|
||||
};
|
||||
|
||||
}
|
|
@ -218,7 +218,7 @@ namespace ams::ncm {
|
|||
std::scoped_lock lk(placeholder_mutex);
|
||||
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
auto writer = content_meta.GetWriter();
|
||||
StorageId storage_id = static_cast<StorageId>(writer.GetHeader()->storage_id);
|
||||
|
@ -291,7 +291,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Get the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Cleanup the content meta. */
|
||||
/* N doesn't check the result of this. */
|
||||
|
@ -352,7 +352,7 @@ namespace ams::ncm {
|
|||
for (s32 i = offset; i < num_keys; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Write output StorageContentMetaKey. */
|
||||
const auto reader = content_meta.GetReader();
|
||||
|
@ -371,7 +371,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader and check if the content has been committed. */
|
||||
const auto reader = content_meta.GetReader();
|
||||
|
@ -416,7 +416,7 @@ namespace ams::ncm {
|
|||
for (s32 i = offset; i < std::min(count, offset + out_keys_count); i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const auto reader = content_meta.GetReader();
|
||||
|
@ -452,7 +452,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Update the data when we are done. */
|
||||
ON_SCOPE_EXIT { this->data->Update(content_meta, i); };
|
||||
|
@ -555,7 +555,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const auto reader = content_meta.GetReader();
|
||||
|
@ -590,7 +590,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const auto reader = content_meta.GetReader();
|
||||
|
@ -690,7 +690,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Check if the attributes are set for including the exfat driver. */
|
||||
if (content_meta.GetReader().GetHeader()->attributes & ContentMetaAttribute_IncludesExFatDriver) {
|
||||
|
@ -725,6 +725,38 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void InstallTaskBase::IncrementProgress(s64 size) {
|
||||
std::scoped_lock lk(this->progress_mutex);
|
||||
this->progress.installed_size += size;
|
||||
}
|
||||
|
||||
void InstallTaskBase::UpdateThroughputMeasurement(s64 throughput) {
|
||||
std::scoped_lock lk(this->throughput_mutex);
|
||||
|
||||
/* Update throughput only if start time has been set. */
|
||||
if (this->throughput_start_time.GetNanoSeconds() != 0) {
|
||||
this->throughput.installed += throughput;
|
||||
this->throughput.elapsed_time = os::ConvertToTimeSpan(os::GetSystemTick()) - this->throughput_start_time;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallTaskBase::IsNecessaryInstallTicket(const fs::RightsId &rights_id) {
|
||||
/* If the title has no rights, there's no ticket to install. */
|
||||
fs::RightsId empty_rights_id = {};
|
||||
if (std::memcmp(std::addressof(rights_id), std::addressof(empty_rights_id), sizeof(fs::RightsId)) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: Support detecting if a title requires rights. */
|
||||
/* TODO: How should es be handled without undesired effects? */
|
||||
return false;
|
||||
}
|
||||
|
||||
void InstallTaskBase::SetTotalSize(s64 size) {
|
||||
std::scoped_lock(this->progress_mutex);
|
||||
this->progress.total_size = size;
|
||||
}
|
||||
|
||||
Result InstallTaskBase::WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary) {
|
||||
/* Generate a placeholder id. */
|
||||
auto placeholder_id = storage->GeneratePlaceHolderId();
|
||||
|
@ -758,7 +790,81 @@ namespace ams::ncm {
|
|||
};
|
||||
}
|
||||
|
||||
/* ... */
|
||||
Result InstallTaskBase::PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional<ContentMetaKey> key, std::optional<u32> source_version) {
|
||||
/* Open the BuiltInSystem content storage. */
|
||||
ContentStorage content_storage;
|
||||
R_TRY(OpenContentStorage(&content_storage, StorageId::BuiltInSystem));
|
||||
|
||||
/* Write content meta to a placeholder. */
|
||||
InstallContentInfo content_info;
|
||||
R_TRY(this->WriteContentMetaToPlaceHolder(std::addressof(content_info), std::addressof(content_storage), meta_info, std::nullopt));
|
||||
|
||||
/* Get the path of the placeholder. */
|
||||
Path path;
|
||||
content_storage.GetPlaceHolderPath(std::addressof(path), content_info.GetPlaceHolderId());
|
||||
|
||||
const bool is_temporary = content_info.is_temporary;
|
||||
auto temporary_guard = SCOPE_GUARD { content_storage.DeletePlaceHolder(content_info.GetPlaceHolderId()); };
|
||||
|
||||
/* Create a new temporary InstallContentInfo if relevant. */
|
||||
if (is_temporary) {
|
||||
content_info = {
|
||||
.digest = content_info.digest,
|
||||
.info = content_info.info,
|
||||
.placeholder_id = content_info.GetPlaceHolderId(),
|
||||
};
|
||||
}
|
||||
|
||||
/* Retrieve the install content meta data. */
|
||||
AutoBuffer meta;
|
||||
R_TRY(this->GetInstallContentMetaDataFromPath(std::addressof(meta), path, content_info, source_version));
|
||||
|
||||
{
|
||||
/* Create a writer. */
|
||||
InstallContentMetaWriter writer(meta.Get(), meta.GetSize());
|
||||
ON_SCOPE_EXIT { this->data->Push(meta.Get(), meta.GetSize()); };
|
||||
|
||||
/* Update the storage id if BuiltInSystem. */
|
||||
if (this->install_storage == StorageId::BuiltInSystem) {
|
||||
writer.SetStorageId(StorageId::BuiltInSystem);
|
||||
}
|
||||
|
||||
/* Ensure key matches, if provided. */
|
||||
R_UNLESS(!key || *key == writer.GetKey(), ncm::ResultUnexpectedContentMetaPrepared());
|
||||
}
|
||||
|
||||
/* Don't delete the placeholder if not temporary. */
|
||||
if (!is_temporary) {
|
||||
temporary_guard.Cancel();
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version) {
|
||||
AutoBuffer meta;
|
||||
{
|
||||
/* TODO: fs::ScopedAutoAbortDisabler aad; */
|
||||
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
|
||||
}
|
||||
|
||||
/* Create a reader. */
|
||||
PackagedContentMetaReader reader(meta.Get(), meta.GetSize());
|
||||
size_t meta_size;
|
||||
|
||||
if (source_version) {
|
||||
/* Convert to fragment only install content meta. */
|
||||
R_TRY(reader.CalculateConvertFragmentOnlyInstallContentMetaSize(std::addressof(meta_size), *source_version));
|
||||
R_TRY(out->Initialize(meta_size));
|
||||
reader.ConvertToFragmentOnlyInstallContentMeta(out->Get(), out->GetSize(), content_info, *source_version);
|
||||
} else {
|
||||
/* Convert to install content meta. */
|
||||
meta_size = reader.CalculateConvertInstallContentMetaSize();
|
||||
R_TRY(out->Initialize(meta_size));
|
||||
reader.ConvertToInstallContentMeta(out->Get(), out->GetSize(), content_info);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer) {
|
||||
/* Create a reader. */
|
||||
|
@ -776,42 +882,6 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
void InstallTaskBase::IncrementProgress(s64 size) {
|
||||
std::scoped_lock lk(this->progress_mutex);
|
||||
this->progress.installed_size += size;
|
||||
}
|
||||
|
||||
void InstallTaskBase::UpdateThroughputMeasurement(s64 throughput) {
|
||||
std::scoped_lock lk(this->throughput_mutex);
|
||||
|
||||
/* Update throughput only if start time has been set. */
|
||||
if (this->throughput_start_time.GetNanoSeconds() != 0) {
|
||||
this->throughput.installed += throughput;
|
||||
this->throughput.elapsed_time = os::ConvertToTimeSpan(os::GetSystemTick()) - this->throughput_start_time;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallTaskBase::IsNecessaryInstallTicket(const fs::RightsId &rights_id) {
|
||||
/* If the title has no rights, there's no ticket to install. */
|
||||
fs::RightsId empty_rights_id = {};
|
||||
if (std::memcmp(std::addressof(rights_id), std::addressof(empty_rights_id), sizeof(fs::RightsId)) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: Support detecting if a title requires rights. */
|
||||
/* TODO: How should es be handled without undesired effects? */
|
||||
return false;
|
||||
}
|
||||
|
||||
void InstallTaskBase::SetTotalSize(s64 size) {
|
||||
std::scoped_lock(this->progress_mutex);
|
||||
this->progress.total_size = size;
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
void InstallTaskBase::PrepareAgain() {
|
||||
this->SetProgressState(InstallProgressState::NotPrepared);
|
||||
}
|
||||
|
@ -820,13 +890,59 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
// Result InstallTaskBase::PrepareSystemUpdateDependency() {
|
||||
// /* TODO */
|
||||
Result InstallTaskBase::PrepareSystemUpdateDependency() {
|
||||
/* Count the number of content meta entries. */
|
||||
s32 count;
|
||||
R_TRY(this->data->Count(std::addressof(count)));
|
||||
|
||||
// return ResultSuccess();
|
||||
// }
|
||||
/* Cleanup on failure. */
|
||||
auto guard = SCOPE_GUARD { this->Cleanup(); };
|
||||
|
||||
Result InstallTaskBase::GetContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key) {
|
||||
/* Iterate over content meta. */
|
||||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
|
||||
/* Skip non system update content metas. */
|
||||
if (reader.GetHeader()->type != ContentMetaType::SystemUpdate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* List content meta infos. */
|
||||
std::unique_ptr<ContentMetaInfo[]> content_meta_infos;
|
||||
s32 num_content_meta_infos;
|
||||
R_TRY(this->ReadContentMetaInfoList(std::addressof(num_content_meta_infos), std::addressof(content_meta_infos), reader.GetKey()));
|
||||
|
||||
/* Iterate over content meta infos. */
|
||||
for (s32 j = 0; j < num_content_meta_infos; j++) {
|
||||
ContentMetaInfo &content_meta_info = content_meta_infos[j];
|
||||
const ContentMetaKey content_meta_info_key = content_meta_info.ToKey();
|
||||
|
||||
/* If exfat driver is not included or is required. */
|
||||
if (!(content_meta_info.attributes & ContentMetaAttribute_IncludesExFatDriver) || this->config & InstallConfig_RequiresExFatDriver) {
|
||||
/* Check if this content meta info is newer than what is already installed. */
|
||||
bool newer_than_installed;
|
||||
R_TRY(this->IsNewerThanInstalled(std::addressof(newer_than_installed), content_meta_info_key));
|
||||
|
||||
if (newer_than_installed) {
|
||||
/* Get and prepare install content meta info. */
|
||||
InstallContentMetaInfo install_content_meta_info;
|
||||
R_TRY(this->GetInstallContentMetaInfo(std::addressof(install_content_meta_info), content_meta_info_key));
|
||||
R_TRY(this->PrepareContentMeta(install_content_meta_info, content_meta_info_key, std::nullopt));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key) {
|
||||
/* Get the install content meta info. */
|
||||
InstallContentMetaInfo install_content_meta_info;
|
||||
R_TRY(this->GetInstallContentMetaInfo(std::addressof(install_content_meta_info), key));
|
||||
|
@ -839,7 +955,7 @@ namespace ams::ncm {
|
|||
InstallContentInfo content_info;
|
||||
R_TRY(this->WriteContentMetaToPlaceHolder(std::addressof(content_info), std::addressof(content_storage), install_content_meta_info, true));
|
||||
|
||||
const PlaceHolderId placeholder_id = content_info.placeholder_id;
|
||||
const PlaceHolderId placeholder_id = content_info.GetPlaceHolderId();
|
||||
|
||||
/* Get the path of the new placeholder. */
|
||||
Path path;
|
||||
|
@ -853,7 +969,79 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* ... */
|
||||
Result InstallTaskBase::PrepareContentMetaIfLatest(const ContentMetaKey &key) {
|
||||
/* Check if the key is newer than what is already installed. */
|
||||
bool newer_than_installed;
|
||||
R_TRY(this->IsNewerThanInstalled(std::addressof(newer_than_installed), key));
|
||||
|
||||
if (newer_than_installed) {
|
||||
/* Get and prepare install content meta info. */
|
||||
InstallContentMetaInfo install_content_meta_info;
|
||||
R_TRY(this->GetInstallContentMetaInfo(std::addressof(install_content_meta_info), key));
|
||||
R_TRY(this->PrepareContentMeta(install_content_meta_info, key, std::nullopt));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out) {
|
||||
/* Open the BuiltInSystem content meta database. */
|
||||
ContentMetaDatabase meta_db;
|
||||
R_TRY(OpenContentMetaDatabase(std::addressof(meta_db), StorageId::BuiltInSystem));
|
||||
|
||||
/* Count the number of content meta entries. */
|
||||
s32 count;
|
||||
R_TRY(this->data->Count(std::addressof(count)));
|
||||
|
||||
/* Iterate over content meta. */
|
||||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
|
||||
/* Skip non system update content metas. */
|
||||
if (reader.GetHeader()->type != ContentMetaType::SystemUpdate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* List content meta infos. */
|
||||
std::unique_ptr<ContentMetaInfo[]> content_meta_infos;
|
||||
s32 num_content_meta_infos;
|
||||
R_TRY(this->ReadContentMetaInfoList(std::addressof(num_content_meta_infos), std::addressof(content_meta_infos), reader.GetKey()));
|
||||
|
||||
/* Iterate over content meta infos. */
|
||||
for (s32 j = 0; j < num_content_meta_infos; j++) {
|
||||
const ContentMetaInfo &content_meta_info = content_meta_infos[j];
|
||||
bool not_found = false;
|
||||
|
||||
/* Get the latest key. */
|
||||
ContentMetaKey installed_key;
|
||||
R_TRY_CATCH(meta_db.GetLatest(std::addressof(installed_key), content_meta_info.id)) {
|
||||
R_CATCH(ncm::ResultContentMetaNotFound) {
|
||||
/* Key doesn't exist, this is okay. */
|
||||
not_found = true;
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* Exfat driver included, but not required. */
|
||||
if (content_meta_info.attributes & ContentMetaAttribute_IncludesExFatDriver && !(this->config & InstallConfig_RequiresExFatDriver)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not found or installed version is below the content meta info version, and this is not a rebootless content meta info. */
|
||||
if ((not_found || installed_key.version < content_meta_info.version) && !(content_meta_info.attributes & ContentMetaAttribute_Rebootless)) {
|
||||
*out = SystemUpdateTaskApplyInfo::RequireReboot;
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out = SystemUpdateTaskApplyInfo::RequireNoReboot;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::IsNewerThanInstalled(bool *out, const ContentMetaKey &key) {
|
||||
/* Obtain a list of suitable storage ids. */
|
||||
|
@ -868,7 +1056,10 @@ namespace ams::ncm {
|
|||
/* Get the latest key. */
|
||||
ContentMetaKey installed_key;
|
||||
R_TRY_CATCH(meta_db.GetLatest(std::addressof(installed_key), key.id)) {
|
||||
R_CATCH(ncm::ResultContentMetaNotFound) { /* Key doesn't exist, this is okay. */ }
|
||||
R_CATCH(ncm::ResultContentMetaNotFound) {
|
||||
/* Key doesn't exist, this is okay. */
|
||||
continue;
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* Check if installed key is newer. */
|
||||
|
@ -897,7 +1088,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Cleanup if the input keys contain this key. */
|
||||
if (Contains(keys, num_keys, content_meta.GetReader().GetKey())) {
|
||||
|
@ -922,7 +1113,58 @@ namespace ams::ncm {
|
|||
return this->throughput.installed;
|
||||
}
|
||||
|
||||
/* ... */
|
||||
Result InstallTaskBase::CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id) {
|
||||
/* Count the number of content meta entries. */
|
||||
s32 count;
|
||||
R_TRY(this->data->Count(std::addressof(count)));
|
||||
|
||||
/* Open the content storage. */
|
||||
ContentStorage content_storage;
|
||||
R_TRY(ncm::OpenContentStorage(&content_storage, storage_id));
|
||||
|
||||
/* Iterate over content meta. */
|
||||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
|
||||
/* Skip this content meta if the key doesn't match. */
|
||||
if (reader.GetKey() != key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Storage id may either by Any, or it must not be None and match the input storage id. */
|
||||
if (storage_id != StorageId::Any && (storage_id == StorageId::None || storage_id != reader.GetStorageId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set the out size to 0. */
|
||||
*out_size = 0;
|
||||
|
||||
/* Sum the sizes from the content infos. */
|
||||
for (size_t j = 0; j < reader.GetContentCount(); j++) {
|
||||
const auto *content_info = reader.GetContentInfo(j);
|
||||
|
||||
/* Check if this content info has a placeholder. */
|
||||
bool has_placeholder;
|
||||
R_TRY(content_storage.HasPlaceHolder(std::addressof(has_placeholder), content_info->GetPlaceHolderId()));
|
||||
|
||||
/* Add the placeholder size to the total. */
|
||||
if (has_placeholder) {
|
||||
*out_size += content_info->GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
/* No need to look for any further keys. */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
*out_size = 0;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::FindMaxRequiredApplicationVersion(u32 *out) {
|
||||
/* Count the number of content meta entries. */
|
||||
|
@ -935,7 +1177,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
|
@ -966,7 +1208,7 @@ namespace ams::ncm {
|
|||
for (s32 i = 0; i < count; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(&content_meta, i));
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
|
@ -992,7 +1234,59 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* ... */
|
||||
Result InstallTaskBase::ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset) {
|
||||
AMS_ABORT_UNLESS(offset >= 0);
|
||||
|
||||
/* Count the number of content meta entries. */
|
||||
s32 data_count;
|
||||
R_TRY(this->data->Count(std::addressof(data_count)));
|
||||
|
||||
/* Iterate over content meta. */
|
||||
s32 count = 0;
|
||||
for (s32 i = offset; i < data_count && count < out_list_size; i++) {
|
||||
/* Obtain the content meta. */
|
||||
InstallContentMeta content_meta;
|
||||
R_TRY(this->data->Get(std::addressof(content_meta), i));
|
||||
|
||||
/* Create a reader. */
|
||||
const InstallContentMetaReader reader = content_meta.GetReader();
|
||||
const StorageId storage_id = reader.GetStorageId();
|
||||
|
||||
s64 total_size = 0;
|
||||
|
||||
for (size_t j = 0; j < reader.GetContentCount(); j++) {
|
||||
const auto *content_info = reader.GetContentInfo(j);
|
||||
|
||||
/* Skip the content info if not prepared. */
|
||||
if (content_info->GetInstallState() == InstallState::NotPrepared) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Open the relevant content storage. */
|
||||
ContentStorage content_storage;
|
||||
R_TRY_CATCH(ncm::OpenContentStorage(std::addressof(content_storage), storage_id)) {
|
||||
R_CATCH(ncm::ResultContentStorageNotActive) { break; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* Check if this content info has a placeholder. */
|
||||
bool has_placeholder;
|
||||
R_TRY(content_storage.HasPlaceHolder(std::addressof(has_placeholder), content_info->GetPlaceHolderId()));
|
||||
|
||||
if (has_placeholder) {
|
||||
total_size += content_info->GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
/* Output this InstallTaskOccupiedSize. */
|
||||
out_list[count++] = {
|
||||
.key = reader.GetKey(),
|
||||
.size = total_size,
|
||||
.storage_id = storage_id,
|
||||
};
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallTaskBase::CanContinue() {
|
||||
auto progress = this->GetProgress();
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace ams::ncm {
|
|||
|
||||
R_DEFINE_ERROR_RESULT(ContentStorageBaseNotFound, 310);
|
||||
R_DEFINE_ERROR_RESULT(ListPartiallyNotCommitted, 330);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedContentMetaPrepared, 360);
|
||||
R_DEFINE_ERROR_RESULT(InvalidFirmwareVariation, 380);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(ContentStorageNotActive, 250, 258);
|
||||
|
|
Loading…
Add table
Reference in a new issue