ncm client: more progress

This commit is contained in:
Michael Scire 2020-03-20 17:06:23 -07:00 committed by Adubbz
parent 6d0250124a
commit 217bdc3c2f
8 changed files with 251 additions and 10 deletions

View file

@ -101,6 +101,13 @@ namespace ams::ncm {
return this->written;
}
static constexpr InstallContentInfo Make(const ContentInfo &info, ContentMetaType meta_type) {
return {
.info = info,
.meta_type = meta_type,
};
}
static constexpr InstallContentInfo Make(const PackagedContentInfo &info, ContentMetaType meta_type) {
return {
.digest = info.digest,

View file

@ -281,7 +281,7 @@ namespace ams::ncm {
switch (this->GetHeader()->type) {
case ContentMetaType::Patch: return this->GetExtendedHeader<PatchMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::Delta: return this->GetExtendedHeader<DeltaMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::SystemUpdate: return this->GetExtendedHeader<SystemUpdateMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::SystemUpdate: return this->GetExtendedHeaderSize() == 0 ? 0 : this->GetExtendedHeader<SystemUpdateMetaExtendedHeader>()->extended_data_size;
default: return 0;
}
}
@ -357,7 +357,7 @@ namespace ams::ncm {
class InstallContentMetaWriter : public ContentMetaAccessor<InstallContentMetaHeader, InstallContentInfo> {
public:
InstallContentMetaWriter(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
InstallContentMetaWriter(void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
using ContentMetaAccessor::CalculateSize;
using ContentMetaAccessor::CalculateContentRequiredSize;
@ -412,13 +412,13 @@ namespace ams::ncm {
return this->GetHeader()->firmware_variation_count;
}
FirmwareVariationId *GetFirmwareVariationId(size_t i) const {
const FirmwareVariationId *GetFirmwareVariationId(size_t i) const {
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
return reinterpret_cast<FirmwareVariationId *>(this->GetFirmwareVariationIdAddress(i));
}
FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const {
const FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const {
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
return reinterpret_cast<FirmwareVariationInfo *>(this->GetFirmwareVariationInfoAddress(i));
@ -437,4 +437,9 @@ namespace ams::ncm {
}
};
class SystemUpdateMetaExtendedDataReader : public SystemUpdateMetaExtendedDataReaderWriterBase {
public:
constexpr SystemUpdateMetaExtendedDataReader(const void *data, size_t size) : SystemUpdateMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
};
}

View file

@ -19,9 +19,12 @@
#include <stratosphere/ncm/ncm_content_storage.hpp>
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
namespace ams::ncm {
Result ReadContentMetaPath(AutoBuffer *out, const char *path);
Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, FirmwareVariationId firmware_variation_id);
}

View file

@ -27,6 +27,14 @@ namespace ams::ncm {
struct FirmwareVariationId {
u32 value;
bool operator==(const FirmwareVariationId& other) const {
return this->value == other.value;
}
bool operator!=(const FirmwareVariationId& other) const {
return this->value != other.value;
}
};
}

View file

@ -80,6 +80,7 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta
InstallThroughput throughput;
TimeSpan throughput_start_time;
os::Mutex throughput_mutex;
FirmwareVariationId firmware_variation_id;
public:
virtual ~InstallTaskBase() { /* ... */ };
private:
@ -127,13 +128,23 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta
Result Commit(const StorageContentMetaKey *keys, s32 num_keys);
Result IncludesExFatDriver(bool *out);
Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size);
Result WriteContentMetaToPlaceHolder(InstallContentInfo *install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary);
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(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 IsNewerThanInstalled(bool *out, const ContentMetaKey &key);
Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys);
void ResetLastResult();
s64 GetThroughput();
Result FindMaxRequiredApplicationVersion(u32 *out);
Result FindMaxRequiredSystemVersion(u32 *out);
Result CanContinue();
void SetFirmwareVariationId(FirmwareVariationId id);
protected:
virtual Result OnPrepareComplete();
virtual Result PrepareDependency();
@ -143,7 +154,7 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta
virtual void ResetCancel();
virtual InstallProgress GetProgress();
virtual Result PrepareInstallContentMetaData() = 0;
void *GetInstallContentMetaInfo;
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key);
virtual Result GetLatestVersion(std::optional<u32> *out_version, u64 id);
virtual Result CheckInstallable();
virtual Result OnExecuteComplete();

View file

@ -77,4 +77,70 @@ namespace ams::ncm {
return ncm::ResultContentMetaNotFound();
}
Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, FirmwareVariationId firmware_variation_id) {
AutoBuffer meta;
{
/* TODO: fs::ScopedAutoAbortDisabler aad; */
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
}
PackagedContentMetaReader reader(meta.Get(), meta.GetSize());
/* TODO: ON_SCOPE_EXIT { <auto abort func> }; */
/* No firmware variations to list. */
if (reader.GetExtendedDataSize() == 0) {
return ResultSuccess();
}
SystemUpdateMetaExtendedDataReader extended_data_reader(reader.GetExtendedData(), reader.GetExtendedDataSize());
std::optional<s32> firmware_variation_index = std::nullopt;
/* Find the input firmware variation id. */
for (s32 i = 0; i < extended_data_reader.GetFirmwareVariationCount(); i++) {
if (*extended_data_reader.GetFirmwareVariationId(i) == firmware_variation_id) {
firmware_variation_index = i;
break;
}
}
/* We couldn't find the input firmware variation id. */
if (!firmware_variation_index) {
return ResultInvalidFirmwareVariation();
}
/* Obtain the variation info. */
const FirmwareVariationInfo *variation_info = extended_data_reader.GetFirmwareVariationInfo(*firmware_variation_index);
/* Success if refer to base, or unk is 1 (unk is usually 2). */
if (variation_info->refer_to_base || extended_data_reader.GetHeader()->unk == 1) {
return ResultSuccess();
}
/* Output the content meta count. */
const u32 content_meta_count = variation_info->content_meta_count;
*out_count = content_meta_count;
/* No content metas to list. */
if (content_meta_count == 0) {
return ResultSuccess();
}
/* Allocate a buffer for the content meta infos. */
std::unique_ptr<ContentMetaInfo[]> buffer(new (std::nothrow) ContentMetaInfo[content_meta_count]);
AMS_ABORT_UNLESS(buffer != nullptr);
/* Get the content meta infos. */
Span<const ContentMetaInfo> meta_infos;
extended_data_reader.GetContentMetaInfoList(std::addressof(meta_infos), content_meta_count);
/* Copy the meta infos to the buffer. */
for (size_t i = 0; i < content_meta_count; i++) {
buffer[i] = meta_infos[i];
}
/* Output the content meta info buffer. */
*out_meta_infos = std::move(buffer);
return ResultSuccess();
}
}

View file

@ -725,7 +725,7 @@ namespace ams::ncm {
return ResultSuccess();
}
Result InstallTaskBase::WriteContentMetaToPlaceHolder(InstallContentInfo *install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary) {
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();
@ -734,14 +734,14 @@ namespace ams::ncm {
auto placeholder_guard = SCOPE_GUARD { storage->DeletePlaceHolder(placeholder_id); };
/* Output install content info. */
*install_content_info = this->MakeInstallContentInfoFrom(meta_info, placeholder_id, is_temporary);
*out_install_content_info = this->MakeInstallContentInfoFrom(meta_info, placeholder_id, is_temporary);
/* Write install content info. */
R_TRY(this->WritePlaceHolder(meta_info.key, install_content_info));
R_TRY(this->WritePlaceHolder(meta_info.key, out_install_content_info));
/* Don't delete the placeholder. Set state to installed. */
placeholder_guard.Cancel();
install_content_info->install_state = InstallState::Installed;
out_install_content_info->install_state = InstallState::Installed;
return ResultSuccess();
}
@ -760,6 +760,24 @@ namespace ams::ncm {
/* ... */
Result InstallTaskBase::PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer) {
/* Create a reader. */
PackagedContentMetaReader reader(buffer->Get(), buffer->GetSize());
/* Initialize the temporary buffer. */
AutoBuffer tmp_buffer;
R_TRY(tmp_buffer.Initialize(reader.CalculateConvertInstallContentMetaSize()));
/* Convert packaged content meta to install content meta. */
reader.ConvertToInstallContentMeta(tmp_buffer.Get(), tmp_buffer.GetSize(), InstallContentInfo::Make(ContentInfo::Make(content_id, size, ContentType::Meta), meta_type));
/* Push the content meta. */
this->data->Push(tmp_buffer.Get(), tmp_buffer.GetSize());
return ResultSuccess();
}
/* ... */
void InstallTaskBase::IncrementProgress(s64 size) {
std::scoped_lock lk(this->progress_mutex);
this->progress.installed_size += size;
@ -802,6 +820,39 @@ namespace ams::ncm {
return ResultSuccess();
}
// Result InstallTaskBase::PrepareSystemUpdateDependency() {
// /* TODO */
// return ResultSuccess();
// }
Result InstallTaskBase::GetContentMetaInfoList(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));
/* Open the BuiltInSystem content storage. */
ContentStorage content_storage;
R_TRY(ncm::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), install_content_meta_info, true));
const PlaceHolderId placeholder_id = content_info.placeholder_id;
/* Get the path of the new placeholder. */
Path path;
content_storage.GetPlaceHolderPath(std::addressof(path), placeholder_id);
/* Read the variation list. */
R_TRY(ReadVariationContentMetaInfoList(out_count, out_meta_infos, path, this->firmware_variation_id));
/* Delete the placeholder. */
content_storage.DeletePlaceHolder(placeholder_id);
return ResultSuccess();
}
/* ... */
Result InstallTaskBase::IsNewerThanInstalled(bool *out, const ContentMetaKey &key) {
@ -871,4 +922,93 @@ namespace ams::ncm {
return this->throughput.installed;
}
/* ... */
Result InstallTaskBase::FindMaxRequiredApplicationVersion(u32 *out) {
/* Count the number of content meta entries. */
s32 count;
R_TRY(this->data->Count(std::addressof(count)));
u32 max_version = 0;
/* Iterate over content meta. */
for (s32 i = 0; i < count; i++) {
/* Obtain the content meta. */
InstallContentMeta content_meta;
R_TRY(this->data->Get(&content_meta, i));
/* Create a reader. */
const InstallContentMetaReader reader = content_meta.GetReader();
/* Check if the meta type is for add on content. */
if (reader.GetHeader()->type == ContentMetaType::AddOnContent) {
const auto *extended_header = reader.GetExtendedHeader<AddOnContentMetaExtendedHeader>();
/* Set the max version if higher. */
if (extended_header->required_application_version >= max_version) {
max_version = extended_header->required_application_version;
}
}
}
*out = max_version;
return ResultSuccess();
}
Result InstallTaskBase::FindMaxRequiredSystemVersion(u32 *out) {
/* Count the number of content meta entries. */
s32 count;
R_TRY(this->data->Count(std::addressof(count)));
u32 max_version = 0;
/* Iterate over content meta. */
for (s32 i = 0; i < count; i++) {
/* Obtain the content meta. */
InstallContentMeta content_meta;
R_TRY(this->data->Get(&content_meta, i));
/* Create a reader. */
const InstallContentMetaReader reader = content_meta.GetReader();
if (reader.GetHeader()->type == ContentMetaType::Application) {
const auto *extended_header = reader.GetExtendedHeader<ApplicationMetaExtendedHeader>();
/* Set the max version if higher. */
if (extended_header->required_system_version >= max_version) {
max_version = extended_header->required_system_version;
}
} else if (reader.GetHeader()->type == ContentMetaType::Patch) {
const auto *extended_header = reader.GetExtendedHeader<PatchMetaExtendedHeader>();
/* Set the max version if higher. */
if (extended_header->required_system_version >= max_version) {
max_version = extended_header->required_system_version;
}
}
}
*out = max_version;
return ResultSuccess();
}
/* ... */
Result InstallTaskBase::CanContinue() {
auto progress = this->GetProgress();
if (progress.state == InstallProgressState::NotPrepared || progress.state == InstallProgressState::DataPrepared) {
R_UNLESS(!this->IsCancelRequested(), ncm::ResultCreatePlaceHolderCancelled());
}
if (progress.state == InstallProgressState::Prepared) {
R_UNLESS(!this->IsCancelRequested(), ncm::ResultWritePlaceHolderCancelled());
}
return ResultSuccess();
}
void InstallTaskBase::SetFirmwareVariationId(FirmwareVariationId id) {
this->firmware_variation_id = id;
}
}

View file

@ -45,6 +45,7 @@ namespace ams::ncm {
R_DEFINE_ERROR_RESULT(ContentStorageBaseNotFound, 310);
R_DEFINE_ERROR_RESULT(ListPartiallyNotCommitted, 330);
R_DEFINE_ERROR_RESULT(InvalidFirmwareVariation, 380);
R_DEFINE_ERROR_RANGE(ContentStorageNotActive, 250, 258);
R_DEFINE_ERROR_RESULT(GameCardContentStorageNotActive, 251);