diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_i_add_on_content_location_resolver.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_i_add_on_content_location_resolver.hpp index 813e07899..893b27012 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_i_add_on_content_location_resolver.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_i_add_on_content_location_resolver.hpp @@ -17,12 +17,16 @@ #pragma once #include -#define AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveAddOnContentPath, (sf::Out out, ncm::DataId id), (out, id), hos::Version_2_0_0) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorageDeprecated, (ncm::DataId id, ncm::StorageId storage_id), (id, storage_id), hos::Version_2_0_0, hos::Version_8_1_1) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorage, (ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id), (id, application_id, storage_id), hos::Version_9_0_0) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, UnregisterAllAddOnContentPath, (), (), hos::Version_2_0_0) \ - AMS_SF_METHOD_INFO(C, H, 3, Result, RefreshApplicationAddOnContent, (const sf::InArray &ids), (ids), hos::Version_9_0_0) \ - AMS_SF_METHOD_INFO(C, H, 4, Result, UnregisterApplicationAddOnContent, (ncm::ApplicationId id), (id), hos::Version_9_0_0) +#define AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveAddOnContentPath, (sf::Out out, ncm::DataId id), (out, id), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorageDeprecated, (ncm::DataId id, ncm::StorageId storage_id), (id, storage_id), hos::Version_2_0_0, hos::Version_8_1_1) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorage, (ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id), (id, application_id, storage_id), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, UnregisterAllAddOnContentPath, (), (), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, RefreshApplicationAddOnContent, (const sf::InArray &ids), (ids), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, UnregisterApplicationAddOnContent, (ncm::ApplicationId id), (id), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, GetRegisteredAddOnContentPaths, (sf::Out out, sf::Out out2, ncm::DataId id), (out, out2, id), hos::Version_15_0_0) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, RegisterAddOnContentPath, (ncm::DataId id, ncm::ApplicationId application_id, const lr::Path &path), (id, application_id, path), hos::Version_15_0_0) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, RegisterAddOnContentPaths, (ncm::DataId id, ncm::ApplicationId application_id, const lr::Path &path, const lr::Path &path2), (id, application_id, path, path2), hos::Version_15_0_0) + AMS_SF_DEFINE_INTERFACE(ams::lr, IAddOnContentLocationResolver, AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO, 0x77617E39) diff --git a/libraries/libstratosphere/include/stratosphere/ncm.hpp b/libraries/libstratosphere/include/stratosphere/ncm.hpp index 896306225..958496c95 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_attributes.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_attributes.hpp deleted file mode 100644 index 5bfd69485..000000000 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_attributes.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once -#include -#include - -namespace ams::ncm { - - /* TODO: What is this struct, really? It is presumably not ContentAttributes/has more fields. */ - struct ContentAttributes { - fs::ContentAttributes content_attributes; - u8 unknown[0xF]; - - static constexpr ALWAYS_INLINE ContentAttributes Make(fs::ContentAttributes attr) { - return { attr, }; - } - }; - static_assert(util::is_pod::value); - static_assert(sizeof(ContentAttributes) == 0x10); - - constexpr inline const ContentAttributes DefaultContentAttributes = ContentAttributes::Make(fs::ContentAttributes_None); - -} 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 ed8f796ef..1d1bb8425 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 @@ -18,28 +18,60 @@ namespace ams::lr { - Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out out, ncm::DataId id) { - /* Find a storage that contains the given program id. */ - ncm::StorageId storage_id = ncm::StorageId::None; - R_UNLESS(m_registered_storages.Find(std::addressof(storage_id), id), lr::ResultAddOnContentNotFound()); + namespace { - /* Obtain a content meta database for the storage id. */ - ncm::ContentMetaDatabase content_meta_database; - R_TRY(ncm::OpenContentMetaDatabase(std::addressof(content_meta_database), storage_id)); + constexpr const lr::Path EmptyPath = {}; - /* Find the latest data content id for the given program id. */ - ncm::ContentId data_content_id; - R_TRY(content_meta_database.GetLatestData(std::addressof(data_content_id), id)); + template + Result ResolveAddOnContentPathImpl(Path *out, RedirectionAttributes *out_attr, const RegisteredStorages &storages, ncm::DataId id) { + /* Find a storage that contains the given program id. */ + ncm::StorageId storage_id = ncm::StorageId::None; + R_UNLESS(storages.Find(std::addressof(storage_id), id), lr::ResultAddOnContentNotFound()); - /* Obtain a content storage for the storage id. */ - ncm::ContentStorage content_storage; - R_TRY(ncm::OpenContentStorage(std::addressof(content_storage), storage_id)); + /* Obtain a content meta database for the storage id. */ + ncm::ContentMetaDatabase content_meta_database; + R_TRY(ncm::OpenContentMetaDatabase(std::addressof(content_meta_database), storage_id)); - /* Get the path of the data content. */ - static_assert(sizeof(lr::Path) == sizeof(ncm::Path)); - content_storage.GetPath(reinterpret_cast(out.GetPointer()), data_content_id); + /* Find the latest data content info for the given program id. */ + ncm::ContentInfo data_content_info; + R_TRY(content_meta_database.GetLatestData(std::addressof(data_content_info), id)); + /* Obtain a content storage for the storage id. */ + ncm::ContentStorage content_storage; + R_TRY(ncm::OpenContentStorage(std::addressof(content_storage), storage_id)); + + /* Get the path of the data content. */ + static_assert(sizeof(lr::Path) == sizeof(ncm::Path)); + content_storage.GetPath(reinterpret_cast(out), data_content_info.GetId()); + + /* Get the redirection attributes. */ + *out_attr = RedirectionAttributes::Make(data_content_info.GetContentAttributes()); + + R_SUCCEED(); + } + + } + + Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(Path *out, RedirectionAttributes *out_attr, ncm::DataId id) { + /* Try to resolve using our registered storages. */ + if (const auto result = ResolveAddOnContentPathImpl(out, out_attr, m_registered_storages, id); R_SUCCEEDED(result) || !lr::ResultAddOnContentNotFound::Includes(result)) { + R_RETURN(result); + } + + /* If we failed to find the add-on content by storage, we should check if there's a registered path. */ + auto * const found = m_registered_paths.Find(id); + R_UNLESS(found != nullptr, lr::ResultAddOnContentNotFound()); + + /* Set the output path. */ + *out = found->redir_path.path; + *out_attr = found->redir_path.attributes; R_SUCCEED(); + + } + + Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out out, ncm::DataId id) { + RedirectionAttributes attr; + R_RETURN(this->ResolveAddOnContentPath(out.GetPointer(), std::addressof(attr), id)); } Result AddOnContentLocationResolverImpl::RegisterAddOnContentStorageDeprecated(ncm::DataId id, ncm::StorageId storage_id) { @@ -56,17 +88,27 @@ namespace ams::lr { Result AddOnContentLocationResolverImpl::UnregisterAllAddOnContentPath() { m_registered_storages.Clear(); + m_registered_paths.RemoveAll(); + m_registered_other_paths.RemoveAll(); R_SUCCEED(); } Result AddOnContentLocationResolverImpl::RefreshApplicationAddOnContent(const sf::InArray &ids) { - if (ids.GetSize() == 0) { - /* Clear all registered storages. */ - m_registered_storages.Clear(); - } else { - /* Clear all registered storages excluding the provided program ids. */ - m_registered_storages.ClearExcluding(reinterpret_cast(ids.GetPointer()), ids.GetSize()); - } + /* Clear all registered storages excluding the provided program ids. */ + m_registered_storages.ClearExcluding(reinterpret_cast(ids.GetPointer()), ids.GetSize()); + + auto ShouldRefresh = [&ids](const ncm::DataId &, const OwnedPath &owned_path) { + for (size_t i = 0; i < ids.GetSize(); ++i) { + if (owned_path.owner_id == ids[i]) { + return false; + } + } + + return true; + }; + + m_registered_paths.RemoveIf(ShouldRefresh); + m_registered_other_paths.RemoveIf(ShouldRefresh); R_SUCCEED(); } @@ -74,6 +116,77 @@ namespace ams::lr { Result AddOnContentLocationResolverImpl::UnregisterApplicationAddOnContent(ncm::ApplicationId id) { /* Remove entries belonging to the provided application. */ m_registered_storages.UnregisterOwnerProgram(id); + + auto ShouldRefresh = [&id](const ncm::DataId &, const OwnedPath &owned_path) { + return owned_path.owner_id == id; + }; + + m_registered_paths.RemoveIf(ShouldRefresh); + m_registered_other_paths.RemoveIf(ShouldRefresh); + + R_SUCCEED(); + } + + Result AddOnContentLocationResolverImpl::GetRegisteredAddOnContentPaths(Path *out, RedirectionAttributes *out_attr, Path *out2, RedirectionAttributes *out_attr2, ncm::DataId id) { + /* Find a registered path. */ + auto * const found = m_registered_paths.Find(id); + if (found == nullptr) { + /* We have no registered path, so perform a normal resolution. */ + R_TRY(ResolveAddOnContentPathImpl(out, out_attr, m_registered_storages, id)); + + /* Clear the second output path. */ + *out2 = {}; + *out_attr2 = {}; + R_SUCCEED(); + } + + /* Set the output path. */ + *out = found->redir_path.path; + *out_attr = found->redir_path.attributes; + + /* If we have a second path, set it to output. */ + if (auto * const found2 = m_registered_other_paths.Find(id); found2 != nullptr) { + *out2 = found2->redir_path.path; + *out_attr2 = found2->redir_path.attributes; + } else { + *out2 = {}; + *out_attr2 = {}; + } + + R_SUCCEED(); + } + + Result AddOnContentLocationResolverImpl::GetRegisteredAddOnContentPaths(sf::Out out, sf::Out out2, ncm::DataId id) { + RedirectionAttributes attr, attr2; + R_RETURN(this->GetRegisteredAddOnContentPaths(out.GetPointer(), std::addressof(attr), out2.GetPointer(), std::addressof(attr2), id)); + } + + Result AddOnContentLocationResolverImpl::RegisterAddOnContentPath(ncm::DataId id, ncm::ApplicationId application_id, const lr::Path &path) { + R_RETURN(this->RegisterAddOnContentPaths(id, application_id, path, DefaultRedirectionAttributes, EmptyPath, DefaultRedirectionAttributes)); + } + + Result AddOnContentLocationResolverImpl::RegisterAddOnContentPaths(ncm::DataId id, ncm::ApplicationId application_id, const lr::Path &path, const lr::Path &path2) { + R_RETURN(this->RegisterAddOnContentPaths(id, application_id, path, DefaultRedirectionAttributes, path2, DefaultRedirectionAttributes)); + } + + Result AddOnContentLocationResolverImpl::RegisterAddOnContentPaths(ncm::DataId id, ncm::ApplicationId application_id, const Path &path, const RedirectionAttributes &attr, const Path &path2, const RedirectionAttributes &attr2) { + /* Check that it's possible for us to register the path. */ + /* NOTE: This check is technically incorrect, if the id is already registered. */ + R_UNLESS(!m_registered_paths.IsFull(), lr::ResultTooManyRegisteredPaths()); + + /* Check that the input path isn't empty. */ + R_UNLESS(path.str[0] != '\x00', lr::ResultInvalidPath()); + + /* Insert the path. */ + m_registered_paths.InsertOrAssign(id, OwnedPath{ { path, attr }, application_id }); + + /* If we have a second path, insert it. */ + if (path2.str[0] != '\x00') { + m_registered_other_paths.InsertOrAssign(id, OwnedPath { { path2, attr2 }, application_id }); + } else { + m_registered_other_paths.Remove(id); + } + R_SUCCEED(); } diff --git a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.hpp index 6f96ed724..14223178c 100644 --- a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.hpp @@ -22,9 +22,16 @@ namespace ams::lr { class AddOnContentLocationResolverImpl { + private: + struct OwnedPath { + RedirectionPath redir_path; + ncm::ApplicationId owner_id; + }; private: /* Storage for RegisteredData entries by data id. */ RegisteredStorages m_registered_storages; + ncm::BoundedMap m_registered_paths; + ncm::BoundedMap m_registered_other_paths; private: static ALWAYS_INLINE size_t GetStorageCapacity() { const auto version = hos::GetVersion(); @@ -37,7 +44,7 @@ namespace ams::lr { } } public: - AddOnContentLocationResolverImpl() : m_registered_storages(GetStorageCapacity()) { /* ... */ } + AddOnContentLocationResolverImpl() : m_registered_storages(GetStorageCapacity()), m_registered_paths{}, m_registered_other_paths{} { /* ... */ } /* Actual commands. */ Result ResolveAddOnContentPath(sf::Out out, ncm::DataId id); @@ -46,6 +53,13 @@ namespace ams::lr { Result UnregisterAllAddOnContentPath(); Result RefreshApplicationAddOnContent(const sf::InArray &ids); Result UnregisterApplicationAddOnContent(ncm::ApplicationId id); + Result GetRegisteredAddOnContentPaths(sf::Out out, sf::Out out2, ncm::DataId id); + Result RegisterAddOnContentPath(ncm::DataId id, ncm::ApplicationId application_id, const Path &path); + Result RegisterAddOnContentPaths(ncm::DataId id, ncm::ApplicationId application_id, const Path &path, const Path &path2); + private: + Result ResolveAddOnContentPath(Path *out, RedirectionAttributes *out_attr, ncm::DataId id); + Result GetRegisteredAddOnContentPaths(Path *out, RedirectionAttributes *out_attr, Path *out2, RedirectionAttributes *out_attr2, ncm::DataId id); + Result RegisterAddOnContentPaths(ncm::DataId id, ncm::ApplicationId application_id, const Path &path, const RedirectionAttributes &attr, const Path &path2, const RedirectionAttributes &attr2); }; static_assert(lr::IsIAddOnContentLocationResolver); 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 eb062bb9e..2b918715b 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp @@ -28,37 +28,45 @@ namespace ams::lr { m_content_storage.GetPath(reinterpret_cast(out), content_id); } - Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out out, ncm::ProgramId id) { + Result ContentLocationResolverImpl::ResolveProgramPath(Path *out, RedirectionAttributes *out_attr, ncm::ProgramId id) { /* Use a redirection if present. */ - R_SUCCEED_IF(m_program_redirector.FindRedirection(out.GetPointer(), id)); + R_SUCCEED_IF(m_program_redirector.FindRedirection(out, out_attr, id)); /* If we're not enabled, we can't resolve a program. */ R_UNLESS(m_enabled, lr::ResultProgramNotFound()) /* Find the latest program content for the program id. */ - ncm::ContentId program_content_id; - R_TRY_CATCH(m_content_meta_database.GetLatestProgram(std::addressof(program_content_id), id)) { + ncm::ContentInfo program_content_info; + R_TRY_CATCH(m_content_meta_database.GetLatestProgram(std::addressof(program_content_info), id)) { R_CONVERT(ncm::ResultContentMetaNotFound, lr::ResultProgramNotFound()) } R_END_TRY_CATCH; - /* Obtain the content path. */ - this->GetContentStoragePath(out.GetPointer(), program_content_id); + /* Obtain the content path and attributes. */ + this->GetContentStoragePath(out, program_content_info.GetId()); + *out_attr = RedirectionAttributes::Make(program_content_info.GetContentAttributes()); R_SUCCEED(); } + Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out out, ncm::ProgramId id) { + RedirectionAttributes attr; + R_RETURN(this->ResolveProgramPath(out.GetPointer(), std::addressof(attr), id)); + } + Result ContentLocationResolverImpl::RedirectProgramPath(const Path &path, ncm::ProgramId id) { - m_program_redirector.SetRedirection(id, path); + m_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result ContentLocationResolverImpl::ResolveApplicationControlPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_app_control_redirector.FindRedirection(out.GetPointer(), id), lr::ResultControlNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_app_control_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultControlNotFound()); R_SUCCEED(); } Result ContentLocationResolverImpl::ResolveApplicationHtmlDocumentPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_html_docs_redirector.FindRedirection(out.GetPointer(), id), lr::ResultHtmlDocumentNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_html_docs_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultHtmlDocumentNotFound()); R_SUCCEED(); } @@ -66,48 +74,49 @@ namespace ams::lr { /* If we're not enabled, we can't resolve data. */ R_UNLESS(m_enabled, lr::ResultDataNotFound()) - /* Find the latest data content for the program id. */ - ncm::ContentId data_content_id; - R_TRY(m_content_meta_database.GetLatestData(std::addressof(data_content_id), id)); + /* Find the latest data content info for the program id. */ + ncm::ContentInfo data_content_info; + R_TRY(m_content_meta_database.GetLatestData(std::addressof(data_content_info), id)); /* Obtain the content path. */ - this->GetContentStoragePath(out.GetPointer(), data_content_id); + this->GetContentStoragePath(out.GetPointer(), data_content_info.GetId()); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) { - m_app_control_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_app_control_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_app_control_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_app_control_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) { - m_html_docs_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_html_docs_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_html_docs_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_html_docs_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::ResolveApplicationLegalInformationPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_legal_info_redirector.FindRedirection(out.GetPointer(), id), lr::ResultLegalInformationNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_legal_info_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultLegalInformationNotFound()); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) { - m_legal_info_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_legal_info_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_legal_info_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_legal_info_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } @@ -129,12 +138,12 @@ namespace ams::lr { } Result ContentLocationResolverImpl::RedirectApplicationProgramPathDeprecated(const Path &path, ncm::ProgramId id) { - m_program_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_program_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_program_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } @@ -170,13 +179,14 @@ namespace ams::lr { Result ContentLocationResolverImpl::ResolveProgramPathForDebug(sf::Out out, ncm::ProgramId id) { /* Use a redirection if present. */ - R_SUCCEED_IF(m_debug_program_redirector.FindRedirection(out.GetPointer(), id)); + RedirectionAttributes attr; + R_SUCCEED_IF(m_debug_program_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id)); /* If we're not enabled, we can't resolve a program. */ R_UNLESS(m_enabled, lr::ResultDebugProgramNotFound()) /* Otherwise find the path for the program id. */ - R_TRY_CATCH(this->ResolveProgramPath(out.GetPointer(), id)) { + R_TRY_CATCH(this->ResolveProgramPath(out.GetPointer(), std::addressof(attr), id)) { R_CONVERT(lr::ResultProgramNotFound, lr::ResultDebugProgramNotFound()) } R_END_TRY_CATCH; @@ -184,17 +194,17 @@ namespace ams::lr { } Result ContentLocationResolverImpl::RedirectProgramPathForDebug(const Path &path, ncm::ProgramId id) { - m_debug_program_redirector.SetRedirection(id, path); + m_debug_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationProgramPathForDebugDeprecated(const Path &path, ncm::ProgramId id) { - m_debug_program_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_debug_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result ContentLocationResolverImpl::RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_debug_program_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_debug_program_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } 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 a219fca54..d57aaf67e 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp @@ -16,6 +16,7 @@ #pragma once #include "lr_location_resolver_impl_base.hpp" +#include "lr_location_redirector.hpp" namespace ams::lr { @@ -34,6 +35,7 @@ namespace ams::lr { private: /* Helper functions. */ void GetContentStoragePath(Path *out, ncm::ContentId content_id); + Result ResolveProgramPath(Path *out, RedirectionAttributes *out_attr, ncm::ProgramId id); public: /* Actual commands. */ Result ResolveProgramPath(sf::Out out, ncm::ProgramId id); diff --git a/libraries/libstratosphere/source/lr/lr_location_redirector.cpp b/libraries/libstratosphere/source/lr/lr_location_redirector.cpp index 17158d18a..ff724a544 100644 --- a/libraries/libstratosphere/source/lr/lr_location_redirector.cpp +++ b/libraries/libstratosphere/source/lr/lr_location_redirector.cpp @@ -25,10 +25,11 @@ namespace ams::lr { ncm::ProgramId m_program_id; ncm::ProgramId m_owner_id; Path m_path; + RedirectionAttributes m_attr; u32 m_flags; public: - Redirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, u32 flags) : - m_program_id(program_id), m_owner_id(owner_id), m_path(path), m_flags(flags) { /* ... */ } + Redirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, const RedirectionAttributes &attr, u32 flags) : + m_program_id(program_id), m_owner_id(owner_id), m_path(path), m_attr(attr), m_flags(flags) { /* ... */ } ncm::ProgramId GetProgramId() const { return m_program_id; @@ -42,6 +43,10 @@ namespace ams::lr { *out = m_path; } + void GetAttributes(RedirectionAttributes *out) const { + *out = m_attr; + } + u32 GetFlags() const { return m_flags; } @@ -51,37 +56,28 @@ namespace ams::lr { } }; - bool LocationRedirector::FindRedirection(Path *out, ncm::ProgramId program_id) const { + bool LocationRedirector::FindRedirection(Path *out, RedirectionAttributes *out_attr, ncm::ProgramId program_id) const { /* Obtain the path of a matching redirection. */ for (const auto &redirection : m_redirection_list) { if (redirection.GetProgramId() == program_id) { redirection.GetPath(out); + redirection.GetAttributes(out_attr); return true; } } return false; } - void LocationRedirector::SetRedirection(ncm::ProgramId program_id, const Path &path, u32 flags) { - this->SetRedirection(program_id, ncm::InvalidProgramId, path, flags); + void LocationRedirector::SetRedirection(ncm::ProgramId program_id, const Path &path, const RedirectionAttributes &attr, u32 flags) { + this->SetRedirection(program_id, ncm::InvalidProgramId, path, attr, flags); } - void LocationRedirector::SetRedirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, u32 flags) { + void LocationRedirector::SetRedirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, const RedirectionAttributes &attr, u32 flags) { /* Remove any existing redirections for this program id. */ this->EraseRedirection(program_id); /* Insert a new redirection into the list. */ - m_redirection_list.push_back(*(new Redirection(program_id, owner_id, path, flags))); - } - - void LocationRedirector::SetRedirectionFlags(ncm::ProgramId program_id, u32 flags) { - /* Set the flags of a redirection with a matching program id. */ - for (auto &redirection : m_redirection_list) { - if (redirection.GetProgramId() == program_id) { - redirection.SetFlags(flags); - break; - } - } + m_redirection_list.push_back(*(new Redirection(program_id, owner_id, path, attr, flags))); } void LocationRedirector::EraseRedirection(ncm::ProgramId program_id) { diff --git a/libraries/libstratosphere/source/lr/lr_location_redirector.hpp b/libraries/libstratosphere/source/lr/lr_location_redirector.hpp index 5d30f95a7..46d611845 100644 --- a/libraries/libstratosphere/source/lr/lr_location_redirector.hpp +++ b/libraries/libstratosphere/source/lr/lr_location_redirector.hpp @@ -24,6 +24,27 @@ namespace ams::lr { RedirectionFlags_Application = (1 << 0), }; + /* TODO: Do any of these unknown fields exist? */ + struct RedirectionAttributes { + fs::ContentAttributes content_attributes; + u8 unknown[0xF]; + + static constexpr ALWAYS_INLINE RedirectionAttributes Make(fs::ContentAttributes attr) { + return { attr, }; + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(RedirectionAttributes) == 0x10); + + constexpr inline const RedirectionAttributes DefaultRedirectionAttributes = RedirectionAttributes::Make(fs::ContentAttributes_None); + + struct RedirectionPath { + Path path; + RedirectionAttributes attributes; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(RedirectionPath) == 0x310); + class LocationRedirector { NON_COPYABLE(LocationRedirector); NON_MOVEABLE(LocationRedirector); @@ -38,10 +59,9 @@ namespace ams::lr { ~LocationRedirector() { this->ClearRedirections(); } /* API. */ - bool FindRedirection(Path *out, ncm::ProgramId program_id) const; - void SetRedirection(ncm::ProgramId program_id, const Path &path, u32 flags = RedirectionFlags_None); - void SetRedirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, u32 flags = RedirectionFlags_None); - void SetRedirectionFlags(ncm::ProgramId program_id, u32 flags); + bool FindRedirection(Path *out, RedirectionAttributes *out_attr, ncm::ProgramId program_id) const; + void SetRedirection(ncm::ProgramId program_id, const Path &path, const RedirectionAttributes &attr, u32 flags = RedirectionFlags_None); + void SetRedirection(ncm::ProgramId program_id, ncm::ProgramId owner_id, const Path &path, const RedirectionAttributes &attr, u32 flags = RedirectionFlags_None); void EraseRedirection(ncm::ProgramId program_id); void ClearRedirections(u32 flags = RedirectionFlags_None); void ClearRedirectionsExcludingOwners(const ncm::ProgramId *excluding_ids, size_t num_ids); diff --git a/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.cpp index 8ae0d8433..1b9e81a38 100644 --- a/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.cpp @@ -24,22 +24,25 @@ namespace ams::lr { } Result RedirectOnlyLocationResolverImpl::ResolveProgramPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_program_redirector.FindRedirection(out.GetPointer(), id), lr::ResultProgramNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_program_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultProgramNotFound()); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectProgramPath(const Path &path, ncm::ProgramId id) { - m_program_redirector.SetRedirection(id, path); + m_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::ResolveApplicationControlPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_app_control_redirector.FindRedirection(out.GetPointer(), id), lr::ResultControlNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_app_control_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultControlNotFound()); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::ResolveApplicationHtmlDocumentPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_html_docs_redirector.FindRedirection(out.GetPointer(), id), lr::ResultHtmlDocumentNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_html_docs_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultHtmlDocumentNotFound()); R_SUCCEED(); } @@ -49,37 +52,38 @@ namespace ams::lr { } Result RedirectOnlyLocationResolverImpl::RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) { - m_app_control_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_app_control_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_app_control_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_app_control_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) { - m_html_docs_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_html_docs_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_html_docs_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_html_docs_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::ResolveApplicationLegalInformationPath(sf::Out out, ncm::ProgramId id) { - R_UNLESS(m_legal_info_redirector.FindRedirection(out.GetPointer(), id), lr::ResultLegalInformationNotFound()); + RedirectionAttributes attr; + R_UNLESS(m_legal_info_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultLegalInformationNotFound()); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) { - m_legal_info_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_legal_info_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_legal_info_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_legal_info_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } @@ -89,12 +93,12 @@ namespace ams::lr { } Result RedirectOnlyLocationResolverImpl::RedirectApplicationProgramPathDeprecated(const Path &path, ncm::ProgramId id) { - m_program_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_program_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_program_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } @@ -130,26 +134,27 @@ namespace ams::lr { Result RedirectOnlyLocationResolverImpl::ResolveProgramPathForDebug(sf::Out out, ncm::ProgramId id) { /* If a debug program redirection is present, use it. */ - R_SUCCEED_IF(m_debug_program_redirector.FindRedirection(out.GetPointer(), id)); + RedirectionAttributes attr; + R_SUCCEED_IF(m_debug_program_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id)); /* Otherwise, try to find a normal program redirection. */ - R_UNLESS(m_program_redirector.FindRedirection(out.GetPointer(), id), lr::ResultDebugProgramNotFound()); + R_UNLESS(m_program_redirector.FindRedirection(out.GetPointer(), std::addressof(attr), id), lr::ResultDebugProgramNotFound()); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectProgramPathForDebug(const Path &path, ncm::ProgramId id) { - m_debug_program_redirector.SetRedirection(id, path); + m_debug_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationProgramPathForDebugDeprecated(const Path &path, ncm::ProgramId id) { - m_debug_program_redirector.SetRedirection(id, path, RedirectionFlags_Application); + m_debug_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } Result RedirectOnlyLocationResolverImpl::RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_debug_program_redirector.SetRedirection(id, owner_id, path, RedirectionFlags_Application); + m_debug_program_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes, RedirectionFlags_Application); R_SUCCEED(); } diff --git a/libraries/libstratosphere/source/lr/lr_registered_data.hpp b/libraries/libstratosphere/source/lr/lr_registered_data.hpp index ffbb7f2b5..03e2037e0 100644 --- a/libraries/libstratosphere/source/lr/lr_registered_data.hpp +++ b/libraries/libstratosphere/source/lr/lr_registered_data.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include "lr_location_redirector.hpp" namespace ams::lr { @@ -137,7 +138,7 @@ namespace ams::lr { }; template - using RegisteredLocations = RegisteredData; + using RegisteredLocations = RegisteredData; template using RegisteredStorages = RegisteredData; diff --git a/libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.cpp index dd7cb67cd..a61148755 100644 --- a/libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.cpp @@ -23,25 +23,33 @@ namespace ams::lr { template bool ResolvePath(Path *out, const LocationRedirector &redirector, const RegisteredLocations &locations, ncm::ProgramId id) { /* Attempt to use a redirection if present. */ - if (!redirector.FindRedirection(out, id)) { + RedirectionAttributes attr; + if (!redirector.FindRedirection(out, std::addressof(attr), id)) { /* Otherwise try and use a registered location. */ - if (!locations.Find(out, id)) { + RedirectionPath redir_path; + if (!locations.Find(std::addressof(redir_path), id)) { return false; } + + /* Set the output path. */ + *out = redir_path.path; } return true; } template void RegisterPath(RegisteredLocations &locations, ncm::ProgramId id, const Path& path, ncm::ProgramId owner_id) { + /* Create a redirection path. */ + const RedirectionPath redir_path = { path, DefaultRedirectionAttributes }; + /* If we register successfully, we're good. */ - if (locations.Register(id, path, owner_id)) { + if (locations.Register(id, redir_path, owner_id)) { return; } /* Otherwise, clear and register (this should always succeed). */ locations.Clear(); - locations.Register(id, path, owner_id); + locations.Register(id, redir_path, owner_id); } } @@ -100,12 +108,12 @@ namespace ams::lr { } Result RegisteredLocationResolverImpl::RedirectProgramPathDeprecated(const Path &path, ncm::ProgramId id) { - m_program_redirector.SetRedirection(id, path); + m_program_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result RegisteredLocationResolverImpl::RedirectProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_program_redirector.SetRedirection(id, owner_id, path); + m_program_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes); R_SUCCEED(); } @@ -130,12 +138,12 @@ namespace ams::lr { } Result RegisteredLocationResolverImpl::RedirectHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) { - m_html_docs_redirector.SetRedirection(id, path); + m_html_docs_redirector.SetRedirection(id, path, DefaultRedirectionAttributes); R_SUCCEED(); } Result RegisteredLocationResolverImpl::RedirectHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - m_html_docs_redirector.SetRedirection(id, owner_id, path); + m_html_docs_redirector.SetRedirection(id, owner_id, path, DefaultRedirectionAttributes); R_SUCCEED(); } diff --git a/libraries/libvapours/include/vapours/results/lr_results.hpp b/libraries/libvapours/include/vapours/results/lr_results.hpp index faad916d3..a139cce69 100644 --- a/libraries/libvapours/include/vapours/results/lr_results.hpp +++ b/libraries/libvapours/include/vapours/results/lr_results.hpp @@ -32,4 +32,6 @@ namespace ams::lr { R_DEFINE_ERROR_RESULT(TooManyRegisteredPaths, 90); + R_DEFINE_ERROR_RESULT(InvalidPath, 140); + } diff --git a/libraries/libvapours/include/vapours/util/util_bounded_map.hpp b/libraries/libvapours/include/vapours/util/util_bounded_map.hpp index ea57ee788..96d1a4f97 100644 --- a/libraries/libvapours/include/vapours/util/util_bounded_map.hpp +++ b/libraries/libvapours/include/vapours/util/util_bounded_map.hpp @@ -134,6 +134,15 @@ namespace ams::util { } } } + + template + void RemoveIf(F f) { + for (size_t i = 0; i < N; ++i) { + if (m_keys[i] && f(m_keys[i].value(), GetReference(m_values[i]))) { + this->FreeEntry(i); + } + } + } }; }