mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-07-17 14:22:13 +02:00
ncm: cleanup client code
This commit is contained in:
parent
5eeb4884c4
commit
b8e2c96824
@ -17,12 +17,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_max_count.hpp>
|
||||||
#include <stratosphere/ncm/ncm_program_location.hpp>
|
#include <stratosphere/ncm/ncm_program_location.hpp>
|
||||||
#include <stratosphere/ncm/ncm_auto_buffer.hpp>
|
#include <stratosphere/ncm/ncm_auto_buffer.hpp>
|
||||||
#include <stratosphere/ncm/ncm_make_path.hpp>
|
#include <stratosphere/ncm/ncm_make_path.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_id_utils.hpp>
|
#include <stratosphere/ncm/ncm_content_id_utils.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_info_utils.hpp>
|
#include <stratosphere/ncm/ncm_content_info_utils.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_meta.hpp>
|
#include <stratosphere/ncm/ncm_content_meta.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta_extended_data.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
|
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_storage.hpp>
|
#include <stratosphere/ncm/ncm_content_storage.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_manager_impl.hpp>
|
#include <stratosphere/ncm/ncm_content_manager_impl.hpp>
|
||||||
@ -35,5 +37,5 @@
|
|||||||
#include <stratosphere/ncm/ncm_package_install_task.hpp>
|
#include <stratosphere/ncm/ncm_package_install_task.hpp>
|
||||||
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
|
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
|
||||||
#include <stratosphere/ncm/ncm_submission_package_install_task.hpp>
|
#include <stratosphere/ncm/ncm_submission_package_install_task.hpp>
|
||||||
#include <stratosphere/ncm/ncm_storage_id_utils.hpp>
|
#include <stratosphere/ncm/ncm_storage_utils.hpp>
|
||||||
#include <stratosphere/ncm/ncm_api.hpp>
|
#include <stratosphere/ncm/ncm_api.hpp>
|
||||||
|
@ -62,7 +62,6 @@ namespace ams::ncm {
|
|||||||
StorageId storage_id;
|
StorageId storage_id;
|
||||||
bool is_temporary;
|
bool is_temporary;
|
||||||
bool is_sha256_calculated;
|
bool is_sha256_calculated;
|
||||||
u8 reserved[2];
|
|
||||||
s64 written;
|
s64 written;
|
||||||
|
|
||||||
constexpr const ContentId &GetId() const {
|
constexpr const ContentId &GetId() const {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
@ -23,4 +24,8 @@ namespace ams::ncm {
|
|||||||
s64 CalculateRequiredSize(s64 file_size, s64 cluster_size = MaxClusterSize);
|
s64 CalculateRequiredSize(s64 file_size, s64 cluster_size = MaxClusterSize);
|
||||||
s64 CalculateRequiredSizeForExtension(s64 file_size, s64 cluster_size = MaxClusterSize);
|
s64 CalculateRequiredSizeForExtension(s64 file_size, s64 cluster_size = MaxClusterSize);
|
||||||
|
|
||||||
|
class ContentMetaDatabase;
|
||||||
|
|
||||||
|
Result EstimateRequiredSize(s64 *out_size, const ContentMetaKey &key, ContentMetaDatabase *db);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -112,11 +112,6 @@ namespace ams::ncm {
|
|||||||
u32 extended_data_size;
|
u32 extended_data_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SystemUpdateMetaExtendedDataHeader {
|
|
||||||
u32 unk; // Always seems to be set to 2
|
|
||||||
u32 firmware_variation_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ContentMetaHeaderType, typename ContentInfoType>
|
template<typename ContentMetaHeaderType, typename ContentInfoType>
|
||||||
class ContentMetaAccessor {
|
class ContentMetaAccessor {
|
||||||
public:
|
public:
|
||||||
@ -227,6 +222,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HeaderType *GetWritableHeader() const {
|
HeaderType *GetWritableHeader() const {
|
||||||
|
AMS_ABORT_UNLESS(this->is_header_valid);
|
||||||
return reinterpret_cast<HeaderType *>(this->data);
|
return reinterpret_cast<HeaderType *>(this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,13 +335,8 @@ namespace ams::ncm {
|
|||||||
size_t CalculateConvertContentMetaSize() const;
|
size_t CalculateConvertContentMetaSize() const;
|
||||||
void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta);
|
void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta);
|
||||||
|
|
||||||
Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) {
|
Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) const;
|
||||||
AMS_ABORT("Not implemented");
|
Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version);
|
||||||
};
|
|
||||||
|
|
||||||
Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version) {
|
|
||||||
AMS_ABORT("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CountDeltaFragments() const;
|
size_t CountDeltaFragments() const;
|
||||||
|
|
||||||
@ -358,6 +349,10 @@ namespace ams::ncm {
|
|||||||
public:
|
public:
|
||||||
constexpr InstallContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
|
constexpr InstallContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
|
||||||
|
|
||||||
|
using ContentMetaAccessor::CalculateSize;
|
||||||
|
using ContentMetaAccessor::CalculateContentRequiredSize;
|
||||||
|
using ContentMetaAccessor::GetStorageId;
|
||||||
|
|
||||||
size_t CalculateConvertSize() const;
|
size_t CalculateConvertSize() const;
|
||||||
|
|
||||||
void ConvertToContentMeta(void *dst, size_t size) const;
|
void ConvertToContentMeta(void *dst, size_t size) const;
|
||||||
@ -373,81 +368,4 @@ namespace ams::ncm {
|
|||||||
using ContentMetaAccessor::SetStorageId;
|
using ContentMetaAccessor::SetStorageId;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SystemUpdateMetaExtendedDataReaderWriterBase {
|
|
||||||
private:
|
|
||||||
void *data;
|
|
||||||
const size_t size;
|
|
||||||
bool is_header_valid;
|
|
||||||
protected:
|
|
||||||
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(const void *d, size_t sz) : data(const_cast<void *>(d)), size(sz), is_header_valid(true) { /* ... */ }
|
|
||||||
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(void *d, size_t sz) : data(d), size(sz), is_header_valid(false) { /* ... */ }
|
|
||||||
|
|
||||||
uintptr_t GetHeaderAddress() const {
|
|
||||||
return reinterpret_cast<uintptr_t>(this->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetFirmwarVariationIdStartAddress() const {
|
|
||||||
return this->GetHeaderAddress() + sizeof(SystemUpdateMetaExtendedDataHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetFirmwareVariationIdAddress(size_t i) const {
|
|
||||||
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetFirmwareVariationInfoStartAddress() const {
|
|
||||||
return this->GetFirmwareVariationIdAddress(this->GetFirmwareVariationCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetFirmwareVariationInfoAddress(size_t i) const {
|
|
||||||
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetContentMetaInfoStartAddress() const {
|
|
||||||
return this->GetFirmwareVariationInfoAddress(this->GetFirmwareVariationCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetContentMetaInfoAddress(size_t i) const {
|
|
||||||
return this->GetContentMetaInfoStartAddress() + i * sizeof(ContentMetaInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const SystemUpdateMetaExtendedDataHeader *GetHeader() const {
|
|
||||||
AMS_ABORT_UNLESS(this->is_header_valid);
|
|
||||||
return reinterpret_cast<const SystemUpdateMetaExtendedDataHeader *>(this->GetHeaderAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetFirmwareVariationCount() const {
|
|
||||||
return this->GetHeader()->firmware_variation_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FirmwareVariationId *GetFirmwareVariationId(size_t i) const {
|
|
||||||
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
|
|
||||||
|
|
||||||
return reinterpret_cast<FirmwareVariationId *>(this->GetFirmwareVariationIdAddress(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
const FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const {
|
|
||||||
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
|
|
||||||
|
|
||||||
return reinterpret_cast<FirmwareVariationInfo *>(this->GetFirmwareVariationInfoAddress(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetContentMetaInfoList(Span<const ContentMetaInfo> *out_list, size_t i) const {
|
|
||||||
size_t preceding_content_meta_count = 0;
|
|
||||||
|
|
||||||
/* Count the number of preceding content metas. */
|
|
||||||
for (size_t j = 0; j < i; j++) {
|
|
||||||
preceding_content_meta_count += GetFirmwareVariationInfo(j)->content_meta_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output the list. */
|
|
||||||
*out_list = Span<const ContentMetaInfo>(reinterpret_cast<const ContentMetaInfo *>(GetContentMetaInfoAddress(preceding_content_meta_count)), GetFirmwareVariationInfo(i)->content_meta_count);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SystemUpdateMetaExtendedDataReader : public SystemUpdateMetaExtendedDataReaderWriterBase {
|
|
||||||
public:
|
|
||||||
constexpr SystemUpdateMetaExtendedDataReader(const void *data, size_t size) : SystemUpdateMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,384 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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_info.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
|
||||||
|
|
||||||
|
namespace ams::ncm {
|
||||||
|
|
||||||
|
enum class UpdateType : u8 {
|
||||||
|
ApplyAsDelta = 0,
|
||||||
|
Overwrite = 1,
|
||||||
|
Create = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentIndicator {
|
||||||
|
u16 content_info_index;
|
||||||
|
u16 fragment_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentSet {
|
||||||
|
ContentId source_content_id;
|
||||||
|
ContentId destination_content_id;
|
||||||
|
u32 source_size_low;
|
||||||
|
u16 source_size_high;
|
||||||
|
u16 destination_size_high;
|
||||||
|
u32 destination_size_low;
|
||||||
|
u16 fragment_count;
|
||||||
|
ContentType target_content_type;
|
||||||
|
UpdateType update_type;
|
||||||
|
u8 reserved[4];
|
||||||
|
|
||||||
|
constexpr s64 GetSourceSize() const {
|
||||||
|
return (static_cast<s64>(this->source_size_high) << 32) + this->source_size_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr s64 GetDestinationSize() const {
|
||||||
|
return (static_cast<s64>(this->destination_size_high) << 32) + this->destination_size_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void SetSourceSize(s64 size) {
|
||||||
|
this->source_size_low = size & 0xFFFFFFFFll;
|
||||||
|
this->source_size_high = static_cast<u16>(size >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void SetDestinationSize(s64 size) {
|
||||||
|
this->destination_size_low = size & 0xFFFFFFFFll;
|
||||||
|
this->destination_size_high = static_cast<u16>(size >> 32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SystemUpdateMetaExtendedDataHeader {
|
||||||
|
u32 unk; // Always seems to be set to 2
|
||||||
|
u32 firmware_variation_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeltaMetaExtendedDataHeader {
|
||||||
|
PatchId source_id;
|
||||||
|
PatchId destination_id;
|
||||||
|
u32 source_version;
|
||||||
|
u32 destination_version;
|
||||||
|
u16 fragment_set_count;
|
||||||
|
u8 reserved[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PatchMetaExtendedDataHeader {
|
||||||
|
u32 history_count;
|
||||||
|
u32 delta_history_count;
|
||||||
|
u32 delta_count;
|
||||||
|
u32 fragment_set_count;
|
||||||
|
u32 history_content_total_count;
|
||||||
|
u32 delta_content_total_count;
|
||||||
|
u8 reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PatchHistoryHeader {
|
||||||
|
ContentMetaKey key;
|
||||||
|
Digest digest;
|
||||||
|
u16 content_count;
|
||||||
|
u8 reserver[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PatchDeltaHistory {
|
||||||
|
PatchId source_id;
|
||||||
|
PatchId destination_id;
|
||||||
|
u32 source_version;
|
||||||
|
u32 destination_version;
|
||||||
|
u64 download_size;
|
||||||
|
u8 reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PatchDeltaHeader {
|
||||||
|
DeltaMetaExtendedDataHeader delta;
|
||||||
|
u16 content_count;
|
||||||
|
u8 reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename MemberTypePointer, typename DataTypePointer>
|
||||||
|
class PatchMetaExtendedDataReaderWriterBase {
|
||||||
|
private:
|
||||||
|
MemberTypePointer data;
|
||||||
|
const size_t size;
|
||||||
|
public:
|
||||||
|
PatchMetaExtendedDataReaderWriterBase(MemberTypePointer d, size_t sz) : data(d), size(sz) { /* ... */ }
|
||||||
|
protected:
|
||||||
|
s32 CountFragmentSet(s32 delta_index) const {
|
||||||
|
auto delta_header = this->GetPatchDeltaHeader(0);
|
||||||
|
s32 count = 0;
|
||||||
|
for (s32 i = 0; i < delta_index; i++) {
|
||||||
|
count += delta_header[i].delta.fragment_set_count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 CountHistoryContent(s32 history_index) const {
|
||||||
|
auto history_header = this->GetPatchHistoryHeader(0);
|
||||||
|
s32 count = 0;
|
||||||
|
for (s32 i = 0; i < history_index; i++) {
|
||||||
|
count += history_header[i].content_count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 CountDeltaContent(s32 delta_index) const {
|
||||||
|
auto delta_header = this->GetPatchDeltaHeader(0);
|
||||||
|
s32 count = 0;
|
||||||
|
for (s32 i = 0; i < delta_index; i++) {
|
||||||
|
count += delta_header[i].content_count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 CountFragment(s32 index) const {
|
||||||
|
auto fragment_set = this->GetFragmentSet(0, 0);
|
||||||
|
s32 count = 0;
|
||||||
|
for (s32 i = 0; i < index; i++) {
|
||||||
|
count += fragment_set[i].fragment_count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetHeaderAddress() const {
|
||||||
|
return reinterpret_cast<DataTypePointer>(this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetPatchHistoryHeaderAddress(s32 index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->history_count);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * index;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetPatchDeltaHistoryAddress(s32 index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_history_count);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * index;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetPatchDeltaHeaderAddress(s32 index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_count);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * header->delta_history_count
|
||||||
|
+ sizeof(PatchDeltaHeader) * index;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetFragmentSetAddress(s32 delta_index, s32 fragment_set_index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(delta_index) < header->delta_count);
|
||||||
|
|
||||||
|
auto delta_header = this->GetPatchDeltaHeader(delta_index);
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(fragment_set_index) < delta_header->delta.fragment_set_count);
|
||||||
|
|
||||||
|
auto previous_fragment_set_count = this->CountFragmentSet(delta_index);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * header->delta_history_count
|
||||||
|
+ sizeof(PatchDeltaHeader) * header->delta_count
|
||||||
|
+ sizeof(FragmentSet) * (previous_fragment_set_count + fragment_set_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetPatchHistoryContentInfoAddress(s32 history_index, s32 content_index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
auto history_header = this->GetPatchHistoryHeader(history_index);
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(content_index) < history_header->content_count);
|
||||||
|
|
||||||
|
auto prev_history_count = this->CountHistoryContent(history_index);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * header->delta_history_count
|
||||||
|
+ sizeof(PatchDeltaHeader) * header->delta_count
|
||||||
|
+ sizeof(FragmentSet) * header->fragment_set_count
|
||||||
|
+ sizeof(ContentInfo) * (prev_history_count + content_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetPatchDeltaPackagedContentInfoAddress(s32 delta_index, s32 content_index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
auto delta_header = this->GetPatchDeltaHeader(delta_index);
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(content_index) < delta_header->content_count);
|
||||||
|
|
||||||
|
auto content_count = this->CountDeltaContent(delta_index);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * header->delta_history_count
|
||||||
|
+ sizeof(PatchDeltaHeader) * header->delta_count
|
||||||
|
+ sizeof(FragmentSet) * header->fragment_set_count
|
||||||
|
+ sizeof(ContentInfo) * header->history_content_total_count
|
||||||
|
+ sizeof(PackagedContentInfo) * (content_count + content_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePointer GetFragmentIndicatorAddress(s32 delta_index, s32 fragment_set_index, s32 index) const {
|
||||||
|
auto header = this->GetHeader();
|
||||||
|
auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index);
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u16>(index) < fragment_set->fragment_count);
|
||||||
|
|
||||||
|
auto fragment_set_count = this->CountFragmentSet(delta_index);
|
||||||
|
auto fragment_count = this->CountFragment(fragment_set_count + fragment_set_index);
|
||||||
|
|
||||||
|
return this->GetHeaderAddress()
|
||||||
|
+ sizeof(PatchMetaExtendedDataHeader)
|
||||||
|
+ sizeof(PatchHistoryHeader) * header->history_count
|
||||||
|
+ sizeof(PatchDeltaHistory) * header->delta_history_count
|
||||||
|
+ sizeof(PatchDeltaHeader) * header->delta_count
|
||||||
|
+ sizeof(FragmentSet) * header->fragment_set_count
|
||||||
|
+ sizeof(ContentInfo) * header->history_content_total_count
|
||||||
|
+ sizeof(PackagedContentInfo) * header->delta_content_total_count
|
||||||
|
+ sizeof(FragmentIndicator) * (fragment_count + index);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const PatchMetaExtendedDataHeader *GetHeader() const {
|
||||||
|
return reinterpret_cast<const PatchMetaExtendedDataHeader *>(this->GetHeaderAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
const PatchHistoryHeader *GetPatchHistoryHeader(s32 index) const {
|
||||||
|
return reinterpret_cast<const PatchHistoryHeader *>(this->GetPatchHistoryHeaderAddress(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const PatchDeltaHistory *GetPatchDeltaHistory(s32 index) const {
|
||||||
|
return reinterpret_cast<const PatchDeltaHistory *>(this->GetPatchDeltaHistoryAddress(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ContentInfo *GetPatchHistoryContentInfo(s32 history_index, s32 content_index) const {
|
||||||
|
return reinterpret_cast<const ContentInfo *>(this->GetPatchHistoryContentInfoAddress(history_index, content_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const PatchDeltaHeader *GetPatchDeltaHeader(s32 index) const {
|
||||||
|
return reinterpret_cast<const PatchDeltaHeader *>(this->GetPatchDeltaHeaderAddress(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const PackagedContentInfo *GetPatchDeltaPackagedContentInfo(s32 delta_index, s32 content_index) const {
|
||||||
|
return reinterpret_cast<const PackagedContentInfo *>(this->GetPatchDeltaPackagedContentInfoAddress(delta_index, content_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const FragmentSet *GetFragmentSet(s32 delta_index, s32 fragment_set_index) const {
|
||||||
|
return reinterpret_cast<const FragmentSet *>(this->GetFragmentSetIndex(delta_index, fragment_set_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const FragmentIndicator *GetFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 index) const {
|
||||||
|
return reinterpret_cast<const FragmentIndicator *>(this->GetFragmentIndicatorAddress(delta_index, fragment_set_index, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const FragmentIndicator *FindFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 fragment_index) const {
|
||||||
|
auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index);
|
||||||
|
auto fragment = this->GetFragmentIndicator(delta_index, fragment_set_index, 0);
|
||||||
|
for (s32 i = 0; i < fragment_set->fragment_count; i++) {
|
||||||
|
if (fragment[i].fragment_index == fragment_index) {
|
||||||
|
return std::addressof(fragment[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchMetaExtendedDataReader : public PatchMetaExtendedDataReaderWriterBase<const void *, const u8 *> {
|
||||||
|
public:
|
||||||
|
PatchMetaExtendedDataReader(const void *data, size_t size) : PatchMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SystemUpdateMetaExtendedDataReaderWriterBase {
|
||||||
|
private:
|
||||||
|
void *data;
|
||||||
|
const size_t size;
|
||||||
|
bool is_header_valid;
|
||||||
|
protected:
|
||||||
|
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(const void *d, size_t sz) : data(const_cast<void *>(d)), size(sz), is_header_valid(true) { /* ... */ }
|
||||||
|
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(void *d, size_t sz) : data(d), size(sz), is_header_valid(false) { /* ... */ }
|
||||||
|
|
||||||
|
uintptr_t GetHeaderAddress() const {
|
||||||
|
return reinterpret_cast<uintptr_t>(this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetFirmwarVariationIdStartAddress() const {
|
||||||
|
return this->GetHeaderAddress() + sizeof(SystemUpdateMetaExtendedDataHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetFirmwareVariationIdAddress(size_t i) const {
|
||||||
|
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetFirmwareVariationInfoStartAddress() const {
|
||||||
|
return this->GetFirmwareVariationIdAddress(this->GetFirmwareVariationCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetFirmwareVariationInfoAddress(size_t i) const {
|
||||||
|
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetContentMetaInfoStartAddress() const {
|
||||||
|
return this->GetFirmwareVariationInfoAddress(this->GetFirmwareVariationCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetContentMetaInfoAddress(size_t i) const {
|
||||||
|
return this->GetContentMetaInfoStartAddress() + i * sizeof(ContentMetaInfo);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const SystemUpdateMetaExtendedDataHeader *GetHeader() const {
|
||||||
|
AMS_ABORT_UNLESS(this->is_header_valid);
|
||||||
|
return reinterpret_cast<const SystemUpdateMetaExtendedDataHeader *>(this->GetHeaderAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetFirmwareVariationCount() const {
|
||||||
|
return this->GetHeader()->firmware_variation_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FirmwareVariationId *GetFirmwareVariationId(size_t i) const {
|
||||||
|
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
|
||||||
|
|
||||||
|
return reinterpret_cast<FirmwareVariationId *>(this->GetFirmwareVariationIdAddress(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
const FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const {
|
||||||
|
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
|
||||||
|
|
||||||
|
return reinterpret_cast<FirmwareVariationInfo *>(this->GetFirmwareVariationInfoAddress(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetContentMetaInfoList(Span<const ContentMetaInfo> *out_list, size_t i) const {
|
||||||
|
size_t preceding_content_meta_count = 0;
|
||||||
|
|
||||||
|
/* Count the number of preceding content metas. */
|
||||||
|
for (size_t j = 0; j < i; j++) {
|
||||||
|
preceding_content_meta_count += this->GetFirmwareVariationInfo(j)->content_meta_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the list. */
|
||||||
|
*out_list = Span<const ContentMetaInfo>(reinterpret_cast<const ContentMetaInfo *>(this->GetContentMetaInfoAddress(preceding_content_meta_count)), this->GetFirmwareVariationInfo(i)->content_meta_count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SystemUpdateMetaExtendedDataReader : public SystemUpdateMetaExtendedDataReaderWriterBase {
|
||||||
|
public:
|
||||||
|
constexpr SystemUpdateMetaExtendedDataReader(const void *data, size_t size) : SystemUpdateMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -27,14 +27,14 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
struct FirmwareVariationId {
|
struct FirmwareVariationId {
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
bool operator==(const FirmwareVariationId& other) const {
|
|
||||||
return this->value == other.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const FirmwareVariationId& other) const {
|
|
||||||
return this->value != other.value;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr inline bool operator==(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) {
|
||||||
|
return lhs.value == rhs.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool operator!=(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) {
|
||||||
|
return lhs.value != rhs.value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,18 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/ncm/ncm_install_progress_state.hpp>
|
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
|
enum class InstallProgressState : u8 {
|
||||||
|
NotPrepared = 0,
|
||||||
|
DataPrepared = 1,
|
||||||
|
Prepared = 2,
|
||||||
|
Downloaded = 3,
|
||||||
|
Committed = 4,
|
||||||
|
Fatal = 5,
|
||||||
|
};
|
||||||
|
|
||||||
struct InstallProgress {
|
struct InstallProgress {
|
||||||
InstallProgressState state;
|
InstallProgressState state;
|
||||||
u8 pad[3];
|
u8 pad[3];
|
||||||
|
@ -79,6 +79,8 @@ namespace ams::ncm {
|
|||||||
static_assert(sizeof(InstallContentMetaInfo) == 0x50);
|
static_assert(sizeof(InstallContentMetaInfo) == 0x50);
|
||||||
|
|
||||||
class InstallTaskBase {
|
class InstallTaskBase {
|
||||||
|
NON_COPYABLE(InstallTaskBase);
|
||||||
|
NON_MOVEABLE(InstallTaskBase);
|
||||||
private:
|
private:
|
||||||
crypto::Sha256Generator sha256_generator;
|
crypto::Sha256Generator sha256_generator;
|
||||||
StorageId install_storage;
|
StorageId install_storage;
|
||||||
@ -92,8 +94,6 @@ namespace ams::ncm {
|
|||||||
TimeSpan throughput_start_time;
|
TimeSpan throughput_start_time;
|
||||||
os::Mutex throughput_mutex;
|
os::Mutex throughput_mutex;
|
||||||
FirmwareVariationId firmware_variation_id;
|
FirmwareVariationId firmware_variation_id;
|
||||||
public:
|
|
||||||
virtual ~InstallTaskBase() { /* ... */ };
|
|
||||||
private:
|
private:
|
||||||
ALWAYS_INLINE Result SetLastResultOnFailure(Result result) {
|
ALWAYS_INLINE Result SetLastResultOnFailure(Result result) {
|
||||||
if (R_FAILED(result)) {
|
if (R_FAILED(result)) {
|
||||||
@ -101,78 +101,103 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
Result PrepareImpl();
|
|
||||||
Result CleanupOne(const InstallContentMeta &content_meta);
|
|
||||||
Result ExecuteImpl();
|
|
||||||
Result CommitImpl(const StorageContentMetaKey *keys, s32 num_keys);
|
|
||||||
InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, std::optional<bool> is_temporary);
|
|
||||||
Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key);
|
|
||||||
Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span<RightsId> out_span, const InstallContentMeta &content_meta, s32 offset);
|
|
||||||
protected:
|
|
||||||
Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config);
|
|
||||||
Result CountInstallContentMetaData(s32 *out_count);
|
|
||||||
Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
void PrepareAgain();
|
|
||||||
Result PrepareSystemUpdateDependency();
|
|
||||||
Result PrepareContentMetaIfLatest(const ContentMetaKey &key);
|
|
||||||
Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out);
|
|
||||||
Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys);
|
|
||||||
Result CanContinue();
|
|
||||||
public:
|
public:
|
||||||
bool IsCancelRequested();
|
InstallTaskBase() : data(), progress(), cancel_requested() { /* ... */ }
|
||||||
Result Prepare();
|
virtual ~InstallTaskBase() { /* ... */ };
|
||||||
void SetLastResult(Result last_result);
|
|
||||||
Result GetPreparedPlaceHolderPath(Path *out_path, u64 id, ContentMetaType meta_type, ContentType type);
|
|
||||||
Result CalculateRequiredSize(size_t *out_size);
|
|
||||||
void ResetThroughputMeasurement();
|
|
||||||
void SetProgressState(InstallProgressState state);
|
|
||||||
void IncrementProgress(s64 size);
|
|
||||||
void UpdateThroughputMeasurement(s64 throughput);
|
|
||||||
bool IsNecessaryInstallTicket(const fs::RightsId &rights_id);
|
|
||||||
void SetTotalSize(s64 size);
|
|
||||||
Result PreparePlaceHolder();
|
|
||||||
Result Cleanup();
|
|
||||||
void CleanupProgress();
|
|
||||||
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter);
|
|
||||||
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset);
|
|
||||||
Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset);
|
|
||||||
Result Execute();
|
|
||||||
void StartThroughputMeasurement();
|
|
||||||
Result WritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info);
|
|
||||||
Result PrepareAndExecute();
|
|
||||||
Result VerifyAllNotCommitted(const StorageContentMetaKey *keys, s32 num_keys);
|
|
||||||
Result Commit(const StorageContentMetaKey *keys, s32 num_keys);
|
|
||||||
Result Commit();
|
|
||||||
Result IncludesExFatDriver(bool *out);
|
|
||||||
Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key);
|
|
||||||
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);
|
|
||||||
void SetFirmwareVariationId(FirmwareVariationId id);
|
|
||||||
Result ListRightsIds(s32 *out_count, Span<RightsId> out_span, const ContentMetaKey &key, s32 offset);
|
|
||||||
protected:
|
|
||||||
virtual Result OnPrepareComplete();
|
|
||||||
virtual Result PrepareDependency();
|
|
||||||
public:
|
public:
|
||||||
virtual void Cancel();
|
virtual void Cancel();
|
||||||
virtual void ResetCancel();
|
virtual void ResetCancel();
|
||||||
|
|
||||||
|
Result Prepare();
|
||||||
|
Result GetPreparedPlaceHolderPath(Path *out_path, u64 id, ContentMetaType meta_type, ContentType type);
|
||||||
|
Result CalculateRequiredSize(s64 *out_size);
|
||||||
|
Result Cleanup();
|
||||||
|
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter);
|
||||||
|
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset) { return this->ListContentMetaKey(out_keys_written, out_keys, out_keys_count, offset, ListContentMetaKeyFilter::All); }
|
||||||
|
Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset);
|
||||||
|
Result Execute();
|
||||||
|
Result PrepareAndExecute();
|
||||||
|
Result Commit(const StorageContentMetaKey *keys, s32 num_keys);
|
||||||
|
Result Commit() { return this->Commit(nullptr, 0); }
|
||||||
virtual InstallProgress GetProgress();
|
virtual InstallProgress GetProgress();
|
||||||
|
void ResetLastResult();
|
||||||
|
Result IncludesExFatDriver(bool *out);
|
||||||
|
InstallThroughput GetThroughput();
|
||||||
|
Result CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id);
|
||||||
|
Result ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset);
|
||||||
|
|
||||||
|
Result FindMaxRequiredApplicationVersion(u32 *out);
|
||||||
|
Result FindMaxRequiredSystemVersion(u32 *out);
|
||||||
|
protected:
|
||||||
|
Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config);
|
||||||
|
|
||||||
|
Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional<ContentMetaKey> key, std::optional<u32> source_version);
|
||||||
|
Result PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer);
|
||||||
|
Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size);
|
||||||
|
void PrepareAgain();
|
||||||
|
|
||||||
|
Result CountInstallContentMetaData(s32 *out_count);
|
||||||
|
Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index);
|
||||||
|
Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys);
|
||||||
|
|
||||||
|
virtual Result PrepareDependency();
|
||||||
|
Result PrepareSystemUpdateDependency();
|
||||||
|
Result PrepareContentMetaIfLatest(const ContentMetaKey &key);
|
||||||
|
u32 GetConfig() const { return this->config; }
|
||||||
|
Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary);
|
||||||
|
|
||||||
|
StorageId GetInstallStorage() const { return this->install_storage; }
|
||||||
|
|
||||||
|
virtual Result OnPrepareComplete() { return ResultSuccess(); }
|
||||||
|
|
||||||
|
Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out);
|
||||||
|
|
||||||
|
Result CanContinue();
|
||||||
|
private:
|
||||||
|
bool IsCancelRequested();
|
||||||
|
Result PrepareImpl();
|
||||||
|
Result ExecuteImpl();
|
||||||
|
Result CommitImpl(const StorageContentMetaKey *keys, s32 num_keys);
|
||||||
|
Result CleanupOne(const InstallContentMeta &content_meta);
|
||||||
|
|
||||||
|
Result VerifyAllNotCommitted(const StorageContentMetaKey *keys, s32 num_keys);
|
||||||
|
|
||||||
virtual Result PrepareInstallContentMetaData() = 0;
|
virtual Result PrepareInstallContentMetaData() = 0;
|
||||||
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key);
|
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) = 0;
|
||||||
virtual Result GetLatestVersion(std::optional<u32> *out_version, u64 id);
|
virtual Result GetLatestVersion(std::optional<u32> *out_version, u64 id) { return ncm::ResultContentMetaNotFound(); }
|
||||||
virtual Result CheckInstallable();
|
|
||||||
virtual Result OnExecuteComplete();
|
virtual Result OnExecuteComplete() { return ResultSuccess(); }
|
||||||
|
|
||||||
|
Result WritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info);
|
||||||
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) = 0;
|
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) = 0;
|
||||||
|
|
||||||
|
bool IsNecessaryInstallTicket(const fs::RightsId &rights_id);
|
||||||
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) = 0;
|
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) = 0;
|
||||||
|
|
||||||
|
Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key);
|
||||||
|
Result PreparePlaceHolder();
|
||||||
|
|
||||||
|
void SetProgressState(InstallProgressState state);
|
||||||
|
void IncrementProgress(s64 size);
|
||||||
|
void SetTotalSize(s64 size);
|
||||||
|
void SetLastResult(Result last_result);
|
||||||
|
void CleanupProgress();
|
||||||
|
|
||||||
|
void ResetThroughputMeasurement();
|
||||||
|
void StartThroughputMeasurement();
|
||||||
|
void UpdateThroughputMeasurement(s64 throughput);
|
||||||
|
|
||||||
|
Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version);
|
||||||
|
|
||||||
|
InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, std::optional<bool> is_temporary);
|
||||||
|
|
||||||
|
Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key);
|
||||||
|
Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span<RightsId> out_span, const InstallContentMeta &content_meta, s32 offset);
|
||||||
|
public:
|
||||||
|
virtual Result CheckInstallable() { return ResultSuccess(); }
|
||||||
|
|
||||||
|
void SetFirmwareVariationId(FirmwareVariationId id) { this->firmware_variation_id = id; }
|
||||||
|
Result ListRightsIds(s32 *out_count, Span<RightsId> out_span, const ContentMetaKey &key, s32 offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ namespace ams::ncm {
|
|||||||
Result last_result;
|
Result last_result;
|
||||||
SystemUpdateTaskApplyInfo system_update_task_apply_info;
|
SystemUpdateTaskApplyInfo system_update_task_apply_info;
|
||||||
public:
|
public:
|
||||||
MemoryInstallTaskData() { /* ... */ };
|
MemoryInstallTaskData() : state(InstallProgressState::NotPrepared), last_result(ResultSuccess()) { /* ... */ };
|
||||||
~MemoryInstallTaskData() {
|
~MemoryInstallTaskData() {
|
||||||
this->Cleanup();
|
this->Cleanup();
|
||||||
}
|
}
|
||||||
@ -87,8 +87,8 @@ namespace ams::ncm {
|
|||||||
class FileInstallTaskData : public InstallTaskDataBase {
|
class FileInstallTaskData : public InstallTaskDataBase {
|
||||||
private:
|
private:
|
||||||
struct Header {
|
struct Header {
|
||||||
s32 max_entries;
|
u32 max_entries;
|
||||||
s32 count;
|
u32 count;
|
||||||
s64 last_data_offset;
|
s64 last_data_offset;
|
||||||
Result last_result;
|
Result last_result;
|
||||||
InstallProgressState progress_state;
|
InstallProgressState progress_state;
|
||||||
@ -107,13 +107,9 @@ namespace ams::ncm {
|
|||||||
Header header;
|
Header header;
|
||||||
char path[64];
|
char path[64];
|
||||||
private:
|
private:
|
||||||
static constexpr s64 GetEntryInfoOffset(s32 index) {
|
|
||||||
return index * sizeof(EntryInfo) + sizeof(Header);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr Header MakeInitialHeader(s32 max_entries) {
|
static constexpr Header MakeInitialHeader(s32 max_entries) {
|
||||||
return {
|
return {
|
||||||
.max_entries = max_entries,
|
.max_entries = static_cast<u32>(max_entries),
|
||||||
.count = 0,
|
.count = 0,
|
||||||
.last_data_offset = GetEntryInfoOffset(max_entries),
|
.last_data_offset = GetEntryInfoOffset(max_entries),
|
||||||
.last_result = ResultSuccess(),
|
.last_result = ResultSuccess(),
|
||||||
@ -121,6 +117,10 @@ namespace ams::ncm {
|
|||||||
.system_update_task_apply_info = SystemUpdateTaskApplyInfo::Unknown,
|
.system_update_task_apply_info = SystemUpdateTaskApplyInfo::Unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr s64 GetEntryInfoOffset(s32 index) {
|
||||||
|
return index * sizeof(EntryInfo) + sizeof(Header);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
static Result Create(const char *path, s32 max_entries);
|
static Result Create(const char *path, s32 max_entries);
|
||||||
Result Initialize(const char *path);
|
Result Initialize(const char *path);
|
||||||
@ -135,15 +135,15 @@ namespace ams::ncm {
|
|||||||
virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override;
|
virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override;
|
||||||
virtual Result Cleanup() override;
|
virtual Result Cleanup() override;
|
||||||
private:
|
private:
|
||||||
Result GetEntryInfo(EntryInfo *out_entry_info, s32 index);
|
|
||||||
|
|
||||||
Result Read(void *out, size_t out_size, s64 offset);
|
|
||||||
Result Write(const void *data, size_t size, s64 offset);
|
|
||||||
Result WriteHeader();
|
|
||||||
|
|
||||||
virtual Result GetSize(size_t *out_size, s32 index) override;
|
virtual Result GetSize(size_t *out_size, s32 index) override;
|
||||||
virtual Result Get(s32 index, void *out, size_t out_size) override;
|
virtual Result Get(s32 index, void *out, size_t out_size) override;
|
||||||
virtual Result Update(s32 index, const void *data, size_t data_size) override;
|
virtual Result Update(s32 index, const void *data, size_t data_size) override;
|
||||||
|
|
||||||
|
Result GetEntryInfo(EntryInfo *out_entry_info, s32 index);
|
||||||
|
|
||||||
|
Result Write(const void *data, size_t size, s64 offset);
|
||||||
|
Result Read(void *out, size_t out_size, s64 offset);
|
||||||
|
Result WriteHeader();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,9 @@
|
|||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
enum class InstallProgressState : u8 {
|
constexpr inline s32 SystemMaxContentMetaCount = 0x800;
|
||||||
NotPrepared = 0,
|
constexpr inline s32 GameCardMaxContentMetaCount = 0x800;
|
||||||
DataPrepared = 1,
|
constexpr inline s32 UserMaxContentMetaCount = 0x2000;
|
||||||
Prepared = 2,
|
constexpr inline s32 SdCardMaxContentMetaCount = 0x2000;
|
||||||
Downloaded = 3,
|
|
||||||
Committed = 4,
|
|
||||||
Fatal = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
@ -22,9 +22,6 @@ namespace ams::ncm {
|
|||||||
private:
|
private:
|
||||||
MemoryInstallTaskData data;
|
MemoryInstallTaskData data;
|
||||||
public:
|
public:
|
||||||
PackageInstallTask() { /* ... */ }
|
|
||||||
virtual ~PackageInstallTask() override { /* ... */ }
|
|
||||||
|
|
||||||
Result Initialize(const char *package_root, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket);
|
Result Initialize(const char *package_root, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket);
|
||||||
protected:
|
protected:
|
||||||
bool IsContentMetaContentName(const char *name);
|
bool IsContentMetaContentName(const char *name);
|
||||||
|
@ -35,13 +35,13 @@ namespace ams::ncm {
|
|||||||
return this->package_root.Get();
|
return this->package_root.Get();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) override;
|
||||||
|
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) override;
|
||||||
|
|
||||||
void CreateContentMetaPath(PackagePath *out_path, ContentId content_id);
|
void CreateContentMetaPath(PackagePath *out_path, ContentId content_id);
|
||||||
void CreateContentPath(PackagePath *out_path, ContentId content_id);
|
void CreateContentPath(PackagePath *out_path, ContentId content_id);
|
||||||
void CreateTicketPath(PackagePath *out_path, fs::RightsId id);
|
void CreateTicketPath(PackagePath *out_path, fs::RightsId id);
|
||||||
void CreateCertificatePath(PackagePath *out_path, fs::RightsId id);
|
void CreateCertificatePath(PackagePath *out_path, fs::RightsId id);
|
||||||
private:
|
|
||||||
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) override;
|
|
||||||
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,10 @@ namespace ams::ncm {
|
|||||||
protected:
|
protected:
|
||||||
virtual Result PrepareInstallContentMetaData() override;
|
virtual Result PrepareInstallContentMetaData() override;
|
||||||
private:
|
private:
|
||||||
Result GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key);
|
|
||||||
virtual Result PrepareDependency() override;
|
virtual Result PrepareDependency() override;
|
||||||
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out, const ContentMetaKey &key) override;
|
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out, const ContentMetaKey &key) override;
|
||||||
|
|
||||||
|
Result GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ namespace ams::ncm {
|
|||||||
BuiltInUser = 4,
|
BuiltInUser = 4,
|
||||||
SdCard = 5,
|
SdCard = 5,
|
||||||
Any = 6,
|
Any = 6,
|
||||||
|
|
||||||
|
/* Aliases. */
|
||||||
|
Card = GameCard,
|
||||||
|
BuildInSystem = BuiltInSystem,
|
||||||
|
BuildInUser = BuiltInUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr inline bool IsUniqueStorage(StorageId id) {
|
constexpr inline bool IsUniqueStorage(StorageId id) {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/ncm/ncm_storage_id.hpp>
|
#include <stratosphere/ncm/ncm_storage_id.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
@ -67,7 +68,8 @@ namespace ams::ncm {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, size_t required_size);
|
Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, s64 required_size);
|
||||||
|
Result SelectPatchStorage(StorageId *out_storage_id, StorageId storage_id, PatchId patch_id);
|
||||||
const char *GetStorageIdString(StorageId storage_id);
|
const char *GetStorageIdString(StorageId storage_id);
|
||||||
const char *GetStorageIdStringForPlayReport(StorageId storage_id);
|
const char *GetStorageIdStringForPlayReport(StorageId storage_id);
|
||||||
|
|
@ -28,7 +28,7 @@ namespace ams::ncm {
|
|||||||
SubmissionPackageInstallTask();
|
SubmissionPackageInstallTask();
|
||||||
virtual ~SubmissionPackageInstallTask() override;
|
virtual ~SubmissionPackageInstallTask() override;
|
||||||
|
|
||||||
Result Initialize(fs::FileHandle handle, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket);
|
Result Initialize(fs::FileHandle handle, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,36 @@ namespace ams::ncm {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Handler>
|
||||||
|
Result ForEachContentInfo(const ContentMetaKey &key, ncm::ContentMetaDatabase *db, Handler handler) {
|
||||||
|
constexpr s32 MaxPerIteration = 0x10;
|
||||||
|
ContentInfo info_list[MaxPerIteration];
|
||||||
|
s32 offset = 0;
|
||||||
|
while (true) {
|
||||||
|
/* List the content infos. */
|
||||||
|
s32 count;
|
||||||
|
R_TRY(db->ListContentInfo(std::addressof(count), info_list, MaxPerIteration, key, offset));
|
||||||
|
|
||||||
|
/* Handle all that we listed. */
|
||||||
|
for (s32 i = 0; i < count; i++) {
|
||||||
|
bool done = false;
|
||||||
|
R_TRY(handler(std::addressof(done), info_list[i]));
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're done. */
|
||||||
|
if (count != MaxPerIteration) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 CalculateRequiredSize(s64 file_size, s64 cluster_size) {
|
s64 CalculateRequiredSize(s64 file_size, s64 cluster_size) {
|
||||||
@ -44,4 +74,16 @@ namespace ams::ncm {
|
|||||||
return file_size + ((file_size / ConcatenationFileSizeMax) + 1) * cluster_size;
|
return file_size + ((file_size / ConcatenationFileSizeMax) + 1) * cluster_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result EstimateRequiredSize(s64 *out_size, const ContentMetaKey &key, ncm::ContentMetaDatabase *db) {
|
||||||
|
s64 size = 0;
|
||||||
|
R_TRY(ForEachContentInfo(key, db, [&size](bool *out_done, const ContentInfo &info) -> Result {
|
||||||
|
size += CalculateRequiredSize(info.GetSize(), MaxClusterSize);
|
||||||
|
*out_done = false;
|
||||||
|
return ResultSuccess();
|
||||||
|
}));
|
||||||
|
|
||||||
|
*out_size = size;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,6 @@ namespace ams::ncm {
|
|||||||
.space_id = fs::SaveDataSpaceId::SdSystem,
|
.space_id = fs::SaveDataSpaceId::SdSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr size_t MaxBuiltInSystemContentMetaCount = 0x800;
|
|
||||||
constexpr size_t MaxBuiltInUserContentMetaCount = 0x2000;
|
|
||||||
constexpr size_t MaxSdCardContentMetaCount = 0x2000;
|
|
||||||
constexpr size_t MaxGameCardContentMetaCount = 0x800;
|
|
||||||
|
|
||||||
using RootPath = kvdb::BoundedString<32>;
|
using RootPath = kvdb::BoundedString<32>;
|
||||||
|
|
||||||
inline void ReplaceMountName(char *out_path, const char *mount_name, const char *path) {
|
inline void ReplaceMountName(char *out_path, const char *mount_name, const char *path) {
|
||||||
@ -342,7 +337,7 @@ namespace ams::ncm {
|
|||||||
R_TRY(this->ActivateContentStorage(StorageId::BuiltInSystem));
|
R_TRY(this->ActivateContentStorage(StorageId::BuiltInSystem));
|
||||||
|
|
||||||
/* Next, the BuiltInSystem content meta entry. */
|
/* Next, the BuiltInSystem content meta entry. */
|
||||||
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[this->num_content_meta_entries++], StorageId::BuiltInSystem, BuiltInSystemSystemSaveDataInfo, MaxBuiltInSystemContentMetaCount, std::addressof(g_system_content_meta_memory_resource)));
|
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[this->num_content_meta_entries++], StorageId::BuiltInSystem, BuiltInSystemSystemSaveDataInfo, SystemMaxContentMetaCount, std::addressof(g_system_content_meta_memory_resource)));
|
||||||
|
|
||||||
if (R_FAILED(this->VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
|
if (R_FAILED(this->VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
|
||||||
R_TRY(this->CreateContentMetaDatabase(StorageId::BuiltInSystem));
|
R_TRY(this->CreateContentMetaDatabase(StorageId::BuiltInSystem));
|
||||||
@ -370,18 +365,18 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Now for BuiltInUser's content storage and content meta entries. */
|
/* Now for BuiltInUser's content storage and content meta entries. */
|
||||||
R_TRY(this->InitializeContentStorageRoot(&this->content_storage_roots[this->num_content_storage_entries++], StorageId::BuiltInUser, fs::ContentStorageId::User));
|
R_TRY(this->InitializeContentStorageRoot(&this->content_storage_roots[this->num_content_storage_entries++], StorageId::BuiltInUser, fs::ContentStorageId::User));
|
||||||
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[this->num_content_meta_entries++], StorageId::BuiltInUser, BuiltInUserSystemSaveDataInfo, MaxBuiltInUserContentMetaCount, std::addressof(g_sd_and_user_content_meta_memory_resource)));
|
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[this->num_content_meta_entries++], StorageId::BuiltInUser, BuiltInUserSystemSaveDataInfo, UserMaxContentMetaCount, std::addressof(g_sd_and_user_content_meta_memory_resource)));
|
||||||
|
|
||||||
/* Beyond this point, N uses hardcoded indices. */
|
/* Beyond this point, N uses hardcoded indices. */
|
||||||
|
|
||||||
/* Next SdCard's content storage and content meta entries. */
|
/* Next SdCard's content storage and content meta entries. */
|
||||||
R_TRY(this->InitializeContentStorageRoot(&this->content_storage_roots[2], StorageId::SdCard, fs::ContentStorageId::SdCard));
|
R_TRY(this->InitializeContentStorageRoot(&this->content_storage_roots[2], StorageId::SdCard, fs::ContentStorageId::SdCard));
|
||||||
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[2], StorageId::SdCard, SdCardSystemSaveDataInfo, MaxSdCardContentMetaCount, std::addressof(g_sd_and_user_content_meta_memory_resource)));
|
R_TRY(this->InitializeContentMetaDatabaseRoot(&this->content_meta_database_roots[2], StorageId::SdCard, SdCardSystemSaveDataInfo, SdCardMaxContentMetaCount, std::addressof(g_sd_and_user_content_meta_memory_resource)));
|
||||||
|
|
||||||
/* GameCard's content storage and content meta entries. */
|
/* GameCard's content storage and content meta entries. */
|
||||||
/* N doesn't set a content storage id for game cards, so we'll just use 0 (System). */
|
/* N doesn't set a content storage id for game cards, so we'll just use 0 (System). */
|
||||||
R_TRY(this->InitializeGameCardContentStorageRoot(&this->content_storage_roots[3]));
|
R_TRY(this->InitializeGameCardContentStorageRoot(&this->content_storage_roots[3]));
|
||||||
R_TRY(this->InitializeGameCardContentMetaDatabaseRoot(&this->content_meta_database_roots[3], MaxGameCardContentMetaCount, std::addressof(g_gamecard_content_meta_memory_resource)));
|
R_TRY(this->InitializeGameCardContentMetaDatabaseRoot(&this->content_meta_database_roots[3], GameCardMaxContentMetaCount, std::addressof(g_gamecard_content_meta_memory_resource)));
|
||||||
|
|
||||||
this->initialized = true;
|
this->initialized = true;
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
|
@ -59,6 +59,35 @@ namespace ams::ncm {
|
|||||||
dst->attributes = src.attributes;
|
dst->attributes = src.attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FindDeltaIndex(s32 *out_index, const PatchMetaExtendedDataReader &reader, u32 src_version, u32 dst_version) {
|
||||||
|
/* Iterate over all deltas. */
|
||||||
|
auto header = reader.GetHeader();
|
||||||
|
for (s32 i = 0; i < static_cast<s32>(header->delta_count); i++) {
|
||||||
|
/* Check if the current delta matches the versions. */
|
||||||
|
auto delta = reader.GetPatchDeltaHeader(i);
|
||||||
|
if ((src_version == 0 || delta->delta.source_version == src_version) && delta->delta.destination_version == dst_version) {
|
||||||
|
*out_index = i;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We didn't find the delta. */
|
||||||
|
return ncm::ResultDeltaNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 CountContentExceptForMeta(const PatchMetaExtendedDataReader &reader, s32 delta_index) {
|
||||||
|
/* Iterate over packaged content infos, checking for those which aren't metas. */
|
||||||
|
s32 count = 0;
|
||||||
|
auto delta = reader.GetPatchDeltaHeader(delta_index);
|
||||||
|
for (s32 i = 0; i < static_cast<s32>(delta->content_count); i++) {
|
||||||
|
if (reader.GetPatchDeltaPackagedContentInfo(delta_index, i)->GetType() != ContentType::Meta) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PackagedContentMetaReader::CalculateConvertInstallContentMetaSize() const {
|
size_t PackagedContentMetaReader::CalculateConvertInstallContentMetaSize() const {
|
||||||
@ -148,6 +177,78 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result PackagedContentMetaReader::ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &meta, u32 source_version) {
|
||||||
|
/* Ensure that we have enough space. */
|
||||||
|
size_t required_size;
|
||||||
|
R_TRY(this->CalculateConvertFragmentOnlyInstallContentMetaSize(std::addressof(required_size), source_version));
|
||||||
|
AMS_ABORT_UNLESS(size >= required_size);
|
||||||
|
|
||||||
|
/* Find the delta index. */
|
||||||
|
PatchMetaExtendedDataReader reader(this->GetExtendedData(), this->GetExtendedDataSize());
|
||||||
|
s32 index;
|
||||||
|
R_TRY(FindDeltaIndex(std::addressof(index), reader, source_version, this->GetKey().version));
|
||||||
|
auto delta = reader.GetPatchDeltaHeader(index);
|
||||||
|
|
||||||
|
/* Prepare for conversion. */
|
||||||
|
const auto *packaged_header = this->GetHeader();
|
||||||
|
uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
|
||||||
|
|
||||||
|
/* Convert the header. */
|
||||||
|
InstallContentMetaHeader header;
|
||||||
|
ConvertPackageContentMetaHeaderToInstallContentMetaHeader(std::addressof(header), *packaged_header);
|
||||||
|
header.install_type = ContentInstallType::FragmentOnly;
|
||||||
|
|
||||||
|
/* Set the content count. */
|
||||||
|
auto fragment_count = CountContentExceptForMeta(reader, index);
|
||||||
|
header.content_count = static_cast<u16>(fragment_count) + 1;
|
||||||
|
|
||||||
|
/* Copy the header. */
|
||||||
|
std::memcpy(reinterpret_cast<void *>(dst_addr), std::addressof(header), sizeof(header));
|
||||||
|
dst_addr += sizeof(header);
|
||||||
|
|
||||||
|
/* Copy the extended header. */
|
||||||
|
std::memcpy(reinterpret_cast<void *>(dst_addr), reinterpret_cast<void *>(this->GetExtendedHeaderAddress()), packaged_header->extended_header_size);
|
||||||
|
dst_addr += packaged_header->extended_header_size;
|
||||||
|
|
||||||
|
/* Copy the top level meta. */
|
||||||
|
std::memcpy(reinterpret_cast<void *>(dst_addr), std::addressof(meta), sizeof(meta));
|
||||||
|
dst_addr += sizeof(meta);
|
||||||
|
|
||||||
|
s32 count = 0;
|
||||||
|
for (s32 i = 0; i < static_cast<s32>(delta->content_count); i++) {
|
||||||
|
auto packaged_content_info = reader.GetPatchDeltaPackagedContentInfo(index, i);
|
||||||
|
if (packaged_content_info->GetType() != ContentType::Meta) {
|
||||||
|
/* Create the install content info. */
|
||||||
|
InstallContentInfo install_content_info = InstallContentInfo::Make(*packaged_content_info, packaged_header->type);
|
||||||
|
|
||||||
|
/* Copy the info. */
|
||||||
|
std::memcpy(reinterpret_cast<void *>(dst_addr), std::addressof(install_content_info), sizeof(InstallContentInfo));
|
||||||
|
dst_addr += sizeof(InstallContentInfo);
|
||||||
|
|
||||||
|
/* Increment the count. */
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assert that we copied the right number of infos. */
|
||||||
|
AMS_ASSERT(count == fragment_count);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PackagedContentMetaReader::CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) const {
|
||||||
|
/* Find the delta index. */
|
||||||
|
PatchMetaExtendedDataReader reader(this->GetExtendedData(), this->GetExtendedDataSize());
|
||||||
|
s32 index;
|
||||||
|
R_TRY(FindDeltaIndex(std::addressof(index), reader, source_version, this->GetKey().version));
|
||||||
|
|
||||||
|
/* Get the fragment count. */
|
||||||
|
auto fragment_count = CountContentExceptForMeta(reader, index);
|
||||||
|
|
||||||
|
/* Recalculate. */
|
||||||
|
return CalculateSizeImpl<InstallContentMetaHeader, InstallContentInfo>(this->GetExtendedHeaderSize(), fragment_count + 1, 0, this->GetExtendedDataSize(), false);
|
||||||
|
}
|
||||||
|
|
||||||
void PackagedContentMetaReader::ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta) {
|
void PackagedContentMetaReader::ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta) {
|
||||||
/* Ensure we have enough space to convert. */
|
/* Ensure we have enough space to convert. */
|
||||||
AMS_ABORT_UNLESS(size >= this->CalculateConvertContentMetaSize());
|
AMS_ABORT_UNLESS(size >= this->CalculateConvertContentMetaSize());
|
||||||
|
@ -88,15 +88,13 @@ namespace ams::ncm {
|
|||||||
/* TODO: ON_SCOPE_EXIT { <auto abort func> }; */
|
/* TODO: ON_SCOPE_EXIT { <auto abort func> }; */
|
||||||
|
|
||||||
/* No firmware variations to list. */
|
/* No firmware variations to list. */
|
||||||
if (reader.GetExtendedDataSize() == 0) {
|
R_SUCCEED_IF(reader.GetExtendedDataSize() == 0);
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemUpdateMetaExtendedDataReader extended_data_reader(reader.GetExtendedData(), reader.GetExtendedDataSize());
|
SystemUpdateMetaExtendedDataReader extended_data_reader(reader.GetExtendedData(), reader.GetExtendedDataSize());
|
||||||
std::optional<s32> firmware_variation_index = std::nullopt;
|
std::optional<s32> firmware_variation_index = std::nullopt;
|
||||||
|
|
||||||
/* Find the input firmware variation id. */
|
/* Find the input firmware variation id. */
|
||||||
for (s32 i = 0; i < extended_data_reader.GetFirmwareVariationCount(); i++) {
|
for (size_t i = 0; i < extended_data_reader.GetFirmwareVariationCount(); i++) {
|
||||||
if (*extended_data_reader.GetFirmwareVariationId(i) == firmware_variation_id) {
|
if (*extended_data_reader.GetFirmwareVariationId(i) == firmware_variation_id) {
|
||||||
firmware_variation_index = i;
|
firmware_variation_index = i;
|
||||||
break;
|
break;
|
||||||
@ -104,26 +102,20 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We couldn't find the input firmware variation id. */
|
/* We couldn't find the input firmware variation id. */
|
||||||
if (!firmware_variation_index) {
|
R_UNLESS(firmware_variation_index, ncm::ResultInvalidFirmwareVariation());
|
||||||
return ResultInvalidFirmwareVariation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain the variation info. */
|
/* Obtain the variation info. */
|
||||||
const FirmwareVariationInfo *variation_info = extended_data_reader.GetFirmwareVariationInfo(*firmware_variation_index);
|
const FirmwareVariationInfo *variation_info = extended_data_reader.GetFirmwareVariationInfo(*firmware_variation_index);
|
||||||
|
|
||||||
/* Success if refer to base, or unk is 1 (unk is usually 2). */
|
/* 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) {
|
R_SUCCEED_IF(variation_info->refer_to_base || extended_data_reader.GetHeader()->unk == 1);
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output the content meta count. */
|
/* Output the content meta count. */
|
||||||
const u32 content_meta_count = variation_info->content_meta_count;
|
const u32 content_meta_count = variation_info->content_meta_count;
|
||||||
*out_count = content_meta_count;
|
*out_count = content_meta_count;
|
||||||
|
|
||||||
/* No content metas to list. */
|
/* We're done if there are no content metas to list. */
|
||||||
if (content_meta_count == 0) {
|
R_SUCCEED_IF(content_meta_count);
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a buffer for the content meta infos. */
|
/* Allocate a buffer for the content meta infos. */
|
||||||
std::unique_ptr<ContentMetaInfo[]> buffer(new (std::nothrow) ContentMetaInfo[content_meta_count]);
|
std::unique_ptr<ContentMetaInfo[]> buffer(new (std::nothrow) ContentMetaInfo[content_meta_count]);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -232,13 +232,6 @@ namespace ams::ncm {
|
|||||||
return this->Read(std::addressof(this->header), sizeof(Header), 0);
|
return this->Read(std::addressof(this->header), sizeof(Header), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileInstallTaskData::Read(void *out, size_t out_size, s64 offset) {
|
|
||||||
fs::FileHandle file;
|
|
||||||
R_TRY(fs::OpenFile(std::addressof(file), this->path, fs::OpenMode_Read));
|
|
||||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
|
||||||
return fs::ReadFile(file, offset, out, out_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileInstallTaskData::GetProgress(InstallProgress *out_progress) {
|
Result FileInstallTaskData::GetProgress(InstallProgress *out_progress) {
|
||||||
/* Initialize install progress. */
|
/* Initialize install progress. */
|
||||||
InstallProgress install_progress = {
|
InstallProgress install_progress = {
|
||||||
@ -248,7 +241,7 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Only states after prepared are allowed. */
|
/* Only states after prepared are allowed. */
|
||||||
if (this->header.progress_state != InstallProgressState::NotPrepared && this->header.progress_state != InstallProgressState::DataPrepared) {
|
if (this->header.progress_state != InstallProgressState::NotPrepared && this->header.progress_state != InstallProgressState::DataPrepared) {
|
||||||
for (s32 i = 0; i < this->header.count; i++) {
|
for (size_t i = 0; i < this->header.count; i++) {
|
||||||
/* Obtain the content meta for this entry. */
|
/* Obtain the content meta for this entry. */
|
||||||
InstallContentMeta content_meta;
|
InstallContentMeta content_meta;
|
||||||
R_TRY(InstallTaskDataBase::Get(std::addressof(content_meta), i));
|
R_TRY(InstallTaskDataBase::Get(std::addressof(content_meta), i));
|
||||||
@ -267,11 +260,6 @@ namespace ams::ncm {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileInstallTaskData::GetEntryInfo(EntryInfo *out_entry_info, s32 index) {
|
|
||||||
AMS_ABORT_UNLESS(index < this->header.count);
|
|
||||||
return this->Read(out_entry_info, sizeof(EntryInfo), GetEntryInfoOffset(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileInstallTaskData::GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) {
|
Result FileInstallTaskData::GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) {
|
||||||
*out_info = this->header.system_update_task_apply_info;
|
*out_info = this->header.system_update_task_apply_info;
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
@ -282,10 +270,6 @@ namespace ams::ncm {
|
|||||||
return this->WriteHeader();
|
return this->WriteHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileInstallTaskData::WriteHeader() {
|
|
||||||
return this->Write(std::addressof(this->header), sizeof(Header), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileInstallTaskData::SetLastResult(Result result) {
|
Result FileInstallTaskData::SetLastResult(Result result) {
|
||||||
this->header.last_result = result;
|
this->header.last_result = result;
|
||||||
return this->WriteHeader();
|
return this->WriteHeader();
|
||||||
@ -300,7 +284,7 @@ namespace ams::ncm {
|
|||||||
R_UNLESS(this->header.count < this->header.max_entries, ncm::ResultBufferInsufficient());
|
R_UNLESS(this->header.count < this->header.max_entries, ncm::ResultBufferInsufficient());
|
||||||
|
|
||||||
/* Create a new entry info. Data of the given size will be stored at the end of the file. */
|
/* Create a new entry info. Data of the given size will be stored at the end of the file. */
|
||||||
const EntryInfo entry_info = { this->header.last_data_offset, data_size };
|
const EntryInfo entry_info = { this->header.last_data_offset, static_cast<s64>(data_size) };
|
||||||
|
|
||||||
/* Write the new entry info. */
|
/* Write the new entry info. */
|
||||||
R_TRY(this->Write(std::addressof(entry_info), sizeof(EntryInfo), GetEntryInfoOffset(this->header.count)));
|
R_TRY(this->Write(std::addressof(entry_info), sizeof(EntryInfo), GetEntryInfoOffset(this->header.count)));
|
||||||
@ -316,13 +300,6 @@ namespace ams::ncm {
|
|||||||
return this->WriteHeader();
|
return this->WriteHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileInstallTaskData::Write(const void *data, size_t size, s64 offset) {
|
|
||||||
fs::FileHandle file;
|
|
||||||
R_TRY(fs::OpenFile(std::addressof(file), this->path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
|
||||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
|
||||||
return fs::WriteFile(file, offset, data, size, fs::WriteOption::Flush);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileInstallTaskData::Count(s32 *out) {
|
Result FileInstallTaskData::Count(s32 *out) {
|
||||||
*out = this->header.count;
|
*out = this->header.count;
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
@ -394,4 +371,27 @@ namespace ams::ncm {
|
|||||||
return this->WriteHeader();
|
return this->WriteHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FileInstallTaskData::GetEntryInfo(EntryInfo *out_entry_info, s32 index) {
|
||||||
|
AMS_ABORT_UNLESS(static_cast<u32>(index) < this->header.count);
|
||||||
|
return this->Read(out_entry_info, sizeof(EntryInfo), GetEntryInfoOffset(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileInstallTaskData::Write(const void *data, size_t size, s64 offset) {
|
||||||
|
fs::FileHandle file;
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(file), this->path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||||
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
return fs::WriteFile(file, offset, data, size, fs::WriteOption::Flush);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileInstallTaskData::Read(void *out, size_t out_size, s64 offset) {
|
||||||
|
fs::FileHandle file;
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(file), this->path, fs::OpenMode_Read));
|
||||||
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
return fs::ReadFile(file, offset, out, out_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileInstallTaskData::WriteHeader() {
|
||||||
|
return this->Write(std::addressof(this->header), sizeof(Header), 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -32,6 +32,7 @@ namespace ams::ncm {
|
|||||||
} else {
|
} else {
|
||||||
this->CreateContentPath(std::addressof(path), content_info->GetId());
|
this->CreateContentPath(std::addressof(path), content_info->GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the file. */
|
/* Open the file. */
|
||||||
fs::FileHandle file;
|
fs::FileHandle file;
|
||||||
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read));
|
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read));
|
||||||
@ -55,18 +56,6 @@ namespace ams::ncm {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageInstallTaskBase::CreateContentMetaPath(PackagePath *out_path, ContentId content_id) {
|
|
||||||
char str[ContentIdStringLength + 1] = {};
|
|
||||||
GetStringFromContentId(str, sizeof(str), content_id);
|
|
||||||
out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".cnmt.nca");
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackageInstallTaskBase::CreateContentPath(PackagePath *out_path, ContentId content_id) {
|
|
||||||
char str[ContentIdStringLength + 1] = {};
|
|
||||||
GetStringFromContentId(str, sizeof(str), content_id);
|
|
||||||
out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".nca");
|
|
||||||
}
|
|
||||||
|
|
||||||
Result PackageInstallTaskBase::InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) {
|
Result PackageInstallTaskBase::InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) {
|
||||||
/* Read ticket from file. */
|
/* Read ticket from file. */
|
||||||
s64 ticket_size;
|
s64 ticket_size;
|
||||||
@ -113,6 +102,18 @@ namespace ams::ncm {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PackageInstallTaskBase::CreateContentPath(PackagePath *out_path, ContentId content_id) {
|
||||||
|
char str[ContentIdStringLength + 1] = {};
|
||||||
|
GetStringFromContentId(str, sizeof(str), content_id);
|
||||||
|
out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".nca");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackageInstallTaskBase::CreateContentMetaPath(PackagePath *out_path, ContentId content_id) {
|
||||||
|
char str[ContentIdStringLength + 1] = {};
|
||||||
|
GetStringFromContentId(str, sizeof(str), content_id);
|
||||||
|
out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".cnmt.nca");
|
||||||
|
}
|
||||||
|
|
||||||
void PackageInstallTaskBase::CreateTicketPath(PackagePath *out_path, fs::RightsId id) {
|
void PackageInstallTaskBase::CreateTicketPath(PackagePath *out_path, fs::RightsId id) {
|
||||||
char str[RightsIdStringLength + 1] = {};
|
char str[RightsIdStringLength + 1] = {};
|
||||||
GetStringFromRightsId(str, sizeof(str), id);
|
GetStringFromRightsId(str, sizeof(str), id);
|
||||||
|
@ -38,15 +38,10 @@ namespace ams::ncm {
|
|||||||
/* Activate the game card content meta database. */
|
/* Activate the game card content meta database. */
|
||||||
R_TRY(ActivateContentMetaDatabase(StorageId::GameCard));
|
R_TRY(ActivateContentMetaDatabase(StorageId::GameCard));
|
||||||
this->gamecard_content_meta_database_active = true;
|
this->gamecard_content_meta_database_active = true;
|
||||||
|
auto meta_db_guard = SCOPE_GUARD { this->Inactivate(); };
|
||||||
|
|
||||||
/* Open the game card content meta database. */
|
/* Open the game card content meta database. */
|
||||||
OpenContentMetaDatabase(std::addressof(this->package_db), StorageId::GameCard);
|
OpenContentMetaDatabase(std::addressof(this->package_db), StorageId::GameCard);
|
||||||
auto meta_db_guard = SCOPE_GUARD {
|
|
||||||
if (this->gamecard_content_meta_database_active) {
|
|
||||||
InactivateContentMetaDatabase(StorageId::GameCard);
|
|
||||||
this->gamecard_content_meta_database_active = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ContentMetaDatabaseBuilder builder(std::addressof(this->package_db));
|
ContentMetaDatabaseBuilder builder(std::addressof(this->package_db));
|
||||||
|
|
||||||
@ -56,10 +51,8 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Create a new context file. */
|
/* Create a new context file. */
|
||||||
fs::DeleteFile(context_path);
|
fs::DeleteFile(context_path);
|
||||||
R_TRY(FileInstallTaskData::Create(context_path, 0x800));
|
R_TRY(FileInstallTaskData::Create(context_path, GameCardMaxContentMetaCount));
|
||||||
auto context_guard = SCOPE_GUARD {
|
auto context_guard = SCOPE_GUARD { fs::DeleteFile(context_path); };
|
||||||
fs::DeleteFile(context_path);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Initialize data. */
|
/* Initialize data. */
|
||||||
R_TRY(this->data.Initialize(context_path));
|
R_TRY(this->data.Initialize(context_path));
|
||||||
@ -113,6 +106,24 @@ namespace ams::ncm {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result PackageSystemUpdateTask::PrepareInstallContentMetaData() {
|
||||||
|
/* Obtain a SystemUpdate key. */
|
||||||
|
ContentMetaKey key;
|
||||||
|
auto list_count = this->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. */
|
||||||
|
return this->PrepareContentMeta(InstallContentMetaInfo::MakeUnverifiable(info.GetId(), info.GetSize(), key), key, std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PackageSystemUpdateTask::PrepareDependency() {
|
||||||
|
return this->PrepareSystemUpdateDependency();
|
||||||
|
}
|
||||||
|
|
||||||
Result PackageSystemUpdateTask::GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key) {
|
Result PackageSystemUpdateTask::GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key) {
|
||||||
s32 ofs = 0;
|
s32 ofs = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -137,22 +148,4 @@ namespace ams::ncm {
|
|||||||
return ncm::ResultContentInfoNotFound();
|
return ncm::ResultContentInfoNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PackageSystemUpdateTask::PrepareInstallContentMetaData() {
|
|
||||||
/* Obtain a SystemUpdate key. */
|
|
||||||
ContentMetaKey key;
|
|
||||||
auto list_count = this->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. */
|
|
||||||
return this->PrepareContentMeta(InstallContentMetaInfo::MakeUnverifiable(info.GetId(), info.GetSize(), key), key, std::nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result PackageSystemUpdateTask::PrepareDependency() {
|
|
||||||
return this->PrepareSystemUpdateDependency();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,29 +17,7 @@
|
|||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
namespace {
|
Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, s64 required_size) {
|
||||||
|
|
||||||
constexpr const char *StorageIdStrings[] = {
|
|
||||||
"None",
|
|
||||||
"Host",
|
|
||||||
"GameCard",
|
|
||||||
"BuiltInSystem",
|
|
||||||
"BuiltInUser",
|
|
||||||
"SdCard"
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr const char *StorageIdStringsForPlayReport[] = {
|
|
||||||
"None",
|
|
||||||
"Host",
|
|
||||||
"Card",
|
|
||||||
"BuildInSystem",
|
|
||||||
"BuildInUser",
|
|
||||||
"SdCard"
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, size_t required_size) {
|
|
||||||
auto list = GetStorageList(storage_id);
|
auto list = GetStorageList(storage_id);
|
||||||
for (s32 i = 0; i < list.Count(); i++) {
|
for (s32 i = 0; i < list.Count(); i++) {
|
||||||
auto candidate = list[i];
|
auto candidate = list[i];
|
||||||
@ -73,14 +51,77 @@ namespace ams::ncm {
|
|||||||
return ncm::ResultNotEnoughInstallSpace();
|
return ncm::ResultNotEnoughInstallSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SelectPatchStorage(StorageId *out_storage_id, StorageId storage_id, PatchId patch_id) {
|
||||||
|
auto list = GetStorageList(storage_id);
|
||||||
|
u32 version = 0;
|
||||||
|
*out_storage_id = storage_id;
|
||||||
|
|
||||||
|
for (s32 i = 0; i < list.Count(); i++) {
|
||||||
|
auto candidate = list[i];
|
||||||
|
|
||||||
|
/* Open the content meta database. */
|
||||||
|
ContentMetaDatabase content_meta_database;
|
||||||
|
if (R_FAILED(ncm::OpenContentMetaDatabase(std::addressof(content_meta_database), candidate))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the latest key. */
|
||||||
|
ContentMetaKey key;
|
||||||
|
R_TRY_CATCH(content_meta_database.GetLatest(std::addressof(key), patch_id.value)) {
|
||||||
|
R_CATCH(ncm::ResultContentMetaNotFound) { continue; }
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
if (key.version > version) {
|
||||||
|
version = key.version;
|
||||||
|
*out_storage_id = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr const char * const StorageIdStrings[] = {
|
||||||
|
"None",
|
||||||
|
"Host",
|
||||||
|
"GameCard",
|
||||||
|
"BuiltInSystem",
|
||||||
|
"BuiltInUser",
|
||||||
|
"SdCard"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char * const StorageIdStringsForPlayReport[] = {
|
||||||
|
"None",
|
||||||
|
"Host",
|
||||||
|
"Card",
|
||||||
|
"BuildInSystem",
|
||||||
|
"BuildInUser",
|
||||||
|
"SdCard"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const char *GetStorageIdString(StorageId storage_id) {
|
const char *GetStorageIdString(StorageId storage_id) {
|
||||||
u8 id = static_cast<u8>(storage_id);
|
switch (storage_id) {
|
||||||
return id > 5 ? "(unknown)" : StorageIdStrings[id];
|
case StorageId::None: return "None";
|
||||||
|
case StorageId::Host: return "Host";
|
||||||
|
case StorageId::GameCard: return "GameCard";
|
||||||
|
case StorageId::BuiltInSystem: return "BuiltInSystem";
|
||||||
|
case StorageId::BuiltInUser: return "BuiltInUser";
|
||||||
|
default: return "(unknown)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetStorageIdStringForPlayReport(StorageId storage_id) {
|
const char *GetStorageIdStringForPlayReport(StorageId storage_id) {
|
||||||
u8 id = static_cast<u8>(storage_id);
|
switch (storage_id) {
|
||||||
return id > 5 ? "(unknown)" : StorageIdStringsForPlayReport[id];
|
case StorageId::None: return "None";
|
||||||
|
case StorageId::Host: return "Host";
|
||||||
|
case StorageId::Card: return "Card";
|
||||||
|
case StorageId::BuildInSystem: return "BuildInSystem";
|
||||||
|
case StorageId::BuildInUser: return "BuildInUser";
|
||||||
|
default: return "(unknown)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -42,6 +42,7 @@ namespace ams::ncm {
|
|||||||
R_DEFINE_ERROR_RESULT(NotEnoughInstallSpace, 200);
|
R_DEFINE_ERROR_RESULT(NotEnoughInstallSpace, 200);
|
||||||
R_DEFINE_ERROR_RESULT(SystemUpdateNotFoundInPackage, 210);
|
R_DEFINE_ERROR_RESULT(SystemUpdateNotFoundInPackage, 210);
|
||||||
R_DEFINE_ERROR_RESULT(ContentInfoNotFound, 220);
|
R_DEFINE_ERROR_RESULT(ContentInfoNotFound, 220);
|
||||||
|
R_DEFINE_ERROR_RESULT(DeltaNotFound, 237);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidContentMetaKey, 240);
|
R_DEFINE_ERROR_RESULT(InvalidContentMetaKey, 240);
|
||||||
R_DEFINE_ERROR_RESULT(IgnorableInstallTicketFailure, 280);
|
R_DEFINE_ERROR_RESULT(IgnorableInstallTicketFailure, 280);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user