diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver.hpp index 434ccdcdb..ca0397763 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver.hpp @@ -43,7 +43,8 @@ AMS_SF_METHOD_INFO(C, H, 17, Result, RedirectProgramPathForDebug, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 18, Result, RedirectApplicationProgramPathForDebugDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_7_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 18, Result, RedirectApplicationProgramPathForDebug, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ - AMS_SF_METHOD_INFO(C, H, 19, Result, EraseProgramRedirectionForDebug, (ncm::ProgramId id), (id), hos::Version_7_0_0) + AMS_SF_METHOD_INFO(C, H, 19, Result, EraseProgramRedirectionForDebug, (ncm::ProgramId id), (id), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 20, Result, Disable, (), (), hos::Version_15_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, ILocationResolver, AMS_LR_I_LOCATION_RESOLVER_INTERFACE_INFO, 0xB36C8B0E) diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver_manager.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver_manager.hpp index 548fb7273..d0f626029 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver_manager.hpp @@ -20,10 +20,11 @@ #include #include -#define AMS_LR_I_LOCATION_RESOLVER_MANAGER_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, OpenLocationResolver, (sf::Out> out, ncm::StorageId storage_id), (out, storage_id)) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, OpenRegisteredLocationResolver, (sf::Out> out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, RefreshLocationResolver, (ncm::StorageId storage_id), (storage_id)) \ - AMS_SF_METHOD_INFO(C, H, 3, Result, OpenAddOnContentLocationResolver, (sf::Out> out), (out), hos::Version_2_0_0) +#define AMS_LR_I_LOCATION_RESOLVER_MANAGER_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, OpenLocationResolver, (sf::Out> out, ncm::StorageId storage_id), (out, storage_id)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, OpenRegisteredLocationResolver, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, RefreshLocationResolver, (ncm::StorageId storage_id), (storage_id)) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, OpenAddOnContentLocationResolver, (sf::Out> out), (out), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, SetEnabled, (const ams::sf::InMapAliasArray &storages), (storages), hos::Version_15_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, ILocationResolverManager, AMS_LR_I_LOCATION_RESOLVER_MANAGER_INTERFACE_INFO, 0xB2950191) diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver.hpp index 274d16ca8..0ee8ad3b0 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver.hpp @@ -170,6 +170,11 @@ namespace ams::lr { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseProgramRedirectionForDebug(id)); } + + Result Disable() { + AMS_ASSERT(m_interface != nullptr); + R_RETURN(m_interface->Disable()); + } }; } diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver_manager_impl.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver_manager_impl.hpp index 5d488eae3..24d8c6830 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver_manager_impl.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver_manager_impl.hpp @@ -22,9 +22,13 @@ namespace ams::lr { class LocationResolverManagerImpl { + private: + static constexpr size_t ResolverCountMax = 5; private: /* Resolver storage. */ - ncm::BoundedMap, 5> m_location_resolvers{}; + ncm::BoundedMap, ResolverCountMax> m_location_resolvers{}; + ncm::BoundedMap m_location_resolvers_enabled{}; + bool m_default_enabled = true; sf::SharedPointer m_registered_location_resolver = nullptr; sf::SharedPointer m_add_on_content_location_resolver = nullptr; @@ -35,6 +39,7 @@ namespace ams::lr { Result OpenRegisteredLocationResolver(sf::Out> out); Result RefreshLocationResolver(ncm::StorageId storage_id); Result OpenAddOnContentLocationResolver(sf::Out> out); + Result SetEnabled(const sf::InMapAliasArray &storages); }; static_assert(IsILocationResolverManager); 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 1caa3f3cd..eb062bb9e 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp @@ -32,6 +32,9 @@ namespace ams::lr { /* Use a redirection if present. */ R_SUCCEED_IF(m_program_redirector.FindRedirection(out.GetPointer(), 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)) { @@ -60,6 +63,9 @@ namespace ams::lr { } Result ContentLocationResolverImpl::ResolveDataPath(sf::Out out, ncm::DataId id) { + /* 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)); @@ -166,9 +172,12 @@ namespace ams::lr { /* Use a redirection if present. */ R_SUCCEED_IF(m_debug_program_redirector.FindRedirection(out.GetPointer(), 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_CONVERT(ResultProgramNotFound, lr::ResultDebugProgramNotFound()) + R_CONVERT(lr::ResultProgramNotFound, lr::ResultDebugProgramNotFound()) } R_END_TRY_CATCH; R_SUCCEED(); @@ -194,4 +203,9 @@ namespace ams::lr { R_SUCCEED(); } + Result ContentLocationResolverImpl::Disable() { + m_enabled = false; + 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 b0d908bdb..a219fca54 100644 --- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp @@ -22,12 +22,13 @@ namespace ams::lr { class ContentLocationResolverImpl : public LocationResolverImplBase { private: ncm::StorageId m_storage_id; + bool m_enabled; /* Objects for this storage type. */ ncm::ContentMetaDatabase m_content_meta_database; ncm::ContentStorage m_content_storage; public: - ContentLocationResolverImpl(ncm::StorageId storage_id) : m_storage_id(storage_id), m_content_meta_database(), m_content_storage() { /* ... */ } + ContentLocationResolverImpl(ncm::StorageId storage_id, bool enabled) : m_storage_id(storage_id), m_enabled(enabled), m_content_meta_database(), m_content_storage() { /* ... */ } ~ContentLocationResolverImpl(); private: @@ -61,6 +62,7 @@ namespace ams::lr { Result RedirectApplicationProgramPathForDebugDeprecated(const Path &path, ncm::ProgramId id); Result RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id); Result EraseProgramRedirectionForDebug(ncm::ProgramId id); + Result Disable(); }; static_assert(lr::IsILocationResolver); diff --git a/libraries/libstratosphere/source/lr/lr_location_resolver_manager_impl.cpp b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_impl.cpp index d49bfed94..a7925fa93 100644 --- a/libraries/libstratosphere/source/lr/lr_location_resolver_manager_impl.cpp +++ b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_impl.cpp @@ -27,10 +27,19 @@ namespace ams::lr { using ContentLocationResolverFactory = sf::ObjectFactory>; using RedirectOnlyLocationResolverFactory = sf::ObjectFactory>; + bool IsAcceptableStorageId(ncm::StorageId storage_id) { + if (ncm::IsInstallableStorage(storage_id)) { + return storage_id != ncm::StorageId::Any; + } else { + return storage_id == ncm::StorageId::Host || storage_id == ncm::StorageId::GameCard; + } + } + } Result LocationResolverManagerImpl::OpenLocationResolver(sf::Out> out, ncm::StorageId storage_id) { std::scoped_lock lk(m_mutex); + /* Find an existing resolver. */ auto resolver = m_location_resolvers.Find(storage_id); @@ -39,7 +48,11 @@ namespace ams::lr { if (storage_id == ncm::StorageId::Host) { AMS_ABORT_UNLESS(m_location_resolvers.Insert(storage_id, RedirectOnlyLocationResolverFactory::CreateSharedEmplaced())); } else { - auto content_resolver = ContentLocationResolverFactory::CreateSharedEmplaced(storage_id); + /* Get enabled. */ + auto *enabled = m_location_resolvers_enabled.Find(storage_id); + + /* Create the resolver. */ + auto content_resolver = ContentLocationResolverFactory::CreateSharedEmplaced(storage_id, enabled != nullptr ? *enabled : m_default_enabled); R_TRY(content_resolver->Refresh()); AMS_ABORT_UNLESS(m_location_resolvers.Insert(storage_id, std::move(content_resolver))); } @@ -94,4 +107,39 @@ namespace ams::lr { R_SUCCEED(); } + Result LocationResolverManagerImpl::SetEnabled(const sf::InMapAliasArray &storages) { + std::scoped_lock lk(m_mutex); + + /* If we're setting enabled, we're no longer enabled by default. */ + m_default_enabled = false; + + /* Create entries for each storage. */ + for (size_t i = 0; i < storages.GetSize(); ++i) { + /* Get the storage id. */ + const auto storage_id = storages[i]; + + /* Check that the storage id is acceptable. */ + R_UNLESS(IsAcceptableStorageId(storage_id), lr::ResultUnknownStorageId()); + + /* Set the storage id as enabled. */ + AMS_ABORT_UNLESS(m_location_resolvers_enabled.InsertOrAssign(storage_id, true)); + } + + /* Disable any open storages which shouldn't be enabled. */ + m_location_resolvers.ForEach([&](ncm::StorageId storage_id, sf::SharedPointer &resolver) -> void { + /* Check if the storage id is contained in the input array. */ + for (size_t i = 0; i < storages.GetSize(); ++i) { + if (storages[i] == storage_id) { + /* The storage is enabled, so we can return. */ + return; + } + } + + /* The storage isn't enabled, so disable it. */ + R_ABORT_UNLESS(resolver->Disable()); + }); + + R_SUCCEED(); + } + } 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 bdbaad86f..8ae0d8433 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 @@ -158,4 +158,8 @@ namespace ams::lr { R_SUCCEED(); } + Result RedirectOnlyLocationResolverImpl::Disable() { + R_SUCCEED(); + } + } diff --git a/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.hpp index c6de20283..eaa035733 100644 --- a/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.hpp @@ -50,6 +50,7 @@ namespace ams::lr { Result RedirectApplicationProgramPathForDebugDeprecated(const Path &path, ncm::ProgramId id); Result RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id); Result EraseProgramRedirectionForDebug(ncm::ProgramId id); + Result Disable(); }; static_assert(lr::IsILocationResolver); diff --git a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp index dd7dcfc40..c6120c07f 100644 --- a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp @@ -154,6 +154,11 @@ namespace ams::lr { AMS_UNUSED(id); AMS_ABORT(); } + + Result Disable() { + /* TODO: libnx bindings */ + AMS_ABORT(); + } }; static_assert(lr::IsILocationResolver); #endif diff --git a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp index 0965dae33..a543e71ef 100644 --- a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp @@ -54,6 +54,11 @@ namespace ams::lr { AMS_UNUSED(out); AMS_ABORT("TODO: libnx binding"); } + + Result SetEnabled(const sf::InMapAliasArray &storages) { + AMS_UNUSED(storages); + AMS_ABORT("TODO: libnx binding"); + } }; static_assert(lr::IsILocationResolverManager); #endif diff --git a/libraries/libvapours/include/vapours/util/util_bounded_map.hpp b/libraries/libvapours/include/vapours/util/util_bounded_map.hpp index f09052319..ea57ee788 100644 --- a/libraries/libvapours/include/vapours/util/util_bounded_map.hpp +++ b/libraries/libvapours/include/vapours/util/util_bounded_map.hpp @@ -125,6 +125,15 @@ namespace ams::util { return false; } + + template + void ForEach(F f) { + for (size_t i = 0; i < N; ++i) { + if (m_keys[i]) { + f(m_keys[i].value(), GetReference(m_values[i])); + } + } + } }; }