diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp index 7c9a8e9ad..05ebe160d 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp @@ -27,7 +27,7 @@ namespace ams::ncm { using ListType = ncm::IntegratedList; using DataType = ListType::ListData; private: - os::SdkMutex m_mutex; + os::SdkRecursiveMutex m_mutex; ListType m_list; bool m_disabled; public: diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_storage_impl.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_storage_impl.hpp index 86b19a7d5..c0d5a9dad 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_storage_impl.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_storage_impl.hpp @@ -27,7 +27,7 @@ namespace ams::ncm { using ListType = ncm::IntegratedList; using DataType = ListType::ListData; private: - os::SdkMutex m_mutex; + os::SdkRecursiveMutex m_mutex; ListType m_list; bool m_disabled; public: diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_list.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_list.hpp index 3451301d6..778eec60b 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_list.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_list.hpp @@ -77,6 +77,15 @@ namespace ams::ncm { R_RETURN(result); } + + Result ForAll(auto callback) { + for (size_t i = 0; i < m_count; ++i) { + R_TRY(callback(this->Get(i))); + } + R_SUCCEED(); + } + + size_t GetCount() const { return m_count; } }; } diff --git a/libraries/libstratosphere/source/ncm/ncm_integrated_content_meta_database_impl.cpp b/libraries/libstratosphere/source/ncm/ncm_integrated_content_meta_database_impl.cpp new file mode 100644 index 000000000..2a0ca8f51 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_integrated_content_meta_database_impl.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::ncm { + + Result IntegratedContentMetaDatabaseImpl::Set(const ContentMetaKey &key, const sf::InBuffer &value) { + AMS_UNUSED(key, value); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentMetaDatabaseImpl::Get(sf::Out out_size, const ContentMetaKey &key, const sf::OutBuffer &out_value) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->Get(out_size, key, out_value)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::Remove(const ContentMetaKey &key) { + AMS_UNUSED(key); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentMetaDatabaseImpl::GetContentIdByType(sf::Out out_content_id, const ContentMetaKey &key, ContentType type) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetContentIdByType(out_content_id, key, type)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::ListContentInfo(sf::Out out_entries_written, const sf::OutArray &out_info, const ContentMetaKey &key, s32 offset) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), key)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentMetaNotFound()); + + + /* If it does, list the content infos. */ + R_RETURN(data.interface->ListContentInfo(out_entries_written, out_info, key, offset)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::List(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out_info, ContentMetaType meta_type, ApplicationId application_id, u64 min, u64 max, ContentInstallType install_type) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* List on all databases. */ + s32 entries_total = 0; + s32 entries_written = 0; + R_TRY(m_list.ForAll([&](const auto &data) { + /* List on the current database. */ + s32 cur_total; + s32 cur_written; + R_TRY(data.interface->List(std::addressof(cur_total), std::addressof(cur_written), sf::OutArray{out_info.GetPointer() + entries_written, out_info.GetSize() - entries_written}, meta_type, application_id, min, max, install_type)); + + /* Add to the totals. */ + entries_total += cur_total; + entries_written += cur_written; + R_SUCCEED(); + })); + + /* Set output. */ + *out_entries_total = entries_total; + *out_entries_written = entries_written; + R_SUCCEED(); + } + Result IntegratedContentMetaDatabaseImpl::GetLatestContentMetaKey(sf::Out out_key, u64 id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetLatestContentMetaKey(out_key, id)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::ListApplication(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out_keys, ContentMetaType meta_type) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* List on all databases. */ + s32 entries_total = 0; + s32 entries_written = 0; + R_TRY(m_list.ForAll([&](const auto &data) { + /* List on the current database. */ + s32 cur_total; + s32 cur_written; + R_TRY(data.interface->ListApplication(std::addressof(cur_total), std::addressof(cur_written), sf::OutArray{out_keys.GetPointer() + entries_written, out_keys.GetSize() - entries_written}, meta_type)); + + /* Add to the totals. */ + entries_total += cur_total; + entries_written += cur_written; + R_SUCCEED(); + })); + + /* Set output. */ + *out_entries_total = entries_total; + *out_entries_written = entries_written; + R_SUCCEED(); + } + + Result IntegratedContentMetaDatabaseImpl::Has(sf::Out out, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* If we don't locate the content meta, set the output to false. */ + *out = false; + ON_RESULT_INCLUDED(ncm::ResultContentMetaNotFound) { *out = false; }; + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + R_TRY(data.interface->Has(out, key)); + + /* If it doesn't, continue on. */ + R_UNLESS(*out, ncm::ResultContentMetaNotFound()); + + /* If it does, we're done looking. */ + R_SUCCEED(); + })); + } + + Result IntegratedContentMetaDatabaseImpl::HasAll(sf::Out out, const sf::InArray &keys) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + *out = false; + + /* Check if keys are present. */ + for (size_t i = 0; i < keys.GetSize(); i++) { + /* Check if we have the current key. */ + bool has; + R_TRY(this->Has(std::addressof(has), keys[i])); + + /* If we don't, then we can early return because we don't have all. */ + R_SUCCEED_IF(!has); + } + + *out = true; + R_SUCCEED(); + } + + Result IntegratedContentMetaDatabaseImpl::GetSize(sf::Out out_size, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetSize(out_size, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetRequiredSystemVersion(sf::Out out_version, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetRequiredSystemVersion(out_version, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetPatchContentMetaId(sf::Out out_patch_id, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetPatchContentMetaId(out_patch_id, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::DisableForcibly() { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + m_disabled = true; + R_SUCCEED(); + } + + Result IntegratedContentMetaDatabaseImpl::LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) { + AMS_UNUSED(out_orphaned, content_ids); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentMetaDatabaseImpl::Commit() { + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentMetaDatabaseImpl::HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) { + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + /* NOTE: Nintendo bug: Nintendo calls this->Has(), which is likely a copy paste error from ::HasAll... */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), key)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentMetaNotFound()); + + /* If it does, list the content infos. */ + R_RETURN(data.interface->HasContent(out, key, content_id)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, s32 offset) { + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), key)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentMetaNotFound()); + + /* If it does, list the content infos. */ + R_RETURN(data.interface->ListContentMetaInfo(out_entries_written, out_meta_info, key, offset)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetAttributes(out_attributes, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetRequiredApplicationVersion(out_version, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetContentIdByTypeAndIdOffset(sf::Out out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetContentIdByTypeAndIdOffset(out_content_id, key, type, id_offset)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetCount(sf::Out out_count) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* List on all databases. */ + u32 total = 0; + R_TRY(m_list.ForAll([&](const auto &data) { + /* List on the current database. */ + u32 cur; + R_TRY(data.interface->GetCount(std::addressof(cur))); + + /* Add to the totals. */ + total += cur; + R_SUCCEED(); + })); + + /* Set output. */ + *out_count = total; + R_SUCCEED(); + } + + Result IntegratedContentMetaDatabaseImpl::GetOwnerApplicationId(sf::Out out_id, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetOwnerApplicationId(out_id, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetContentAccessibilities(sf::Out out_accessibilities, const ContentMetaKey &key) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetContentAccessibilities(out_accessibilities, key)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetContentInfoByType(sf::Out out_content_info, const ContentMetaKey &key, ContentType type) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetContentInfoByType(out_content_info, key, type)); + })); + } + + Result IntegratedContentMetaDatabaseImpl::GetContentInfoByTypeAndIdOffset(sf::Out out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound()); + + /* Check each interface in turn. */ + R_RETURN(m_list.TryEach([&](const auto &data) { + /* Try the current interface. */ + R_RETURN(data.interface->GetContentInfoByTypeAndIdOffset(out_content_info, key, type, id_offset)); + })); + } + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_integrated_content_storage_impl.cpp b/libraries/libstratosphere/source/ncm/ncm_integrated_content_storage_impl.cpp new file mode 100644 index 000000000..0ac66dfee --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_integrated_content_storage_impl.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::ncm { + + Result IntegratedContentStorageImpl::GeneratePlaceHolderId(sf::Out out) { + AMS_UNUSED(out); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size) { + AMS_UNUSED(placeholder_id, content_id, size); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::DeletePlaceHolder(PlaceHolderId placeholder_id) { + AMS_UNUSED(placeholder_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::HasPlaceHolder(sf::Out out, PlaceHolderId placeholder_id) { + AMS_UNUSED(placeholder_id); + + /* Integrated storages cannot have placeholders. */ + *out = false; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data) { + AMS_UNUSED(placeholder_id, offset, data); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::Register(PlaceHolderId placeholder_id, ContentId content_id) { + AMS_UNUSED(placeholder_id, content_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::Delete(ContentId content_id) { + AMS_UNUSED(content_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::Has(sf::Out out, ContentId content_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* If we don't locate the content, set the output to false. */ + *out = false; + ON_RESULT_INCLUDED(ncm::ResultContentNotFound) { *out = false; }; + + /* Check each interface in turn. */ + R_TRY(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + R_TRY(data.interface->Has(out, content_id)); + + /* If it doesn't, continue on. */ + R_UNLESS(*out, ncm::ResultContentNotFound()); + + /* If it does, we're done looking. */ + R_SUCCEED(); + })); + + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetPath(sf::Out out, ContentId content_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentNotFound()); + + /* Check each interface in turn. */ + R_TRY(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), content_id)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentNotFound()); + + + /* If it does, get the path. */ + R_RETURN(data.interface->GetPath(out, content_id)); + })); + + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) { + AMS_UNUSED(out, placeholder_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::CleanupAllPlaceHolder() { + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) { + AMS_UNUSED(out_buf); + *out_count = 0; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetContentCount(sf::Out out_count) { + *out_count = 0; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::ListContentId(sf::Out out_count, const sf::OutArray &out_buf, s32 offset) { + AMS_UNUSED(out_buf, offset); + *out_count = 0; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetSizeFromContentId(sf::Out out_size, ContentId content_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentNotFound()); + + /* Check each interface in turn. */ + R_TRY(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), content_id)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentNotFound()); + + + /* If it does, get the size. */ + R_RETURN(data.interface->GetSizeFromContentId(out_size, content_id)); + })); + + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::DisableForcibly() { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + m_disabled = true; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { + AMS_UNUSED(placeholder_id, old_content_id, new_content_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size) { + AMS_UNUSED(placeholder_id, size); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentNotFound()); + + /* Check each interface in turn. */ + R_TRY(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), content_id)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentNotFound()); + + + /* If it does, read the file. */ + R_RETURN(data.interface->ReadContentIdFile(buf, content_id, offset)); + })); + + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromPlaceHolderIdDeprecated(sf::Out out_rights_id, PlaceHolderId placeholder_id) { + /* Obtain the regular rights id for the placeholder id. */ + ncm::RightsId rights_id; + R_TRY(this->GetRightsIdFromPlaceHolderIdDeprecated2(std::addressof(rights_id), placeholder_id)); + + /* Output the fs rights id. */ + out_rights_id.SetValue(rights_id.id); + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromPlaceHolderIdDeprecated2(sf::Out out_rights_id, PlaceHolderId placeholder_id) { + R_RETURN(this->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id, fs::ContentAttributes_None)); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromPlaceHolderId(sf::Out out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr) { + AMS_UNUSED(out_rights_id, placeholder_id, attr); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromContentIdDeprecated(sf::Out out_rights_id, ContentId content_id) { + /* Obtain the regular rights id for the content id. */ + ncm::RightsId rights_id; + R_TRY(this->GetRightsIdFromContentIdDeprecated2(std::addressof(rights_id), content_id)); + + /* Output the fs rights id. */ + out_rights_id.SetValue(rights_id.id); + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromContentIdDeprecated2(sf::Out out_rights_id, ContentId content_id) { + R_RETURN(this->GetRightsIdFromContentId(out_rights_id, content_id, fs::ContentAttributes_None)); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromContentId(sf::Out out_rights_id, ContentId content_id, fs::ContentAttributes attr) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Check that our list has interfaces to check. */ + R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentNotFound()); + + /* Check each interface in turn. */ + R_TRY(m_list.TryEach([&](const auto &data) { + /* Check if the current interface has it. */ + bool has; + R_TRY(data.interface->Has(std::addressof(has), content_id)); + + /* If it doesn't, continue on. */ + R_UNLESS(has, ncm::ResultContentNotFound()); + + + /* If it does, read the file. */ + R_RETURN(data.interface->GetRightsIdFromContentId(out_rights_id, content_id, attr)); + })); + + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data) { + AMS_UNUSED(content_id, offset, data); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::GetFreeSpaceSize(sf::Out out_size) { + out_size.SetValue(0); + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetTotalSpaceSize(sf::Out out_size) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we're enabled. */ + R_TRY(this->EnsureEnabled()); + + /* Determine the total size. */ + s64 total_size = 0; + R_TRY(m_list.ForAll([&](const auto &data) { + /* Get the current size. */ + s64 cur_size; + R_TRY(data.interface->GetTotalSpaceSize(std::addressof(cur_size))); + + /* Add to the total. */ + total_size += cur_size; + R_SUCCEED(); + })); + + *out_size = total_size; + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::FlushPlaceHolder() { + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::GetSizeFromPlaceHolderId(sf::Out out, PlaceHolderId placeholder_id) { + AMS_UNUSED(out, placeholder_id); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::RepairInvalidFileAttribute() { + R_SUCCEED(); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCacheDeprecated(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) { + R_RETURN(this->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id, fs::ContentAttributes_None)); + } + + Result IntegratedContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) { + AMS_UNUSED(out_rights_id, placeholder_id, cache_content_id, attr); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::RegisterPath(const ContentId &content_id, const Path &path) { + AMS_UNUSED(content_id, path); + R_THROW(ncm::ResultInvalidOperation()); + } + + Result IntegratedContentStorageImpl::ClearRegisteredPath() { + R_THROW(ncm::ResultInvalidOperation()); + } + +}