/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
namespace ams::ncm {
enum class ListContentMetaKeyFilter : u8 {
All = 0,
Committed = 1,
NotCommitted = 2,
};
enum InstallConfig {
InstallConfig_None = (0 << 0),
InstallConfig_SystemUpdate = (1 << 2),
InstallConfig_RequiresExFatDriver = (1 << 3),
InstallConfig_IgnoreTicket = (1 << 4),
};
struct InstallThroughput {
s64 installed;
TimeSpan elapsed_time;
};
struct InstallContentMetaInfo {
ContentId content_id;
s64 content_size;
ContentMetaKey key;
bool verify_digest;
bool has_key;
Digest digest;
static constexpr InstallContentMetaInfo MakeVerifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky, const Digest &d) {
return {
.content_id = cid,
.content_size = sz,
.key = ky,
.verify_digest = true,
.has_key = true,
.digest = d,
};
}
static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky) {
return {
.content_id = cid,
.content_size = sz,
.key = ky,
.verify_digest = false,
.has_key = true,
};
}
static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz) {
return {
.content_id = cid,
.content_size = sz,
.verify_digest = false,
.has_key = false,
};
}
};
static_assert(sizeof(InstallContentMetaInfo) == 0x50);
class InstallTaskBase {
NON_COPYABLE(InstallTaskBase);
NON_MOVEABLE(InstallTaskBase);
private:
crypto::Sha256Generator m_sha256_generator{};
StorageId m_install_storage{};
InstallTaskDataBase *m_data{};
InstallProgress m_progress{};
os::SdkMutex m_progress_mutex{};
u32 m_config{};
os::SdkMutex m_cancel_mutex{};
bool m_cancel_requested{};
InstallThroughput m_throughput{};
TimeSpan m_throughput_start_time{};
os::SdkMutex m_throughput_mutex{};
FirmwareVariationId m_firmware_variation_id{};
private:
ALWAYS_INLINE Result SetLastResultOnFailure(Result result) {
if (R_FAILED(result)) {
this->SetLastResult(result);
}
R_RETURN(result);
}
public:
InstallTaskBase() : m_data(), m_progress(), m_progress_mutex(), m_cancel_mutex(), m_cancel_requested(), m_throughput_mutex() { /* ... */ }
virtual ~InstallTaskBase() { /* ... */ };
public:
virtual void Cancel();
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) { R_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() { R_RETURN(this->Commit(nullptr, 0)); }
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, util::optional key, util::optional 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 GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) = 0;
virtual Result PrepareDependency();
Result PrepareSystemUpdateDependency();
virtual Result PrepareContentMetaIfLatest(const ContentMetaKey &key); /* NOTE: This is not virtual in Nintendo's code. We do so to facilitate downgrades. */
u32 GetConfig() const { return m_config; }
Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, util::optional is_temporary);
StorageId GetInstallStorage() const { return m_install_storage; }
virtual Result OnPrepareComplete() { R_SUCCEED(); }
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 GetLatestVersion(util::optional *out_version, u64 id) { AMS_UNUSED(out_version, id); R_THROW(ncm::ResultContentMetaNotFound()); }
virtual Result OnExecuteComplete() { R_SUCCEED(); }
Result WritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info);
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;
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, util::optional source_version);
InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, util::optional is_temporary);
Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr *out_meta_infos, const ContentMetaKey &key, fs::ContentAttributes attr);
Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span out_span, const InstallContentMeta &content_meta, s32 offset);
public:
virtual Result CheckInstallable() { R_SUCCEED(); }
void SetFirmwareVariationId(FirmwareVariationId id) { m_firmware_variation_id = id; }
Result ListRightsIds(s32 *out_count, Span out_span, const ContentMetaKey &key, s32 offset);
};
}