mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 04:24:48 +00:00
ncm client: more progress
This commit is contained in:
parent
6d0250124a
commit
217bdc3c2f
8 changed files with 251 additions and 10 deletions
|
@ -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,
|
||||
|
|
|
@ -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) { /* ... */ }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue