diff --git a/libraries/libstratosphere/include/stratosphere/ncm.hpp b/libraries/libstratosphere/include/stratosphere/ncm.hpp index 343073124..38811eaec 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm.hpp @@ -18,5 +18,6 @@ #include "ncm/ncm_types.hpp" #include "ncm/ncm_content_meta.hpp" -#include "ncm/ncm_i_content_meta_database.hpp" -#include "ncm/ncm_i_content_storage.hpp" +#include "ncm/ncm_content_meta_database.hpp" +#include "ncm/ncm_content_storage.hpp" +#include "ncm/ncm_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp new file mode 100644 index 000000000..4d42dd3b9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 +#include +#include + +namespace ams::ncm { + + /* Management. */ + void Initialize(); + void Finalize(); + + void InitializeWithObject(std::shared_ptr manager_object); + + /* Service API. */ + Result CreateContentStorage(StorageId storage_id); + Result CreateContentMetaDatabase(StorageId storage_id); + + Result VerifyContentStorage(StorageId storage_id); + Result VerifyContentMetaDatabase(StorageId storage_id); + + Result OpenContentStorage(ContentStorage *out, StorageId storage_id); + Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id); + + Result CleanupContentMetaDatabase(StorageId storage_id); + + Result ActivateContentStorage(StorageId storage_id); + Result InactivateContentStorage(StorageId storage_id); + + Result ActivateContentMetaDatabase(StorageId storage_id); + Result InactivateContentMetaDatabase(StorageId storage_id); + + Result InvalidateRightsIdCache(); + + /* Deprecated API. */ + Result CloseContentStorageForcibly(StorageId storage_id); + Result CloseContentMetaDatabaseForcibly(StorageId storage_id); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp new file mode 100644 index 000000000..b3c9e3e20 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 { + + class ContentMetaDatabase { + NON_COPYABLE(ContentMetaDatabase); + public: + struct ListCount { + u32 written; + u32 total; + }; + private: + std::shared_ptr interface; + public: + ContentMetaDatabase() { /* ... */ } + explicit ContentMetaDatabase(std::shared_ptr intf) : interface(std::move(intf)) { /* ... */ } + + ContentMetaDatabase(ContentMetaDatabase &&rhs) { + this->interface = std::move(rhs.interface); + } + + ContentMetaDatabase &operator=(ContentMetaDatabase &&rhs) { + ContentMetaDatabase(std::move(rhs)).Swap(*this); + return *this; + } + + void Swap(ContentMetaDatabase &rhs) { + std::swap(this->interface, rhs.interface); + } + public: + Result Set(const ContentMetaKey &key, const void *buf, size_t size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Set(key, sf::InBuffer(buf, size)); + } + + Result Get(size_t *out_size, void *dst, size_t dst_size, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + u64 size; + R_TRY(this->interface->Get(std::addressof(size), key, sf::OutBuffer(dst, dst_size))); + + *out_size = size; + return ResultSuccess(); + } + + /* TODO: Proper ProgramId vs DataId vs ApplicationId for Get */ + #define AMS_NCM_DEFINE_GETTERS(Kind) \ + Result Get##Kind(ContentId *out, ProgramId id, u32 version) { \ + return this->interface->GetContentIdByType(out, ContentMetaKey::MakeUnknownType(id, version), ContentType::Kind); \ + } \ + \ + Result GetLatest##Kind(ContentId *out, ProgramId id) { \ + ContentMetaKey latest_key; \ + R_TRY(this->interface->GetLatestContentMetaKey(std::addressof(latest_key), id)); \ + return this->interface->GetContentIdByType(out, latest_key, ContentType::Kind); \ + } + + AMS_NCM_DEFINE_GETTERS(Program) + AMS_NCM_DEFINE_GETTERS(Data) + AMS_NCM_DEFINE_GETTERS(Control) + AMS_NCM_DEFINE_GETTERS(HtmlDocument) + AMS_NCM_DEFINE_GETTERS(LegalInformation) + + #undef AMS_NCM_DEFINE_GETTERS + + /* TODO: Remove(SystemProgramId) Remove(SystemDataId) Remove(ProgramId) */ + + Result Remove(const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Remove(key); + } + + Result GetContentIdByType(ContentId *out_content_id, const ContentMetaKey &key, ContentType type) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetContentIdByType(out_content_id, key, type); + } + + Result GetContentIdByTypeAndIdOffset(ContentId *out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetContentIdByTypeAndIdOffset(out_content_id, key, type, id_offset); + } + + ListCount ListApplication(ApplicationContentMetaKey *dst, size_t dst_size) { + ListCount lc = {}; + R_ABORT_UNLESS(this->interface->ListApplication(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray(dst, dst_size), ContentMetaType::Unknown)); + return lc; + } + + ListCount ListContentMeta(ContentMetaKey *dst, size_t dst_size, ContentMetaType type, ProgramId app_id, ProgramId min, ProgramId max, ContentInstallType install_type) { + ListCount lc = {}; + R_ABORT_UNLESS(this->interface->List(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray(dst, dst_size), type, app_id, min, max, install_type)); + return lc; + } + + Result GetLatest(ContentMetaKey *out_key, ProgramId id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetLatestContentMetaKey(out_key, id); + } + + Result ListContentInfo(u32 *out_count, ContentInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->ListContentInfo(out_count, sf::OutArray(dst, dst_size), key, offset); + } + + Result ListContentMetaInfo(u32 *out_count, ContentMetaInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->ListContentMetaInfo(out_count, sf::OutArray(dst, dst_size), key, offset); + } + + Result Has(bool *out, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Has(out, key); + } + + Result HasAll(bool *out, const ContentMetaKey *keys, size_t num_keys) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->HasAll(out, sf::InArray(keys, num_keys)); + } + + Result HasContent(bool *out, const ContentMetaKey &key, const ContentId &content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->HasContent(out, key, content_id); + } + + Result GetSize(size_t *out_size, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + u64 size; + R_TRY(this->interface->GetSize(std::addressof(size), key)); + + *out_size = size; + return ResultSuccess(); + } + + Result GetRequiredSystemVersion(u32 *out_version, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetRequiredSystemVersion(out_version, key); + } + + Result GetPatchId(ProgramId *out_patch_id, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetPatchId(out_patch_id, key); + } + + Result DisableForcibly() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->DisableForcibly(); + } + + Result LookupOrphanContent(bool *out_orphaned, ContentId *content_list, size_t count) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->LookupOrphanContent(sf::OutArray(out_orphaned, count), sf::InArray(content_list, count)); + } + + Result Commit() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Commit(); + } + + Result GetAttributes(ContentMetaAttribute *out_attributes, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetAttributes(out_attributes, key); + } + + Result GetRequiredApplicationVersion(u32 *out_version, const ContentMetaKey &key) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetRequiredApplicationVersion(out_version, key); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp new file mode 100644 index 000000000..15821f6f2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 { + + class ContentStorage { + NON_COPYABLE(ContentStorage); + private: + std::shared_ptr interface; + public: + ContentStorage() { /* ... */ } + explicit ContentStorage(std::shared_ptr intf) : interface(std::move(intf)) { /* ... */ } + + ContentStorage(ContentStorage &&rhs) { + this->interface = std::move(rhs.interface); + } + + ContentStorage &operator=(ContentStorage &&rhs) { + ContentStorage(std::move(rhs)).Swap(*this); + return *this; + } + + void Swap(ContentStorage &rhs) { + std::swap(this->interface, rhs.interface); + } + public: + PlaceHolderId GeneratePlaceHolderId() { + AMS_ASSERT(this->interface != nullptr); + + PlaceHolderId id; + R_ABORT_UNLESS(this->interface->GeneratePlaceHolderId(std::addressof(id))); + return id; + } + + Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->CreatePlaceHolder(placeholder_id, content_id, size); + } + + Result DeletePlaceHolder(PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->DeletePlaceHolder(placeholder_id); + } + + Result HasPlaceHolder(bool *out, PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->HasPlaceHolder(out, placeholder_id); + } + + Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, const void *buf, size_t size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->WritePlaceHolder(placeholder_id, offset, sf::InBuffer(buf, size)); + } + + Result Register(PlaceHolderId placeholder_id, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Register(placeholder_id, content_id); + } + + Result Delete(ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Delete(content_id); + } + + Result Has(bool *out, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->Has(out, content_id); + } + + void GetPath(Path *out, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + R_ABORT_UNLESS(this->interface->GetPath(out, content_id)); + } + + void GetPlaceHolderPath(Path *out, PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + R_ABORT_UNLESS(this->interface->GetPlaceHolderPath(out, placeholder_id)); + } + + Result CleanupAllPlaceHolder() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->CleanupAllPlaceHolder(); + } + + Result ListPlaceHolder(u32 *out_count, PlaceHolderId *out_list, size_t out_list_size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->ListPlaceHolder(out_count, sf::OutArray(out_list, out_list_size)); + } + + Result GetContentCount(u32 *out_count) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetContentCount(out_count); + } + + Result ListContentId(u32 *out_count, ContentId *out_list, size_t out_list_size, u32 offset) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->ListContentId(out_count, sf::OutArray(out_list, out_list_size), offset); + } + + Result GetSize(u64 *out_size, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetSizeFromContentId(out_size, content_id); + } + + Result GetSize(u64 *out_size, PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetSizeFromPlaceHolderId(out_size, placeholder_id); + } + + Result DisableForcibly() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->DisableForcibly(); + } + + Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->RevertToPlaceHolder(placeholder_id, old_content_id, new_content_id); + } + + Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->SetPlaceHolderSize(placeholder_id, size); + } + + Result ReadContentIdFile(void *dst, size_t size, ContentId content_id, u64 offset) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->ReadContentIdFile(sf::OutBuffer(dst, size), content_id, offset); + } + + Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300); + return this->interface->GetRightsIdFromPlaceHolderIdDeprecated(out_rights_id, placeholder_id); + } + + Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) { + AMS_ASSERT(this->interface != nullptr); + AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300); + return this->interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id); + } + + Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300); + return this->interface->GetRightsIdFromContentIdDeprecated(out_rights_id, content_id); + } + + Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) { + AMS_ASSERT(this->interface != nullptr); + AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300); + return this->interface->GetRightsIdFromContentId(out_rights_id, content_id); + } + + Result WriteContentForDebug(ContentId content_id, u64 offset, const void *buf, size_t size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->WriteContentForDebug(content_id, offset, sf::InBuffer(buf, size)); + } + + Result GetFreeSpaceSize(u64 *out_size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetFreeSpaceSize(out_size); + } + + Result GetTotalSpaceSize(u64 *out_size) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetTotalSpaceSize(out_size); + } + + Result FlushPlaceHolder() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->FlushPlaceHolder(); + } + + Result RepairInvalidFileAttribute() { + AMS_ASSERT(this->interface != nullptr); + return this->interface->RepairInvalidFileAttribute(); + } + + Result GetRightsIdFromPlaceHolderIdWithCache(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) { + AMS_ASSERT(this->interface != nullptr); + return this->interface->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id); + } + }; + +} diff --git a/stratosphere/ncm/source/ncm_content_manager_service.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp similarity index 67% rename from stratosphere/ncm/source/ncm_content_manager_service.hpp rename to libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp index f855b8259..43071f864 100644 --- a/stratosphere/ncm/source/ncm_content_manager_service.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp @@ -15,12 +15,12 @@ */ #pragma once -#include -#include +#include +#include namespace ams::ncm { - class ContentManagerService final : public sf::IServiceObject { + class IContentManager : public sf::IServiceObject { protected: enum class CommandId { CreateContentStorage = 0, @@ -39,20 +39,20 @@ namespace ams::ncm { InvalidateRightsIdCache = 13, }; public: - Result CreateContentStorage(StorageId storage_id); - Result CreateContentMetaDatabase(StorageId storage_id); - Result VerifyContentStorage(StorageId storage_id); - Result VerifyContentMetaDatabase(StorageId storage_id); - Result OpenContentStorage(sf::Out> out, StorageId storage_id); - Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id); - Result CloseContentStorageForcibly(StorageId storage_id); - Result CloseContentMetaDatabaseForcibly(StorageId storage_id); - Result CleanupContentMetaDatabase(StorageId storage_id); - Result ActivateContentStorage(StorageId storage_id); - Result InactivateContentStorage(StorageId storage_id); - Result ActivateContentMetaDatabase(StorageId storage_id); - Result InactivateContentMetaDatabase(StorageId storage_id); - Result InvalidateRightsIdCache(); + virtual Result CreateContentStorage(StorageId storage_id) = 0; + virtual Result CreateContentMetaDatabase(StorageId storage_id) = 0; + virtual Result VerifyContentStorage(StorageId storage_id) = 0; + virtual Result VerifyContentMetaDatabase(StorageId storage_id) = 0; + virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) = 0; + virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) = 0; + virtual Result CloseContentStorageForcibly(StorageId storage_id) = 0; + virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) = 0; + virtual Result CleanupContentMetaDatabase(StorageId storage_id) = 0; + virtual Result ActivateContentStorage(StorageId storage_id) = 0; + virtual Result InactivateContentStorage(StorageId storage_id) = 0; + virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0; + virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0; + virtual Result InvalidateRightsIdCache() = 0; public: DEFINE_SERVICE_DISPATCH_TABLE { MAKE_SERVICE_COMMAND_META(CreateContentStorage), diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp index f09c7a244..fee22c2fc 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp @@ -64,7 +64,7 @@ namespace ams::ncm { virtual Result DisableForcibly() = 0; virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) = 0; virtual Result Commit() = 0; - virtual Result HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) = 0; + virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) = 0; virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) = 0; virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) = 0; virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) = 0; diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp index 29fb5dc4b..19896cb05 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include @@ -68,8 +69,8 @@ namespace ams::ncm { virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) = 0; virtual Result Delete(ContentId content_id) = 0; virtual Result Has(sf::Out out, ContentId content_id) = 0; - virtual Result GetPath(sf::Out out, ContentId content_id) = 0; - virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) = 0; + virtual Result GetPath(sf::Out out, ContentId content_id) = 0; + virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) = 0; virtual Result CleanupAllPlaceHolder() = 0; virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) = 0; virtual Result GetContentCount(sf::Out out_count) = 0; diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp new file mode 100644 index 000000000..a0d1cd1fb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 +#include +#include + +namespace ams::ncm { + + struct alignas(4) Path : ams::sf::LargeData { + char str[fs::EntryNameLengthMax]; + + static constexpr Path Encode(const char *p) { + Path path = {}; + /* Copy C string to path, terminating when a null byte is found. */ + for (size_t i = 0; i < sizeof(path) - 1; i++) { + path.str[i] = p[i]; + if (p[i] == '\x00') { + break; + } + } + return path; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp index feb560361..7927e8561 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp @@ -621,6 +621,10 @@ namespace ams::ncm { return !(*this == other); } + static constexpr ContentMetaKey MakeUnknownType(ProgramId program_id, u32 version) { + return { .id = program_id, .version = version, .type = ContentMetaType::Unknown }; + } + static constexpr ContentMetaKey Make(ProgramId program_id, u32 version, ContentMetaType type) { return { .id = program_id, .version = version, .type = type }; } diff --git a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp index 1f347ca40..3ceb664d8 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp @@ -86,11 +86,13 @@ namespace ams::sf { cmif::ServiceObjectHolder *srv; cmif::DomainObjectId *object_id; public: + Out(cmif::ServiceObjectHolder *s) : srv(s), object_id(nullptr) { /* ... */ } Out(cmif::ServiceObjectHolder *s, cmif::DomainObjectId *o) : srv(s), object_id(o) { /* ... */ } void SetValue(std::shared_ptr &&s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) { *this->srv = cmif::ServiceObjectHolder(std::move(s)); if (new_object_id != cmif::InvalidDomainObjectId) { + AMS_ABORT_UNLESS(object_id != nullptr); *this->object_id = new_object_id; } } diff --git a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp index 79d939945..66299f35d 100644 --- a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp @@ -16,14 +16,6 @@ #include #include "lr_add_on_content_location_resolver_impl.hpp" -/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */ -namespace ams::ncm::impl { - - Result OpenContentMetaDatabase(std::shared_ptr *, ncm::StorageId); - Result OpenContentStorage(std::shared_ptr *, ncm::StorageId); - -} - namespace ams::lr { Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out out, ncm::ProgramId id) { @@ -32,19 +24,20 @@ namespace ams::lr { R_UNLESS(this->registered_storages.Find(&storage_id, id), lr::ResultAddOnContentNotFound()); /* Obtain a Content Meta Database for the storage id. */ - std::shared_ptr content_meta_database; - R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, storage_id)); + ncm::ContentMetaDatabase content_meta_database; + R_TRY(ncm::OpenContentMetaDatabase(&content_meta_database, storage_id)); /* Find the latest data content id for the given program id. */ ncm::ContentId data_content_id; - R_TRY(content_meta_database->GetLatestData(&data_content_id, id)); + R_TRY(content_meta_database.GetLatestData(&data_content_id, id)); /* Obtain a Content Storage for the storage id. */ - std::shared_ptr content_storage; - R_TRY(ncm::impl::OpenContentStorage(&content_storage, storage_id)); + ncm::ContentStorage content_storage; + R_TRY(ncm::OpenContentStorage(&content_storage, storage_id)); /* Get the path of the data content. */ - R_ABORT_UNLESS(content_storage->GetPath(out.GetPointer(), data_content_id)); + static_assert(sizeof(lr::Path) == sizeof(ncm::Path)); + content_storage.GetPath(reinterpret_cast(out.GetPointer()), data_content_id); return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp index 9398ff327..64ca4e920 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp @@ -16,14 +16,6 @@ #include #include "lr_content_location_resolver_impl.hpp" -/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */ -namespace ams::ncm::impl { - - Result OpenContentMetaDatabase(std::shared_ptr *, ncm::StorageId); - Result OpenContentStorage(std::shared_ptr *, ncm::StorageId); - -} - namespace ams::lr { ContentLocationResolverImpl::~ContentLocationResolverImpl() { @@ -32,7 +24,8 @@ namespace ams::lr { /* Helper function. */ void ContentLocationResolverImpl::GetContentStoragePath(Path *out, ncm::ContentId content_id) { - R_ABORT_UNLESS(this->content_storage->GetPath(out, content_id)); + static_assert(sizeof(lr::Path) == sizeof(ncm::Path)); + this->content_storage.GetPath(reinterpret_cast(out), content_id); } Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out out, ncm::ProgramId id) { @@ -41,7 +34,7 @@ namespace ams::lr { /* Find the latest program content for the program id. */ ncm::ContentId program_content_id; - R_TRY_CATCH(this->content_meta_database->GetLatestProgram(&program_content_id, id)) { + R_TRY_CATCH(this->content_meta_database.GetLatestProgram(&program_content_id, id)) { R_CONVERT(ncm::ResultContentMetaNotFound, lr::ResultProgramNotFound()) } R_END_TRY_CATCH; @@ -69,7 +62,7 @@ namespace ams::lr { Result ContentLocationResolverImpl::ResolveDataPath(sf::Out out, ncm::ProgramId id) { /* Find the latest data content for the program id. */ ncm::ContentId data_content_id; - R_TRY(this->content_meta_database->GetLatestData(&data_content_id, id)); + R_TRY(this->content_meta_database.GetLatestData(&data_content_id, id)); /* Obtain the content path. */ this->GetContentStoragePath(out.GetPointer(), data_content_id); @@ -114,14 +107,14 @@ namespace ams::lr { Result ContentLocationResolverImpl::Refresh() { /* Obtain Content Meta Database and Content Storage objects for this resolver's storage. */ - std::shared_ptr content_meta_database; - std::shared_ptr content_storage; - R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, this->storage_id)); - R_TRY(ncm::impl::OpenContentStorage(&content_storage, this->storage_id)); + ncm::ContentMetaDatabase meta_db; + ncm::ContentStorage storage; + R_TRY(ncm::OpenContentMetaDatabase(&meta_db, this->storage_id)); + R_TRY(ncm::OpenContentStorage(&storage, this->storage_id)); /* Store the acquired objects. */ - this->content_meta_database = std::move(content_meta_database); - this->content_storage = std::move(content_storage); + this->content_meta_database = std::move(meta_db); + this->content_storage = std::move(storage); /* Remove any existing redirections. */ this->ClearRedirections(); diff --git a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp index e25af0050..04a8c55a7 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp @@ -24,8 +24,8 @@ namespace ams::lr { ncm::StorageId storage_id; /* Objects for this storage type. */ - std::shared_ptr content_meta_database; - std::shared_ptr content_storage; + ncm::ContentMetaDatabase content_meta_database; + ncm::ContentStorage content_storage; public: ContentLocationResolverImpl(ncm::StorageId storage_id) : storage_id(storage_id) { /* ... */ } diff --git a/libraries/libstratosphere/source/ncm/ncm_api.cpp b/libraries/libstratosphere/source/ncm/ncm_api.cpp new file mode 100644 index 000000000..7dbed826c --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_api.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 . + */ +#include +#include "ncm_remote_content_manager_impl.hpp" + +namespace ams::ncm { + + namespace { + + std::shared_ptr g_content_manager; + + } + + void Initialize() { + AMS_ASSERT(g_content_manager == nullptr); + R_ABORT_UNLESS(ncmInitialize()); + g_content_manager = std::make_shared(); + } + + void Finalize() { + AMS_ASSERT(g_content_manager != nullptr); + g_content_manager.reset(); + ncmExit(); + } + + void InitializeWithObject(std::shared_ptr manager_object) { + AMS_ASSERT(g_content_manager == nullptr); + g_content_manager = manager_object; + AMS_ASSERT(g_content_manager != nullptr); + } + + /* Service API. */ + Result CreateContentStorage(StorageId storage_id) { + return g_content_manager->CreateContentStorage(storage_id); + } + + Result CreateContentMetaDatabase(StorageId storage_id) { + return g_content_manager->CreateContentMetaDatabase(storage_id); + } + + Result VerifyContentStorage(StorageId storage_id) { + return g_content_manager->VerifyContentStorage(storage_id); + } + + Result VerifyContentMetaDatabase(StorageId storage_id) { + return g_content_manager->VerifyContentMetaDatabase(storage_id); + } + + Result OpenContentStorage(ContentStorage *out, StorageId storage_id) { + sf::cmif::ServiceObjectHolder object_holder; + R_TRY(g_content_manager->OpenContentStorage(std::addressof(object_holder), storage_id)); + + *out = ContentStorage(object_holder.GetServiceObject()); + return ResultSuccess(); + } + + Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id) { + sf::cmif::ServiceObjectHolder object_holder; + R_TRY(g_content_manager->OpenContentMetaDatabase(std::addressof(object_holder), storage_id)); + + *out = ContentMetaDatabase(object_holder.GetServiceObject()); + return ResultSuccess(); + } + + Result CleanupContentMetaDatabase(StorageId storage_id) { + return g_content_manager->CleanupContentMetaDatabase(storage_id); + } + + Result ActivateContentStorage(StorageId storage_id) { + return g_content_manager->ActivateContentStorage(storage_id); + } + + Result InactivateContentStorage(StorageId storage_id) { + return g_content_manager->InactivateContentStorage(storage_id); + } + + Result ActivateContentMetaDatabase(StorageId storage_id) { + return g_content_manager->ActivateContentMetaDatabase(storage_id); + } + + Result InactivateContentMetaDatabase(StorageId storage_id) { + return g_content_manager->InactivateContentMetaDatabase(storage_id); + } + + Result InvalidateRightsIdCache() { + return g_content_manager->InvalidateRightsIdCache(); + } + + /* Deprecated API. */ + Result CloseContentStorageForcibly(StorageId storage_id) { + AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100); + return g_content_manager->CloseContentStorageForcibly(storage_id); + } + + Result CloseContentMetaDatabaseForcibly(StorageId storage_id) { + AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100); + return g_content_manager->CloseContentMetaDatabaseForcibly(storage_id); + } +} diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp new file mode 100644 index 000000000..2baf990fd --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 "ncm_remote_content_storage_impl.hpp" +#include "ncm_remote_content_meta_database_impl.hpp" + +namespace ams::ncm { + + class RemoteContentManagerImpl final : public IContentManager { + public: + RemoteContentManagerImpl() { /* ... */ } + + ~RemoteContentManagerImpl() { /* ... */ } + public: + virtual Result CreateContentStorage(StorageId storage_id) override { + return ::ncmCreateContentStorage(static_cast(storage_id)); + } + + virtual Result CreateContentMetaDatabase(StorageId storage_id) override { + return ::ncmCreateContentMetaDatabase(static_cast(storage_id)); + } + + virtual Result VerifyContentStorage(StorageId storage_id) override { + return ::ncmVerifyContentStorage(static_cast(storage_id)); + } + + virtual Result VerifyContentMetaDatabase(StorageId storage_id) override { + return ::ncmVerifyContentMetaDatabase(static_cast(storage_id)); + } + + virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) override { + NcmContentStorage cs; + R_TRY(::ncmOpenContentStorage(std::addressof(cs), static_cast(storage_id))); + + out.SetValue(std::make_shared(cs)); + return ResultSuccess(); + } + + virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) override { + NcmContentMetaDatabase db; + R_TRY(::ncmOpenContentMetaDatabase(std::addressof(db), static_cast(storage_id))); + + out.SetValue(std::make_shared(db)); + return ResultSuccess(); + } + + virtual Result CloseContentStorageForcibly(StorageId storage_id) override { + return ::ncmCloseContentStorageForcibly(static_cast(storage_id)); + } + + virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override { + return ::ncmCloseContentMetaDatabaseForcibly(static_cast(storage_id)); + } + + virtual Result CleanupContentMetaDatabase(StorageId storage_id) override { + return ::ncmCleanupContentMetaDatabase(static_cast(storage_id)); + } + + virtual Result ActivateContentStorage(StorageId storage_id) override { + return ::ncmActivateContentStorage(static_cast(storage_id)); + } + + virtual Result InactivateContentStorage(StorageId storage_id) override { + return ::ncmInactivateContentStorage(static_cast(storage_id)); + } + + virtual Result ActivateContentMetaDatabase(StorageId storage_id) override { + return ::ncmActivateContentMetaDatabase(static_cast(storage_id)); + } + + virtual Result InactivateContentMetaDatabase(StorageId storage_id) override { + return ::ncmInactivateContentMetaDatabase(static_cast(storage_id)); + } + + virtual Result InvalidateRightsIdCache() override { + return ::ncmInvalidateRightsIdCache(); + } + }; + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp new file mode 100644 index 000000000..ccbb0ada8 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 + +namespace ams::ncm { + + class RemoteContentMetaDatabaseImpl final : public IContentMetaDatabase { + private: + ::NcmContentMetaDatabase srv; + public: + RemoteContentMetaDatabaseImpl(::NcmContentMetaDatabase &db) : srv(db) { /* ... */ } + + ~RemoteContentMetaDatabaseImpl() { ::ncmContentMetaDatabaseClose(std::addressof(srv)); } + private: + ALWAYS_INLINE ::NcmContentMetaKey *Convert(ContentMetaKey *k) { + static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey)); + return reinterpret_cast<::NcmContentMetaKey *>(k); + } + ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey *k) { + static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey)); + return reinterpret_cast(k); + } + + ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey &k) { + static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey)); + return reinterpret_cast(std::addressof(k)); + } + + ALWAYS_INLINE ::NcmApplicationContentMetaKey *Convert(ApplicationContentMetaKey *k) { + static_assert(sizeof(ApplicationContentMetaKey) == sizeof(::NcmApplicationContentMetaKey)); + return reinterpret_cast<::NcmApplicationContentMetaKey *>(k); + } + + ALWAYS_INLINE ::NcmContentInfo *Convert(ContentInfo *c) { + static_assert(sizeof(ContentInfo) == sizeof(::NcmContentInfo)); + return reinterpret_cast<::NcmContentInfo *>(c); + } + + ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast<::NcmContentId *>(c); + } + + ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast<::NcmContentId *>(std::addressof(c)); + } + + ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId *c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast(c); + } + + + ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId &c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast(std::addressof(c)); + } + public: + virtual Result Set(const ContentMetaKey &key, sf::InBuffer value) override { + return ncmContentMetaDatabaseSet(std::addressof(this->srv), Convert(key), value.GetPointer(), value.GetSize()); + } + + virtual Result Get(sf::Out out_size, const ContentMetaKey &key, sf::OutBuffer out_value) override { + return ncmContentMetaDatabaseGet(std::addressof(this->srv), Convert(key), out_size.GetPointer(), out_value.GetPointer(), out_value.GetSize()); + } + + virtual Result Remove(const ContentMetaKey &key) override { + return ncmContentMetaDatabaseRemove(std::addressof(this->srv), Convert(key)); + } + + virtual Result GetContentIdByType(sf::Out out_content_id, const ContentMetaKey &key, ContentType type) override { + return ncmContentMetaDatabaseGetContentIdByType(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type)); + } + + virtual Result ListContentInfo(sf::Out out_entries_written, const sf::OutArray &out_info, const ContentMetaKey &key, u32 start_index) override { + return ncmContentMetaDatabaseListContentInfo(std::addressof(this->srv), reinterpret_cast(out_entries_written.GetPointer()), Convert(out_info.GetPointer()), out_info.GetSize(), Convert(key), start_index); + } + + virtual Result List(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out, ContentMetaType meta_type, ProgramId application_program_id, ProgramId program_id_min, ProgramId program_id_max, ContentInstallType install_type) override { + return ncmContentMetaDatabaseList(std::addressof(this->srv), reinterpret_cast(out_entries_total.GetPointer()), reinterpret_cast(out_entries_written.GetPointer()), Convert(out.GetPointer()), out.GetSize(), static_cast<::NcmContentMetaType>(meta_type), static_cast(application_program_id), static_cast(program_id_min), static_cast(program_id_max), static_cast<::NcmContentInstallType>(install_type)); + } + + virtual Result GetLatestContentMetaKey(sf::Out out_key, ProgramId id) override { + return ncmContentMetaDatabaseGetLatestContentMetaKey(std::addressof(this->srv), Convert(out_key.GetPointer()), static_cast(id)); + } + + virtual Result ListApplication(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out_keys, ContentMetaType meta_type) override { + return ncmContentMetaDatabaseListApplication(std::addressof(this->srv), reinterpret_cast(out_entries_total.GetPointer()), reinterpret_cast(out_entries_written.GetPointer()), Convert(out_keys.GetPointer()), out_keys.GetSize(), static_cast<::NcmContentMetaType>(meta_type)); + } + + virtual Result Has(sf::Out out, const ContentMetaKey &key) override { + return ncmContentMetaDatabaseHas(std::addressof(this->srv), out.GetPointer(), Convert(key)); + } + + virtual Result HasAll(sf::Out out, const sf::InArray &keys) override { + return ncmContentMetaDatabaseHasAll(std::addressof(this->srv), out.GetPointer(), Convert(keys.GetPointer()), keys.GetSize()); + } + + virtual Result GetSize(sf::Out out_size, const ContentMetaKey &key) override { + return ncmContentMetaDatabaseGetSize(std::addressof(this->srv), out_size.GetPointer(), Convert(key)); + } + + virtual Result GetRequiredSystemVersion(sf::Out out_version, const ContentMetaKey &key) override { + return ncmContentMetaDatabaseGetRequiredSystemVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key)); + } + + virtual Result GetPatchId(sf::Out out_patch_id, const ContentMetaKey &key) override { + return ncmContentMetaDatabaseGetPatchId(std::addressof(this->srv), reinterpret_cast(out_patch_id.GetPointer()), Convert(key)); + } + + virtual Result DisableForcibly() override { + return ncmContentMetaDatabaseDisableForcibly(std::addressof(this->srv)); + } + + virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) override { + return ncmContentMetaDatabaseLookupOrphanContent(std::addressof(this->srv), out_orphaned.GetPointer(), Convert(content_ids.GetPointer()), std::min(out_orphaned.GetSize(), content_ids.GetSize())); + } + + virtual Result Commit() override { + return ncmContentMetaDatabaseCommit(std::addressof(this->srv)); + } + + virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) override { + return ncmContentMetaDatabaseHasContent(std::addressof(this->srv), out.GetPointer(), Convert(key), Convert(content_id)); + } + + virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) override { + return ncmContentMetaDatabaseListContentMetaInfo(std::addressof(this->srv), reinterpret_cast(out_entries_written.GetPointer()), out_meta_info.GetPointer(), out_meta_info.GetSize(), Convert(key), start_index); + } + + virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) override { + static_assert(sizeof(ContentMetaAttribute) == sizeof(u8)); + return ncmContentMetaDatabaseGetAttributes(std::addressof(this->srv), Convert(key), reinterpret_cast(out_attributes.GetPointer())); + } + + virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) override { + return ncmContentMetaDatabaseGetRequiredApplicationVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key)); + } + + virtual Result GetContentIdByTypeAndIdOffset(sf::Out out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) override { + return ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type), id_offset); + } + + }; + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp new file mode 100644 index 000000000..f11e1b4d9 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 + +namespace ams::ncm { + + class RemoteContentStorageImpl final : public IContentStorage { + private: + ::NcmContentStorage srv; + public: + RemoteContentStorageImpl(::NcmContentStorage &cs) : srv(cs) { /* ... */ } + + ~RemoteContentStorageImpl() { ::ncmContentStorageClose(std::addressof(srv)); } + private: + ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId *p) { + static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId)); + return reinterpret_cast<::NcmPlaceHolderId *>(p); + } + + ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId &p) { + static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId)); + return reinterpret_cast<::NcmPlaceHolderId *>(std::addressof(p)); + } + + ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast<::NcmContentId *>(c); + } + + ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) { + static_assert(sizeof(ContentId) == sizeof(::NcmContentId)); + return reinterpret_cast<::NcmContentId *>(std::addressof(c)); + } + public: + virtual Result GeneratePlaceHolderId(sf::Out out) override { + return ncmContentStorageGeneratePlaceHolderId(std::addressof(this->srv), Convert(out.GetPointer())); + } + + virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) override { + static_assert(alignof(ContentId) < alignof(PlaceHolderId)); + return ncmContentStorageCreatePlaceHolder(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id), static_cast(size)); + } + + virtual Result DeletePlaceHolder(PlaceHolderId placeholder_id) override { + return ncmContentStorageDeletePlaceHolder(std::addressof(this->srv), Convert(placeholder_id)); + } + + virtual Result HasPlaceHolder(sf::Out out, PlaceHolderId placeholder_id) override { + return ncmContentStorageHasPlaceHolder(std::addressof(this->srv), out.GetPointer(), Convert(placeholder_id)); + } + + virtual Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) override { + return ncmContentStorageWritePlaceHolder(std::addressof(this->srv), Convert(placeholder_id), offset, data.GetPointer(), data.GetSize()); + } + + virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override { + static_assert(alignof(ContentId) < alignof(PlaceHolderId)); + return ncmContentStorageRegister(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id)); + } + + virtual Result Delete(ContentId content_id) override { + return ncmContentStorageDelete(std::addressof(this->srv), Convert(content_id)); + } + + virtual Result Has(sf::Out out, ContentId content_id) override { + return ncmContentStorageHas(std::addressof(this->srv), out.GetPointer(), Convert(content_id)); + } + + virtual Result GetPath(sf::Out out, ContentId content_id) override { + return ncmContentStorageGetPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(content_id)); + } + + virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override { + return ncmContentStorageGetPlaceHolderPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(placeholder_id)); + } + + virtual Result CleanupAllPlaceHolder() override { + return ncmContentStorageCleanupAllPlaceHolder(std::addressof(this->srv)); + } + + virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override { + return ncmContentStorageListPlaceHolder(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast(out_count.GetPointer())); + } + + virtual Result GetContentCount(sf::Out out_count) override { + return ncmContentStorageGetContentCount(std::addressof(this->srv), reinterpret_cast(out_count.GetPointer())); + } + + virtual Result ListContentId(sf::Out out_count, const sf::OutArray &out_buf, u32 offset) override { + return ncmContentStorageListContentId(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast(out_count.GetPointer()), static_cast(offset)); + } + + virtual Result GetSizeFromContentId(sf::Out out_size, ContentId content_id) override { + return ncmContentStorageGetSizeFromContentId(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()), Convert(content_id)); + } + + virtual Result DisableForcibly() override { + return ncmContentStorageDisableForcibly(std::addressof(this->srv)); + } + + virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override { + return ncmContentStorageRevertToPlaceHolder(std::addressof(this->srv), Convert(placeholder_id), Convert(old_content_id), Convert(new_content_id)); + } + + virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override { + return ncmContentStorageSetPlaceHolderSize(std::addressof(this->srv), Convert(placeholder_id), static_cast(size)); + } + + virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override { + return ncmContentStorageReadContentIdFile(std::addressof(this->srv), buf.GetPointer(), buf.GetSize(), Convert(content_id), static_cast(offset)); + } + + virtual Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out out_rights_id, PlaceHolderId placeholder_id) override { + ::NcmRightsId rights_id; + R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id))); + + static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id)); + std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer())); + return ResultSuccess(); + } + + virtual Result GetRightsIdFromPlaceHolderId(sf::Out out_rights_id, PlaceHolderId placeholder_id) override { + ::NcmRightsId rights_id; + R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id))); + + static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id)); + std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer())); + return ResultSuccess(); + } + + virtual Result GetRightsIdFromContentIdDeprecated(sf::Out out_rights_id, ContentId content_id) override { + ::NcmRightsId rights_id; + R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id))); + + static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id)); + std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer())); + return ResultSuccess(); + } + + virtual Result GetRightsIdFromContentId(sf::Out out_rights_id, ContentId content_id) override { + ::NcmRightsId rights_id; + R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id))); + + static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id)); + std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer())); + return ResultSuccess(); + } + + virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override { + return ncmContentStorageWriteContentForDebug(std::addressof(this->srv), Convert(content_id), static_cast(offset), data.GetPointer(), data.GetSize()); + } + + virtual Result GetFreeSpaceSize(sf::Out out_size) override { + return ncmContentStorageGetFreeSpaceSize(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer())); + } + + virtual Result GetTotalSpaceSize(sf::Out out_size) override { + return ncmContentStorageGetTotalSpaceSize(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer())); + } + + virtual Result FlushPlaceHolder() override { + return ncmContentStorageFlushPlaceHolder(std::addressof(this->srv)); + } + + virtual Result GetSizeFromPlaceHolderId(sf::Out out_size, PlaceHolderId placeholder_id) override { + return ncmContentStorageGetSizeFromPlaceHolderId(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()), Convert(placeholder_id)); + } + + virtual Result RepairInvalidFileAttribute() override { + return ncmContentStorageRepairInvalidFileAttribute(std::addressof(this->srv)); + } + + virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) override { + static_assert(sizeof(::NcmRightsId) == sizeof(ncm::RightsId)); + ::NcmRightsId *out = reinterpret_cast<::NcmRightsId *>(out_rights_id.GetPointer()); + return ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(std::addressof(this->srv), out, Convert(placeholder_id), Convert(cache_content_id)); + } + }; + +} diff --git a/stratosphere/ncm/source/impl/ncm_content_manager.cpp b/stratosphere/ncm/source/impl/ncm_content_manager.cpp index 342ef813e..fce9ad590 100644 --- a/stratosphere/ncm/source/impl/ncm_content_manager.cpp +++ b/stratosphere/ncm/source/impl/ncm_content_manager.cpp @@ -72,7 +72,7 @@ namespace ams::ncm::impl { constexpr u64 BuiltInSystemSaveDataSize = 0x6c000; constexpr u64 BuiltInSystemSaveDataJournalSize = 0x6c000; constexpr u32 BuiltInSystemSaveDataFlags = FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment; - + constexpr SaveDataMeta BuiltInSystemSaveDataMeta = { .id = BuiltInSystemSaveDataId, .size = BuiltInSystemSaveDataSize, @@ -119,7 +119,7 @@ namespace ams::ncm::impl { std::optional> kvs; u32 max_content_metas; - inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}), + inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}), content_meta_database(nullptr), kvs(std::nullopt), max_content_metas(0) { mount_point[0] = '\0'; meta_path[0] = '\0'; @@ -268,17 +268,17 @@ namespace ams::ncm::impl { /* First, setup the BuiltInSystem storage entry. */ g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInSystem, FsContentStorageId_System); - if (R_FAILED(VerifyContentStorage(StorageId::BuiltInSystem))) { - R_TRY(CreateContentStorage(StorageId::BuiltInSystem)); + if (R_FAILED(impl::VerifyContentStorage(StorageId::BuiltInSystem))) { + R_TRY(impl::CreateContentStorage(StorageId::BuiltInSystem)); } - R_TRY(ActivateContentStorage(StorageId::BuiltInSystem)); + R_TRY(impl::ActivateContentStorage(StorageId::BuiltInSystem)); /* Next, the BuiltInSystem content meta entry. */ R_TRY(g_content_meta_entries[g_num_content_meta_entries++].Initialize(StorageId::BuiltInSystem, BuiltInSystemSaveDataMeta, MaxBuiltInSystemContentMetaCount)); - if (R_FAILED(VerifyContentMetaDatabase(StorageId::BuiltInSystem))) { - R_TRY(CreateContentMetaDatabase(StorageId::BuiltInSystem)); + if (R_FAILED(impl::VerifyContentMetaDatabase(StorageId::BuiltInSystem))) { + R_TRY(impl::CreateContentMetaDatabase(StorageId::BuiltInSystem)); /* TODO: N supports a number of unused modes here, we don't bother implementing them currently. */ } @@ -287,8 +287,8 @@ namespace ams::ncm::impl { if (hos::GetVersion() >= hos::Version_200 && R_SUCCEEDED(fs::GetSaveDataFlags(¤t_flags, BuiltInSystemSaveDataId)) && current_flags != (FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment)) { fs::SetSaveDataFlags(BuiltInSystemSaveDataId, FsSaveDataSpaceId_System, FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment); } - - R_TRY(ActivateContentMetaDatabase(StorageId::BuiltInSystem)); + + R_TRY(impl::ActivateContentMetaDatabase(StorageId::BuiltInSystem)); /* Now for BuiltInUser's content storage and content meta entries. */ g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInUser, FsContentStorageId_User); @@ -316,12 +316,12 @@ namespace ams::ncm::impl { for (size_t i = 0; i < MaxContentStorageEntries; i++) { ContentStorageRoot *entry = &g_content_storage_roots[i]; - InactivateContentStorage(entry->storage_id); + impl::InactivateContentStorage(entry->storage_id); } for (size_t i = 0; i < MaxContentMetaDatabaseEntries; i++) { ContentMetaDatabaseEntry *entry = &g_content_meta_entries[i]; - InactivateContentMetaDatabase(entry->storage_id); + impl::InactivateContentMetaDatabase(entry->storage_id); } } @@ -374,7 +374,7 @@ namespace ams::ncm::impl { ContentStorageRoot *root; R_TRY(GetUniqueContentStorageRoot(std::addressof(root), storage_id)); - + auto content_storage = root->content_storage; if (hos::GetVersion() >= hos::Version_200) { @@ -382,7 +382,7 @@ namespace ams::ncm::impl { } else { /* 1.0.0 activates content storages as soon as they are opened. */ if (!content_storage) { - R_TRY(ActivateContentStorage(storage_id)); + R_TRY(impl::ActivateContentStorage(storage_id)); content_storage = root->content_storage; } } @@ -518,7 +518,7 @@ namespace ams::ncm::impl { ContentMetaDatabaseEntry *entry; R_TRY(GetUniqueContentMetaDatabaseEntry(&entry, storage_id)); - + auto content_meta_db = entry->content_meta_database; if (hos::GetVersion() >= hos::Version_200) { @@ -526,7 +526,7 @@ namespace ams::ncm::impl { } else { /* 1.0.0 activates content meta databases as soon as they are opened. */ if (!content_meta_db) { - R_TRY(ActivateContentMetaDatabase(storage_id)); + R_TRY(impl::ActivateContentMetaDatabase(storage_id)); content_meta_db = entry->content_meta_database; } } @@ -541,7 +541,7 @@ namespace ams::ncm::impl { R_UNLESS(storage_id != StorageId::None, ncm::ResultUnknownStorage()); ContentMetaDatabaseEntry *entry; R_TRY(FindContentMetaDatabaseEntry(&entry, storage_id)); - + auto content_meta_db = entry->content_meta_database; if (content_meta_db) { diff --git a/stratosphere/ncm/source/ncm_content_manager_service.cpp b/stratosphere/ncm/source/ncm_content_manager_impl.cpp similarity index 63% rename from stratosphere/ncm/source/ncm_content_manager_service.cpp rename to stratosphere/ncm/source/ncm_content_manager_impl.cpp index 82e6aff44..1f9708df1 100644 --- a/stratosphere/ncm/source/ncm_content_manager_service.cpp +++ b/stratosphere/ncm/source/ncm_content_manager_impl.cpp @@ -14,70 +14,70 @@ * along with this program. If not, see . */ +#include "ncm_content_manager_impl.hpp" #include "impl/ncm_content_manager.hpp" -#include "ncm_content_manager_service.hpp" namespace ams::ncm { - Result ContentManagerService::CreateContentStorage(StorageId storage_id) { + Result ContentManagerImpl::CreateContentStorage(StorageId storage_id) { return impl::CreateContentStorage(storage_id); } - Result ContentManagerService::CreateContentMetaDatabase(StorageId storage_id) { + Result ContentManagerImpl::CreateContentMetaDatabase(StorageId storage_id) { return impl::CreateContentMetaDatabase(storage_id); } - Result ContentManagerService::VerifyContentStorage(StorageId storage_id) { + Result ContentManagerImpl::VerifyContentStorage(StorageId storage_id) { return impl::VerifyContentStorage(storage_id); } - Result ContentManagerService::VerifyContentMetaDatabase(StorageId storage_id) { + Result ContentManagerImpl::VerifyContentMetaDatabase(StorageId storage_id) { return impl::VerifyContentMetaDatabase(storage_id); } - Result ContentManagerService::OpenContentStorage(sf::Out> out, StorageId storage_id) { + Result ContentManagerImpl::OpenContentStorage(sf::Out> out, StorageId storage_id) { std::shared_ptr content_storage; R_TRY(impl::OpenContentStorage(&content_storage, storage_id)); out.SetValue(std::move(content_storage)); return ResultSuccess(); } - Result ContentManagerService::OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) { + Result ContentManagerImpl::OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) { std::shared_ptr content_meta_database; R_TRY(impl::OpenContentMetaDatabase(&content_meta_database, storage_id)); out.SetValue(std::move(content_meta_database)); return ResultSuccess(); } - Result ContentManagerService::CloseContentStorageForcibly(StorageId storage_id) { + Result ContentManagerImpl::CloseContentStorageForcibly(StorageId storage_id) { return impl::CloseContentStorageForcibly(storage_id); } - Result ContentManagerService::CloseContentMetaDatabaseForcibly(StorageId storage_id) { + Result ContentManagerImpl::CloseContentMetaDatabaseForcibly(StorageId storage_id) { return impl::CloseContentMetaDatabaseForcibly(storage_id); } - Result ContentManagerService::CleanupContentMetaDatabase(StorageId storage_id) { + Result ContentManagerImpl::CleanupContentMetaDatabase(StorageId storage_id) { return impl::CleanupContentMetaDatabase(storage_id); } - Result ContentManagerService::ActivateContentStorage(StorageId storage_id) { + Result ContentManagerImpl::ActivateContentStorage(StorageId storage_id) { return impl::ActivateContentStorage(storage_id); } - Result ContentManagerService::InactivateContentStorage(StorageId storage_id) { + Result ContentManagerImpl::InactivateContentStorage(StorageId storage_id) { return impl::InactivateContentStorage(storage_id); } - Result ContentManagerService::ActivateContentMetaDatabase(StorageId storage_id) { + Result ContentManagerImpl::ActivateContentMetaDatabase(StorageId storage_id) { return impl::ActivateContentMetaDatabase(storage_id); } - Result ContentManagerService::InactivateContentMetaDatabase(StorageId storage_id) { + Result ContentManagerImpl::InactivateContentMetaDatabase(StorageId storage_id) { return impl::InactivateContentMetaDatabase(storage_id); } - Result ContentManagerService::InvalidateRightsIdCache() { + Result ContentManagerImpl::InvalidateRightsIdCache() { return impl::InvalidateRightsIdCache(); } diff --git a/stratosphere/ncm/source/ncm_content_manager_impl.hpp b/stratosphere/ncm/source/ncm_content_manager_impl.hpp new file mode 100644 index 000000000..7cbef9c85 --- /dev/null +++ b/stratosphere/ncm/source/ncm_content_manager_impl.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2020 Adubbz, 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 + +namespace ams::ncm { + + class ContentManagerImpl final : public IContentManager { + public: + virtual Result CreateContentStorage(StorageId storage_id) override; + virtual Result CreateContentMetaDatabase(StorageId storage_id) override; + virtual Result VerifyContentStorage(StorageId storage_id) override; + virtual Result VerifyContentMetaDatabase(StorageId storage_id) override; + virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) override; + virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) override; + virtual Result CloseContentStorageForcibly(StorageId storage_id) override; + virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override; + virtual Result CleanupContentMetaDatabase(StorageId storage_id) override; + virtual Result ActivateContentStorage(StorageId storage_id) override; + virtual Result InactivateContentStorage(StorageId storage_id) override; + virtual Result ActivateContentMetaDatabase(StorageId storage_id) override; + virtual Result InactivateContentMetaDatabase(StorageId storage_id) override; + virtual Result InvalidateRightsIdCache() override; + }; + +} diff --git a/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp b/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp index 0612cafbe..3c8989980 100644 --- a/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp +++ b/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp @@ -297,7 +297,7 @@ namespace ams::ncm { return fsdevCommitDevice(this->mount_name); } - Result ContentMetaDatabaseImpl::HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) { + Result ContentMetaDatabaseImpl::HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) { const void *meta; size_t meta_size; R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key)); diff --git a/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp b/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp index e3eb9b884..f6c3499fe 100644 --- a/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp +++ b/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp @@ -45,7 +45,7 @@ namespace ams::ncm { virtual Result DisableForcibly() override; virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) override; virtual Result Commit() override; - virtual Result HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) override; + virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) override; virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) override; virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) override; virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) override; diff --git a/stratosphere/ncm/source/ncm_content_storage_impl.cpp b/stratosphere/ncm/source/ncm_content_storage_impl.cpp index b4b9fa39c..08d75840f 100644 --- a/stratosphere/ncm/source/ncm_content_storage_impl.cpp +++ b/stratosphere/ncm/source/ncm_content_storage_impl.cpp @@ -108,7 +108,7 @@ namespace ams::ncm { char placeholder_path[FS_MAX_PATH] = {0}; this->placeholder_accessor.MakePath(placeholder_path, placeholder_id); - + bool has = false; R_TRY(fs::HasFile(&has, placeholder_path)); out.SetValue(has); @@ -173,25 +173,25 @@ namespace ams::ncm { return ResultSuccess(); } - Result ContentStorageImpl::GetPath(sf::Out out, ContentId content_id) { + Result ContentStorageImpl::GetPath(sf::Out out, ContentId content_id) { R_TRY(this->EnsureEnabled()); char content_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0}; this->GetContentPath(content_path, content_id); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); - out.SetValue(lr::Path::Encode(common_path)); + out.SetValue(Path::Encode(common_path)); return ResultSuccess(); } - Result ContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) { + Result ContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) { R_TRY(this->EnsureEnabled()); char placeholder_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0}; this->placeholder_accessor.GetPath(placeholder_path, placeholder_id); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path)); - out.SetValue(lr::Path::Encode(common_path)); + out.SetValue(Path::Encode(common_path)); return ResultSuccess(); } @@ -202,7 +202,7 @@ namespace ams::ncm { this->placeholder_accessor.InvalidateAll(); this->placeholder_accessor.MakeRootPath(placeholder_root_path); - /* Nintendo uses CleanDirectoryRecursively which is 3.0.0+. + /* Nintendo uses CleanDirectoryRecursively which is 3.0.0+. We'll just delete the directory and recreate it to support all firmwares. */ R_TRY(fsdevDeleteDirectoryRecursively(placeholder_root_path)); R_UNLESS(mkdir(placeholder_root_path, S_IRWXU) != -1, fsdevGetLastResult()); @@ -220,15 +220,15 @@ namespace ams::ncm { R_TRY(fs::TraverseDirectory(placeholder_root_path, dir_depth, [&](bool *should_continue, bool *should_retry_dir_read, const char *current_path, struct dirent *dir_entry) -> Result { *should_continue = true; *should_retry_dir_read = false; - + if (dir_entry->d_type == DT_REG) { R_UNLESS(entry_count <= out_buf.GetSize(), ncm::ResultBufferInsufficient()); - + PlaceHolderId cur_entry_placeholder_id = {0}; R_TRY(GetPlaceHolderIdFromDirEntry(&cur_entry_placeholder_id, dir_entry)); out_buf[entry_count++] = cur_entry_placeholder_id; } - + return ResultSuccess(); })); @@ -329,7 +329,7 @@ namespace ams::ncm { Result ContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { R_TRY(this->EnsureEnabled()); - + char old_content_path[FS_MAX_PATH] = {0}; char new_content_path[FS_MAX_PATH] = {0}; char placeholder_path[FS_MAX_PATH] = {0}; @@ -401,7 +401,7 @@ namespace ams::ncm { Result ContentStorageImpl::GetRightsIdFromContentId(sf::Out out_rights_id, ContentId content_id) { R_TRY(this->EnsureEnabled()); - + if (this->rights_id_cache->Find(out_rights_id.GetPointer(), content_id)) { return ResultSuccess(); } @@ -437,7 +437,7 @@ namespace ams::ncm { FILE *f = nullptr; R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Write)); - + ON_SCOPE_EXIT { fclose(f); }; @@ -522,7 +522,7 @@ namespace ams::ncm { Result ContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) { R_TRY(this->EnsureEnabled()); - + if (this->rights_id_cache->Find(out_rights_id.GetPointer(), cache_content_id)) { return ResultSuccess(); } diff --git a/stratosphere/ncm/source/ncm_content_storage_impl.hpp b/stratosphere/ncm/source/ncm_content_storage_impl.hpp index 7ca658c34..c273fdf7a 100644 --- a/stratosphere/ncm/source/ncm_content_storage_impl.hpp +++ b/stratosphere/ncm/source/ncm_content_storage_impl.hpp @@ -60,8 +60,8 @@ namespace ams::ncm { virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override; virtual Result Delete(ContentId content_id) override; virtual Result Has(sf::Out out, ContentId content_id) override; - virtual Result GetPath(sf::Out out, ContentId content_id) override; - virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override; + virtual Result GetPath(sf::Out out, ContentId content_id) override; + virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override; virtual Result CleanupAllPlaceHolder() override; virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override; virtual Result GetContentCount(sf::Out out_count) override; diff --git a/stratosphere/ncm/source/ncm_main.cpp b/stratosphere/ncm/source/ncm_main.cpp index 237726111..4b5b66289 100644 --- a/stratosphere/ncm/source/ncm_main.cpp +++ b/stratosphere/ncm/source/ncm_main.cpp @@ -18,7 +18,7 @@ #include #include "impl/ncm_content_manager.hpp" -#include "ncm_content_manager_service.hpp" +#include "ncm_content_manager_impl.hpp" extern "C" { extern u32 __start__; @@ -100,6 +100,39 @@ namespace { constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm"); + class ContentManagerServerManager : public sf::hipc::ServerManager { + private: + static constexpr size_t ThreadStackSize = 0x4000; + static constexpr int ThreadPriority = 0x15; + + using ServiceType = ncm::ContentManagerImpl; + private: + os::StaticThread thread; + std::shared_ptr ncm_manager; + private: + static void ThreadFunction(void *_this) { + reinterpret_cast(_this)->LoopProcess(); + } + public: + ContentManagerServerManager(ServiceType *m) + : thread(ThreadFunction, this, ThreadPriority), ncm_manager(sf::ServiceObjectTraits::SharedPointerHelper::GetEmptyDeleteSharedPointer(m)) + { + /* ... */ + } + + ams::Result Initialize() { + return this->RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions, this->ncm_manager); + } + + ams::Result StartThreads() { + return this->thread.Start(); + } + + void Wait() { + this->thread.Join(); + } + }; + struct LocationResolverServerOptions { static constexpr size_t PointerBufferSize = 0x400; static constexpr size_t MaxDomains = 0; @@ -146,7 +179,8 @@ namespace { } }; - sf::hipc::ServerManager g_ncm_server_manager; + ncm::ContentManagerImpl g_ncm_manager_service_object; + ContentManagerServerManager g_ncm_server_manager(std::addressof(g_ncm_manager_service_object)); lr::LocationResolverManagerImpl g_lr_manager_service_object; LocationResolverServerManager g_lr_server_manager(std::addressof(g_lr_manager_service_object)); @@ -155,7 +189,7 @@ namespace { void ContentManagerServerMain(void *arg) { /* Create services. */ - R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions)); + R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions)); /* Loop forever, servicing our services. */ g_ncm_server_manager.LoopProcess(); @@ -164,19 +198,19 @@ void ContentManagerServerMain(void *arg) { int main(int argc, char **argv) { /* Initialize content manager implementation. */ + /* TODO: Move Initialize/Finalize into ContentManagerImpl ctor/dtor, initialize client library with static object. */ R_ABORT_UNLESS(ams::ncm::impl::InitializeContentManager()); - static os::Thread s_content_manager_thread; - - R_ABORT_UNLESS(s_content_manager_thread.Initialize(&ContentManagerServerMain, nullptr, 0x4000, 0x15)); - R_ABORT_UNLESS(s_content_manager_thread.Start()); + R_ABORT_UNLESS(g_ncm_server_manager.Initialize()); + R_ABORT_UNLESS(g_ncm_server_manager.StartThreads()); R_ABORT_UNLESS(g_lr_server_manager.Initialize()); R_ABORT_UNLESS(g_lr_server_manager.StartThreads()); - s_content_manager_thread.Join(); + g_ncm_server_manager.Wait(); g_lr_server_manager.Wait(); + /* TODO: This call is eventually automatic at scope exit. */ ams::ncm::impl::FinalizeContentManager(); return 0; diff --git a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp index 3118fb2a8..a99176d65 100644 --- a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp +++ b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp @@ -66,7 +66,7 @@ namespace ams::ncm { bool has = false; R_TRY(fs::HasFile(&has, content_path)); - + if (!has) { path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path); R_TRY(fs::HasFile(&has, content_path)); @@ -76,7 +76,7 @@ namespace ams::ncm { return ResultSuccess(); } - Result ReadOnlyContentStorageImpl::GetPath(sf::Out out, ContentId content_id) { + Result ReadOnlyContentStorageImpl::GetPath(sf::Out out, ContentId content_id) { R_TRY(this->EnsureEnabled()); char content_path[FS_MAX_PATH] = {0}; @@ -85,18 +85,18 @@ namespace ams::ncm { path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path); R_TRY(fs::HasFile(&is_content_meta_file, content_path)); - + if (!is_content_meta_file) { this->make_content_path_func(content_path, content_id, this->root_path); } - + R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); - out.SetValue(lr::Path::Encode(common_path)); + out.SetValue(Path::Encode(common_path)); return ResultSuccess(); } - Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) { + Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) { return ResultInvalidContentStorageOperation(); } @@ -124,7 +124,7 @@ namespace ams::ncm { this->make_content_path_func(content_path, content_id, this->root_path); R_TRY(fs::HasFile(&is_content_file, content_path)); - + if (!is_content_file) { path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path); } @@ -158,18 +158,18 @@ namespace ams::ncm { this->make_content_path_func(content_path, content_id, this->root_path); R_TRY(fs::HasFile(&is_content_file, content_path)); - + if (!is_content_file) { path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path); } - + FILE *f = nullptr; R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Read)); - + ON_SCOPE_EXIT { fclose(f); }; - + R_TRY(fs::ReadFile(f, offset, buf.GetPointer(), buf.GetSize())); return ResultSuccess(); } @@ -198,13 +198,13 @@ namespace ams::ncm { path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path); R_TRY(fs::HasFile(&is_content_meta_file, content_path)); - + if (!is_content_meta_file) { this->make_content_path_func(content_path, content_id, this->root_path); } R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); - + ncm::RightsId rights_id; R_TRY(GetRightsId(&rights_id, common_path)); out_rights_id.SetValue(rights_id); diff --git a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp index f69cd0a17..3869dac01 100644 --- a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp +++ b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp @@ -33,8 +33,8 @@ namespace ams::ncm { virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override; virtual Result Delete(ContentId content_id) override; virtual Result Has(sf::Out out, ContentId content_id) override; - virtual Result GetPath(sf::Out out, ContentId content_id) override; - virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override; + virtual Result GetPath(sf::Out out, ContentId content_id) override; + virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override; virtual Result CleanupAllPlaceHolder() override; virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override; virtual Result GetContentCount(sf::Out out_count) override;