diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_rights_id.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_rights_id.hpp index 6c81d83bb..9d03387de 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_rights_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_rights_id.hpp @@ -19,12 +19,26 @@ namespace ams::fs { union RightsId { - u8 data[0x10]; - u64 data64[2]; + u8 data[0x10]; + u64 data64[2]; }; static_assert(sizeof(RightsId) == 0x10); static_assert(std::is_pod::value); + inline bool operator==(const RightsId &lhs, const RightsId& rhs) { + return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) == 0; + } + + inline bool operator!=(const RightsId &lhs, const RightsId &rhs) { + return !(lhs == rhs); + } + + inline bool operator<(const RightsId &lhs, const RightsId& rhs) { + return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) < 0; + } + + constexpr inline RightsId InvalidRightsId = {}; + /* Rights ID API */ Result GetRightsId(RightsId *out, const char *path); Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path); diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta.hpp index 96c7a59b6..71da4e557 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta.hpp @@ -340,13 +340,11 @@ namespace ams::ncm { void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta); Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) { - /* TODO */ - return ResultSuccess(); + AMS_ABORT("Not implemented"); }; Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version) { - /* TODO */ - return ResultSuccess(); + AMS_ABORT("Not implemented"); } size_t CountDeltaFragments() const; diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp index 1fa1cc67a..cabc7c569 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp @@ -19,9 +19,6 @@ namespace ams::ncm { -/* protected: -PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMetaData, PrepareDependency, PrepareSystemDependency, PrepareContentMetaIfLatest, GetConfig, WriteContentMetaToPlaceHolder, GetInstallStorage, GetSystemUpdateTaskApplyInfo, CanContinue -*/ enum class ListContentMetaKeyFilter : u8 { All = 0, Committed = 1, @@ -91,18 +88,30 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta } 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 is_temporary); + Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr *out_meta_infos, const ContentMetaKey &key); + Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span 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 is_temporary); + Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional key, std::optional source_version); + Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional 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: - /* TODO: Fix access types. */ bool IsCancelRequested(); Result Prepare(); void SetLastResult(Result last_result); @@ -110,14 +119,12 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta 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(); - Result CleanupOne(const InstallContentMeta &content_meta); void CleanupProgress(); Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter); Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset); @@ -128,32 +135,19 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMeta Result VerifyAllNotCommitted(const StorageContentMetaKey *keys, s32 num_keys); Result Commit(const StorageContentMetaKey *keys, s32 num_keys); Result IncludesExFatDriver(bool *out); - Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size); - Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional is_temporary); - InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, std::optional is_temporary); - Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional key, std::optional source_version); - Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional source_version); - Result PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer); - Result PrepareSystemUpdateDependency(); - Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr *out_meta_infos, const ContentMetaKey &key); - Result PrepareContentMetaIfLatest(const ContentMetaKey &key); - Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out); Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key); - Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys); void ResetLastResult(); s64 GetThroughput(); Result CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id); Result FindMaxRequiredApplicationVersion(u32 *out); Result FindMaxRequiredSystemVersion(u32 *out); Result ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset); - - Result CanContinue(); void SetFirmwareVariationId(FirmwareVariationId id); + Result ListRightsIds(s32 *out_count, Span out_span, const ContentMetaKey &key, s32 offset); protected: virtual Result OnPrepareComplete(); virtual Result PrepareDependency(); public: - /* TODO: Fix access types. */ virtual void Cancel(); virtual void ResetCancel(); virtual InstallProgress GetProgress(); diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_occupied_size.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_occupied_size.hpp index e8caf1718..359a8eabc 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_occupied_size.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_occupied_size.hpp @@ -25,4 +25,6 @@ namespace ams::ncm { u8 reserved[7]; }; + static_assert(sizeof(InstallTaskOccupiedSize) == 0x20); + } \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id.hpp index 03b520d94..6806fa7f5 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id.hpp @@ -27,4 +27,15 @@ namespace ams::ncm { static_assert(sizeof(RightsId) == 0x18); static_assert(std::is_pod::value); + inline bool operator==(const RightsId &lhs, const RightsId &rhs) { + return std::tie(lhs.id, lhs.key_generation) == std::tie(rhs.id, rhs.key_generation); + } + + inline bool operator!=(const RightsId &lhs, const RightsId &rhs) { + return !(lhs == rhs); + } + + inline bool operator<(const RightsId &lhs, const RightsId &rhs) { + return std::tie(lhs.id, lhs.key_generation) < std::tie(rhs.id, rhs.key_generation); + } } diff --git a/libraries/libstratosphere/source/ncm/ncm_install_task.cpp b/libraries/libstratosphere/source/ncm/ncm_install_task.cpp index 4fac82584..c892253f3 100644 --- a/libraries/libstratosphere/source/ncm/ncm_install_task.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_install_task.cpp @@ -1305,4 +1305,73 @@ namespace ams::ncm { void InstallTaskBase::SetFirmwareVariationId(FirmwareVariationId id) { this->firmware_variation_id = id; } + + Result InstallTaskBase::ListRightsIds(s32 *out_count, Span out_span, const ContentMetaKey &key, s32 offset) { + /* Count the number of content meta entries. */ + s32 count; + R_TRY(this->data->Count(std::addressof(count))); + + /* Ensure count is >= 1. */ + R_UNLESS(count >= 1, ncm::ResultContentMetaNotFound()); + + /* Iterate over content meta. */ + for (s32 i = 0; i < count; i++) { + /* Obtain the content meta. */ + InstallContentMeta content_meta; + R_TRY(this->data->Get(std::addressof(content_meta), i)); + + /* Create a reader. */ + const InstallContentMetaReader reader = content_meta.GetReader(); + + /* List rights ids if the reader's key matches ours. */ + if (reader.GetKey() == key) { + return this->ListRightsIdsByInstallContentMeta(out_count, out_span, content_meta, offset); + } + } + + return ncm::ResultContentMetaNotFound(); + } + + Result InstallTaskBase::ListRightsIdsByInstallContentMeta(s32 *out_count, Span out_span, const InstallContentMeta &content_meta, s32 offset) { + /* If the offset is greater than zero, we can't create a unique span of rights ids. */ + /* Thus, we have nothing to list. */ + if (offset > 0) { + *out_count = 0; + return ResultSuccess(); + } + + /* Create a reader. */ + const InstallContentMetaReader reader = content_meta.GetReader(); + + s32 count = 0; + for (size_t i = 0; i < reader.GetContentCount(); i++) { + const auto *content_info = reader.GetContentInfo(i); + + /* Skip meta content infos and already installed content infos. Also skip if the content meta has already been comitted. */ + if (content_info->GetType() == ContentType::Meta || content_info->GetInstallState() == InstallState::Installed || reader.GetHeader()->committed) { + continue; + } + + /* Open the relevant content storage. */ + ContentStorage content_storage; + R_TRY(ncm::OpenContentStorage(&content_storage, content_info->storage_id)); + + /* Get the rights id. */ + RightsId rights_id; + R_TRY(content_storage.GetRightsId(std::addressof(rights_id), content_info->GetPlaceHolderId())); + + /* Skip empty rights ids. */ + if (rights_id.id == fs::InvalidRightsId) { + continue; + } + + /* Output the rights id. */ + out_span[count++] = rights_id; + } + + /* Sort and remove duplicate ids from the output span. */ + std::sort(out_span.begin(), out_span.end()); + *out_count = std::distance(out_span.begin(), std::unique(out_span.begin(), out_span.end())); + return ResultSuccess(); + } }