ncm: first pass at ContentManagerImpl refactor (missing the IntegratedImpls, won't link)

This commit is contained in:
Michael Scire 2023-02-22 13:59:05 -07:00
parent ad3da922ef
commit 3cb3b24b4a
9 changed files with 1190 additions and 364 deletions

View file

@ -279,6 +279,23 @@ namespace ams::kvdb {
R_SUCCEED();
}
Result InitializeForReadOnlyArchiveFile(const char *path, size_t capacity, MemoryResource *mr) {
/* Ensure that the passed path is a directory. */
fs::DirectoryEntryType entry_type;
R_TRY(fs::GetEntryType(std::addressof(entry_type), path));
R_UNLESS(entry_type == fs::DirectoryEntryType_File, fs::ResultPathNotFound());
/* Set paths. */
m_path.Assign(path);
m_temp_path.Assign("");
/* Initialize our index. */
R_TRY(m_index.Initialize(capacity, mr));
m_memory_resource = mr;
R_SUCCEED();
}
Result Initialize(size_t capacity, MemoryResource *mr) {
/* This initializes without an archive file. */
/* A store initialized this way cannot have its contents loaded from or flushed to disk. */

View file

@ -21,9 +21,10 @@ namespace ams::ncm {
struct ContentManagerConfig {
bool build_system_database;
bool import_database_from_system_on_sd;
bool enable_integrated_system_content;
bool HasAnyConfig() const {
return this->ShouldBuildDatabase() || this->import_database_from_system_on_sd;
return this->ShouldBuildDatabase() || this->import_database_from_system_on_sd || this->enable_integrated_system_content;
}
bool ShouldBuildDatabase() const {
@ -33,6 +34,10 @@ namespace ams::ncm {
bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const {
return this->import_database_from_system_on_sd;
}
bool IsIntegratedSystemContentEnabled() const {
return this->enable_integrated_system_content;
}
};
}

View file

@ -27,6 +27,8 @@
#include <stratosphere/ncm/ncm_content_management_utils.hpp>
#include <stratosphere/ncm/ncm_content_meta_utils.hpp>
#include <stratosphere/ncm/ncm_registered_host_content.hpp>
#include <stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp>
#include <stratosphere/ncm/ncm_integrated_content_storage_impl.hpp>
#include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp>
namespace ams::ncm {
@ -69,10 +71,29 @@ namespace ams::ncm {
};
static_assert(util::is_pod<SystemSaveDataInfo>::value);
struct IntegratedContentStorageImpl;
class ContentManagerImpl {
private:
constexpr static size_t MaxContentStorageRoots = 8;
constexpr static size_t MaxContentMetaDatabaseRoots = 8;
constexpr static size_t MaxContentStorageRoots = 8;
constexpr static size_t MaxIntegratedContentStorageRoots = 8;
constexpr static size_t MaxContentMetaDatabaseRoots = 8;
constexpr static size_t MaxIntegratedContentMetaDatabaseRoots = 8;
constexpr static size_t MaxConfigs = 8;
constexpr static size_t MaxIntegratedConfigs = 8;
private:
struct ContentStorageConfig {
fs::ContentStorageId content_storage_id;
bool skip_verify_and_create;
bool skip_activate;
};
struct IntegratedContentStorageConfig {
ncm::StorageId storage_id;
fs::ContentStorageId content_storage_ids[MaxContentStorageRoots];
int num_content_storage_ids;
bool is_integrated;
};
private:
struct ContentStorageRoot {
NON_COPYABLE(ContentStorageRoot);
@ -81,10 +102,42 @@ namespace ams::ncm {
char mount_name[fs::MountNameLengthMax + 1];
char path[128];
StorageId storage_id;
fs::ContentStorageId content_storage_id;
util::optional<ContentStorageConfig> config;
sf::SharedPointer<IContentStorage> content_storage;
ContentStorageRoot() : mount_name(), path(), storage_id(), content_storage_id(), content_storage() { /* ... */ }
ContentStorageRoot() : mount_name(), path(), storage_id(), config(util::nullopt), content_storage() { /* ... */ }
};
struct IntegratedContentStorageRoot {
NON_COPYABLE(IntegratedContentStorageRoot);
NON_MOVEABLE(IntegratedContentStorageRoot);
const IntegratedContentStorageConfig *m_config;
ContentStorageRoot *m_roots;
int m_num_roots;
sf::EmplacedRef<IContentStorage, IntegratedContentStorageImpl> m_integrated_content_storage;
IntegratedContentStorageRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_storage() { /* ... */ }
Result Create();
Result Verify();
Result Open(sf::Out<sf::SharedPointer<IContentStorage>> out, RightsIdCache &rights_id_cache, RegisteredHostContent &registered_host_content);
Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent &registered_host_content);
Result Inactivate(RegisteredHostContent &registered_host_content);
Result Activate(ContentStorageRoot &root, RightsIdCache &rights_id_cache, RegisteredHostContent &registered_host_content);
Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent &registered_host_content, fs::ContentStorageId content_storage_id);
ContentStorageRoot *GetRoot(fs::ContentStorageId storage_id) {
for (auto i = 0; i < m_num_roots; ++i) {
if (auto &root = m_roots[i]; root.config.has_value() && root.config->content_storage_id == storage_id) {
return std::addressof(root);
}
}
return nullptr;
}
};
struct ContentMetaDatabaseRoot {
@ -94,46 +147,100 @@ namespace ams::ncm {
char mount_name[fs::MountNameLengthMax + 1];
char path[128];
StorageId storage_id;
SystemSaveDataInfo info;
sf::SharedPointer<IContentMetaDatabase> content_meta_database;
util::optional<ContentStorageConfig> storage_config;
util::optional<SystemSaveDataInfo> save_data_info;
util::optional<kvdb::MemoryKeyValueStore<ContentMetaKey>> kvs;
sf::SharedPointer<IContentMetaDatabase> content_meta_database;
ContentMetaMemoryResource *memory_resource;
u32 max_content_metas;
ContentMetaDatabaseRoot() : mount_name(), path(), storage_id(), info(), content_meta_database(), kvs(util::nullopt), memory_resource(), max_content_metas() { /* ... */ }
ContentMetaDatabaseRoot() : mount_name(), path(), storage_id(), storage_config(util::nullopt), save_data_info(util::nullopt), kvs(util::nullopt), content_meta_database(), memory_resource(), max_content_metas() { /* ... */ }
};
struct IntegratedContentMetaDatabaseRoot {
NON_COPYABLE(IntegratedContentMetaDatabaseRoot);
NON_MOVEABLE(IntegratedContentMetaDatabaseRoot);
const IntegratedContentStorageConfig *m_config;
ContentMetaDatabaseRoot *m_roots;
int m_num_roots;
sf::EmplacedRef<IContentMetaDatabase, IntegratedContentMetaDatabaseImpl> m_integrated_content_meta_database;
IntegratedContentMetaDatabaseRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_meta_database() { /* ... */ }
Result Create();
Result Verify();
Result Open(sf::Out<sf::SharedPointer<IContentMetaDatabase>> out);
Result Cleanup();
Result Activate();
Result Inactivate();
Result Activate(ContentMetaDatabaseRoot &root);
Result Activate(fs::ContentStorageId content_storage_id);
ContentMetaDatabaseRoot *GetRoot(fs::ContentStorageId storage_id) {
for (auto i = 0; i < m_num_roots; ++i) {
if (auto &root = m_roots[i]; root.storage_config.has_value() && root.storage_config->content_storage_id == storage_id) {
return std::addressof(root);
}
}
return nullptr;
}
};
private:
os::SdkRecursiveMutex m_mutex;
bool m_initialized;
ContentStorageRoot m_content_storage_roots[MaxContentStorageRoots];
ContentMetaDatabaseRoot m_content_meta_database_roots[MaxContentMetaDatabaseRoots];
u32 m_num_content_storage_entries;
u32 m_num_content_meta_entries;
RightsIdCache m_rights_id_cache;
RegisteredHostContent m_registered_host_content;
os::SdkRecursiveMutex m_mutex{};
bool m_initialized{false};
IntegratedContentStorageRoot m_integrated_content_storage_roots[MaxIntegratedContentStorageRoots]{};
ContentStorageRoot m_content_storage_roots[MaxContentStorageRoots]{};
IntegratedContentMetaDatabaseRoot m_integrated_content_meta_database_roots[MaxIntegratedContentMetaDatabaseRoots]{};
ContentMetaDatabaseRoot m_content_meta_database_roots[MaxContentMetaDatabaseRoots]{};
IntegratedContentStorageConfig m_integrated_configs[MaxIntegratedConfigs]{};
ContentStorageConfig m_configs[MaxConfigs]{};
u32 m_num_integrated_content_storage_entries{0};
u32 m_num_content_storage_entries{0};
u32 m_num_integrated_content_meta_entries{0};
u32 m_num_content_meta_entries{0};
u32 m_num_integrated_configs{0};
u32 m_num_configs{0};
RightsIdCache m_rights_id_cache{};
RegisteredHostContent m_registered_host_content{};
public:
ContentManagerImpl() : m_mutex(), m_initialized(false), m_content_storage_roots(), m_content_meta_database_roots(), m_num_content_storage_entries(0), m_num_content_meta_entries(0), m_rights_id_cache(), m_registered_host_content() {
/* ... */
};
ContentManagerImpl() = default;
~ContentManagerImpl();
public:
Result Initialize(const ContentManagerConfig &config);
private:
Result Initialize(const ContentManagerConfig &manager_config, const IntegratedContentStorageConfig *integrated_configs, size_t num_integrated_configs, const ContentStorageConfig *configs, size_t num_configs, const ncm::StorageId *activated_storages, size_t num_activated_storages);
Result InitializeStorageBuiltInSystem(const ContentManagerConfig &manager_config);
Result InitializeStorage(ncm::StorageId storage_id);
const ContentStorageConfig &GetContentStorageConfig(fs::ContentStorageId content_storage_id) {
for (size_t i = 0; i < m_num_configs; ++i) {
if (m_configs[i].content_storage_id == content_storage_id) {
return m_configs[i];
}
}
/* NOTE: Nintendo accesses out of bounds memory here. Should we explicitly abort? This is guaranteed by data to never happen. */
AMS_ASSUME(false);
}
private:
/* Helpers. */
Result GetContentStorageRoot(ContentStorageRoot **out, StorageId id);
Result GetContentMetaDatabaseRoot(ContentMetaDatabaseRoot **out, StorageId id);
Result GetIntegratedContentStorageConfig(IntegratedContentStorageConfig **out, fs::ContentStorageId content_storage_id);
Result GetIntegratedContentStorageRoot(IntegratedContentStorageRoot **out, StorageId id);
Result GetIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot **out, StorageId id);
Result InitializeContentStorageRoot(ContentStorageRoot *out, StorageId storage_id, fs::ContentStorageId content_storage_id);
Result InitializeGameCardContentStorageRoot(ContentStorageRoot *out);
Result InitializeContentStorageRoot(ContentStorageRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> config);
Result InitializeContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> storage_config);
Result InitializeContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, StorageId storage_id, const SystemSaveDataInfo &info, size_t max_content_metas, ContentMetaMemoryResource *mr);
Result InitializeGameCardContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, size_t max_content_metas, ContentMetaMemoryResource *mr);
Result InitializeIntegratedContentStorageRoot(IntegratedContentStorageRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count);
Result InitializeIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count);
Result BuildContentMetaDatabase(StorageId storage_id);
Result ImportContentMetaDatabase(StorageId storage_id, bool from_signed_partition);
Result ImportContentMetaDatabaseImpl(StorageId storage_id, const char *import_mount_name, const char *path);
Result EnsureAndMountSystemSaveData(const char *mount, const SystemSaveDataInfo &info) const;
Result ImportContentMetaDatabaseImpl(ContentMetaDatabaseRoot *root, const char *import_mount_name);
public:
/* Actual commands. */
Result CreateContentStorage(StorageId storage_id);

View file

@ -0,0 +1,77 @@
/*
* 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 <stratosphere.hpp>
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_integrated_list.hpp>
namespace ams::ncm {
class IntegratedContentMetaDatabaseImpl {
NON_COPYABLE(IntegratedContentMetaDatabaseImpl);
NON_MOVEABLE(IntegratedContentMetaDatabaseImpl);
private:
using ListType = ncm::IntegratedList<ncm::IContentMetaDatabase, 2>;
using DataType = ListType::ListData;
private:
os::SdkMutex m_mutex;
ListType m_list;
bool m_disabled;
public:
IntegratedContentMetaDatabaseImpl() : m_mutex(), m_list(), m_disabled(false) { /* ... */ }
void Add(sf::SharedPointer<ncm::IContentMetaDatabase> p, u8 id) {
DataType data = {std::move(p), id};
m_list.Add(data);
}
private:
/* Helpers. */
Result EnsureEnabled() const {
R_UNLESS(!m_disabled, ncm::ResultInvalidContentMetaDatabase());
R_SUCCEED();
}
public:
/* Actual commands. */
Result Set(const ContentMetaKey &key, const sf::InBuffer &value);
Result Get(sf::Out<u64> out_size, const ContentMetaKey &key, const sf::OutBuffer &out_value);
Result Remove(const ContentMetaKey &key);
Result GetContentIdByType(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type);
Result ListContentInfo(sf::Out<s32> out_entries_written, const sf::OutArray<ContentInfo> &out_info, const ContentMetaKey &key, s32 offset);
Result List(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaKey> &out_info, ContentMetaType meta_type, ApplicationId application_id, u64 min, u64 max, ContentInstallType install_type);
Result GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, u64 id);
Result ListApplication(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ApplicationContentMetaKey> &out_keys, ContentMetaType meta_type);
Result Has(sf::Out<bool> out, const ContentMetaKey &key);
Result HasAll(sf::Out<bool> out, const sf::InArray<ContentMetaKey> &keys);
Result GetSize(sf::Out<u64> out_size, const ContentMetaKey &key);
Result GetRequiredSystemVersion(sf::Out<u32> out_version, const ContentMetaKey &key);
Result GetPatchContentMetaId(sf::Out<u64> out_patch_id, const ContentMetaKey &key);
Result DisableForcibly();
Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids);
Result Commit();
Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id);
Result ListContentMetaInfo(sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaInfo> &out_meta_info, const ContentMetaKey &key, s32 offset);
Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key);
Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key);
Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset);
Result GetCount(sf::Out<u32> out_count);
Result GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key);
Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key);
Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type);
Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset);
};
static_assert(ncm::IsIContentMetaDatabase<IntegratedContentMetaDatabaseImpl>);
}

View file

@ -0,0 +1,86 @@
/*
* 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 <stratosphere.hpp>
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
#include <stratosphere/ncm/ncm_integrated_list.hpp>
namespace ams::ncm {
class IntegratedContentStorageImpl {
NON_COPYABLE(IntegratedContentStorageImpl);
NON_MOVEABLE(IntegratedContentStorageImpl);
private:
using ListType = ncm::IntegratedList<ncm::IContentStorage, 2>;
using DataType = ListType::ListData;
private:
os::SdkMutex m_mutex;
ListType m_list;
bool m_disabled;
public:
IntegratedContentStorageImpl() : m_mutex(), m_list(), m_disabled(false) { /* ... */ }
void Add(sf::SharedPointer<ncm::IContentStorage> p, u8 id) {
DataType data = {std::move(p), id};
m_list.Add(data);
}
private:
/* Helpers. */
Result EnsureEnabled() const {
R_UNLESS(!m_disabled, ncm::ResultInvalidContentStorage());
R_SUCCEED();
}
public:
/* Actual commands. */
Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out);
Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size);
Result DeletePlaceHolder(PlaceHolderId placeholder_id);
Result HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id);
Result WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data);
Result Register(PlaceHolderId placeholder_id, ContentId content_id);
Result Delete(ContentId content_id);
Result Has(sf::Out<bool> out, ContentId content_id);
Result GetPath(sf::Out<Path> out, ContentId content_id);
Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id);
Result CleanupAllPlaceHolder();
Result ListPlaceHolder(sf::Out<s32> out_count, const sf::OutArray<PlaceHolderId> &out_buf);
Result GetContentCount(sf::Out<s32> out_count);
Result ListContentId(sf::Out<s32> out_count, const sf::OutArray<ContentId> &out_buf, s32 start_offset);
Result GetSizeFromContentId(sf::Out<s64> out_size, ContentId content_id);
Result DisableForcibly();
Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id);
Result SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size);
Result ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset);
Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id);
Result GetRightsIdFromPlaceHolderIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id);
Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr);
Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id);
Result GetRightsIdFromContentIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id);
Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id, fs::ContentAttributes attr);
Result WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data);
Result GetFreeSpaceSize(sf::Out<s64> out_size);
Result GetTotalSpaceSize(sf::Out<s64> out_size);
Result FlushPlaceHolder();
Result GetSizeFromPlaceHolderId(sf::Out<s64> out, PlaceHolderId placeholder_id);
Result RepairInvalidFileAttribute();
Result GetRightsIdFromPlaceHolderIdWithCacheDeprecated(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id);
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
Result RegisterPath(const ContentId &content_id, const Path &path);
Result ClearRegisteredPath();
};
static_assert(ncm::IsIContentStorage<IntegratedContentStorageImpl>);
}

View file

@ -0,0 +1,82 @@
/*
* 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/sf/sf_shared_object.hpp>
namespace ams::ncm {
template<typename T, size_t N>
class IntegratedList {
static_assert(N <= std::numeric_limits<u8>::max());
public:
struct ListData {
sf::SharedPointer<T> interface;
u8 id;
};
private:
size_t m_count;
sf::SharedPointer<T> m_interfaces[N];
u8 m_ids[N];
public:
IntegratedList() : m_count(0), m_interfaces(), m_ids() { /* ... */ }
void Add(ListData &data) {
/* Find place to insert into the list. */
const size_t pos = std::distance(std::begin(m_ids), std::lower_bound(std::begin(m_ids), std::end(m_ids), data.id));
/* If we need to, move stuff to make space. */
if (m_ids[pos] > data.id) {
AMS_ABORT_UNLESS(m_count < N);
for (size_t i = m_count; i > pos; --i) {
m_ids[i] = std::move(m_ids[i - 1]);
m_interfaces[i] = std::move(m_interfaces[i - 1]);
}
/* If we're inserting somewhere in the middle, increment count. */
m_count++;
} else if (m_ids[pos] < data.id) {
/* If we're inserting at the end, increment count. */
AMS_ABORT_UNLESS(m_count < N);
m_count++;
}
/* Set at position. */
m_interfaces[pos] = data.interface;
m_ids[pos] = data.id;
}
ListData Get(size_t idx) {
AMS_ABORT_UNLESS(idx < m_count);
return { m_interfaces[idx], m_ids[idx] };
}
Result TryEach(auto callback) {
Result result = ResultSuccess();
for (size_t i = 0; i < m_count; ++i) {
result = callback(this->Get(i));
if (R_SUCCEEDED(result)) {
break;
}
}
R_RETURN(result);
}
};
}

View file

@ -20,6 +20,7 @@ namespace ams::ncm {
constexpr inline s32 SystemMaxContentMetaCount = 0x800;
constexpr inline s32 GameCardMaxContentMetaCount = 0x800;
constexpr inline s32 HostMaxContentMetaCount = 0x800;
constexpr inline s32 UserMaxContentMetaCount = 0x2000;
constexpr inline s32 SdCardMaxContentMetaCount = 0x2000;

View file

@ -42,41 +42,41 @@ namespace ams::ncm {
HostContentStorageImpl(RegisteredHostContent *registered_content) : m_registered_content(registered_content), m_disabled(false) { /* ... */ }
public:
/* Actual commands. */
virtual Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out);
virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size);
virtual Result DeletePlaceHolder(PlaceHolderId placeholder_id);
virtual Result HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id);
virtual Result WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data);
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id);
virtual Result Delete(ContentId content_id);
virtual Result Has(sf::Out<bool> out, ContentId content_id);
virtual Result GetPath(sf::Out<Path> out, ContentId content_id);
virtual Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id);
virtual Result CleanupAllPlaceHolder();
virtual Result ListPlaceHolder(sf::Out<s32> out_count, const sf::OutArray<PlaceHolderId> &out_buf);
virtual Result GetContentCount(sf::Out<s32> out_count);
virtual Result ListContentId(sf::Out<s32> out_count, const sf::OutArray<ContentId> &out_buf, s32 start_offset);
virtual Result GetSizeFromContentId(sf::Out<s64> out_size, ContentId content_id);
virtual Result DisableForcibly();
virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id);
virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size);
virtual Result ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset);
virtual Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id);
virtual Result GetRightsIdFromPlaceHolderIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id);
virtual Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr);
virtual Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id);
virtual Result GetRightsIdFromContentIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id);
virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id, fs::ContentAttributes attr);
virtual Result WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data);
virtual Result GetFreeSpaceSize(sf::Out<s64> out_size);
virtual Result GetTotalSpaceSize(sf::Out<s64> out_size);
virtual Result FlushPlaceHolder();
virtual Result GetSizeFromPlaceHolderId(sf::Out<s64> out, PlaceHolderId placeholder_id);
virtual Result RepairInvalidFileAttribute();
virtual Result GetRightsIdFromPlaceHolderIdWithCacheDeprecated(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id);
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
virtual Result RegisterPath(const ContentId &content_id, const Path &path);
virtual Result ClearRegisteredPath();
Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out);
Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size);
Result DeletePlaceHolder(PlaceHolderId placeholder_id);
Result HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id);
Result WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data);
Result Register(PlaceHolderId placeholder_id, ContentId content_id);
Result Delete(ContentId content_id);
Result Has(sf::Out<bool> out, ContentId content_id);
Result GetPath(sf::Out<Path> out, ContentId content_id);
Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id);
Result CleanupAllPlaceHolder();
Result ListPlaceHolder(sf::Out<s32> out_count, const sf::OutArray<PlaceHolderId> &out_buf);
Result GetContentCount(sf::Out<s32> out_count);
Result ListContentId(sf::Out<s32> out_count, const sf::OutArray<ContentId> &out_buf, s32 start_offset);
Result GetSizeFromContentId(sf::Out<s64> out_size, ContentId content_id);
Result DisableForcibly();
Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id);
Result SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size);
Result ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset);
Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id);
Result GetRightsIdFromPlaceHolderIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id);
Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr);
Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id);
Result GetRightsIdFromContentIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id);
Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id, fs::ContentAttributes attr);
Result WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data);
Result GetFreeSpaceSize(sf::Out<s64> out_size);
Result GetTotalSpaceSize(sf::Out<s64> out_size);
Result FlushPlaceHolder();
Result GetSizeFromPlaceHolderId(sf::Out<s64> out, PlaceHolderId placeholder_id);
Result RepairInvalidFileAttribute();
Result GetRightsIdFromPlaceHolderIdWithCacheDeprecated(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id);
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
Result RegisterPath(const ContentId &content_id, const Path &path);
Result ClearRegisteredPath();
};
static_assert(ncm::IsIContentStorage<HostContentStorageImpl>);