ncm: update for new add on content/attr changes

This commit is contained in:
Michael Scire 2022-10-11 15:09:11 -07:00 committed by SciresM
parent ef07964ea0
commit 427130a122
14 changed files with 290 additions and 143 deletions

View file

@ -17,12 +17,16 @@
#pragma once
#include <stratosphere/lr/lr_types.hpp>
#define AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveAddOnContentPath, (sf::Out<lr::Path> 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<ncm::ApplicationId> &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<lr::Path> 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<ncm::ApplicationId> &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<lr::Path> out, sf::Out<lr::Path> 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)

View file

@ -21,7 +21,6 @@
#include <stratosphere/ncm/ncm_program_location.hpp>
#include <stratosphere/ncm/ncm_auto_buffer.hpp>
#include <stratosphere/ncm/ncm_make_path.hpp>
#include <stratosphere/ncm/ncm_content_attributes.hpp>
#include <stratosphere/ncm/ncm_content_id_utils.hpp>
#include <stratosphere/ncm/ncm_content_info_utils.hpp>
#include <stratosphere/ncm/ncm_content_meta.hpp>

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/fs/fs_content_attributes.hpp>
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<ContentAttributes>::value);
static_assert(sizeof(ContentAttributes) == 0x10);
constexpr inline const ContentAttributes DefaultContentAttributes = ContentAttributes::Make(fs::ContentAttributes_None);
}

View file

@ -18,28 +18,60 @@
namespace ams::lr {
Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out<Path> 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<size_t N>
Result ResolveAddOnContentPathImpl(Path *out, RedirectionAttributes *out_attr, const RegisteredStorages<ncm::DataId, N> &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<ncm::Path *>(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<ncm::Path *>(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<Path> 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<ncm::ApplicationId> &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<const ncm::ProgramId *>(ids.GetPointer()), ids.GetSize());
}
/* Clear all registered storages excluding the provided program ids. */
m_registered_storages.ClearExcluding(reinterpret_cast<const ncm::ProgramId *>(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<Path> out, sf::Out<Path> 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();
}

View file

@ -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<ncm::DataId, 0x800> m_registered_storages;
ncm::BoundedMap<ncm::DataId, OwnedPath, 8> m_registered_paths;
ncm::BoundedMap<ncm::DataId, OwnedPath, 8> 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<Path> out, ncm::DataId id);
@ -46,6 +53,13 @@ namespace ams::lr {
Result UnregisterAllAddOnContentPath();
Result RefreshApplicationAddOnContent(const sf::InArray<ncm::ApplicationId> &ids);
Result UnregisterApplicationAddOnContent(ncm::ApplicationId id);
Result GetRegisteredAddOnContentPaths(sf::Out<Path> out, sf::Out<Path> 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<AddOnContentLocationResolverImpl>);

View file

@ -28,37 +28,45 @@ namespace ams::lr {
m_content_storage.GetPath(reinterpret_cast<ncm::Path *>(out), content_id);
}
Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out<Path> 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<Path> 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<Path> 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<Path> 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<Path> 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<Path> 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();
}

View file

@ -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<Path> out, ncm::ProgramId id);

View file

@ -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) {

View file

@ -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<RedirectionAttributes>::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<RedirectionPath>::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);

View file

@ -24,22 +24,25 @@ namespace ams::lr {
}
Result RedirectOnlyLocationResolverImpl::ResolveProgramPath(sf::Out<Path> 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<Path> 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<Path> 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<Path> 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<Path> 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();
}

View file

@ -16,6 +16,7 @@
#pragma once
#include <stratosphere/lr/lr_types.hpp>
#include "lr_location_redirector.hpp"
namespace ams::lr {
@ -137,7 +138,7 @@ namespace ams::lr {
};
template<typename Key, size_t NumEntries>
using RegisteredLocations = RegisteredData<Key, lr::Path, NumEntries>;
using RegisteredLocations = RegisteredData<Key, RedirectionPath, NumEntries>;
template<typename Key, size_t NumEntries>
using RegisteredStorages = RegisteredData<Key, ncm::StorageId, NumEntries>;

View file

@ -23,25 +23,33 @@ namespace ams::lr {
template<size_t N>
bool ResolvePath(Path *out, const LocationRedirector &redirector, const RegisteredLocations<ncm::ProgramId, N> &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<size_t N>
void RegisterPath(RegisteredLocations<ncm::ProgramId, N> &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();
}

View file

@ -32,4 +32,6 @@ namespace ams::lr {
R_DEFINE_ERROR_RESULT(TooManyRegisteredPaths, 90);
R_DEFINE_ERROR_RESULT(InvalidPath, 140);
}

View file

@ -134,6 +134,15 @@ namespace ams::util {
}
}
}
template<typename F>
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);
}
}
}
};
}