ncm: client-side api

This commit is contained in:
Michael Scire 2020-03-03 03:47:58 -08:00
parent d40d2006e9
commit 7576ab3ab0
27 changed files with 1241 additions and 126 deletions

View file

@ -18,5 +18,6 @@
#include "ncm/ncm_types.hpp"
#include "ncm/ncm_content_meta.hpp"
#include "ncm/ncm_i_content_meta_database.hpp"
#include "ncm/ncm_i_content_storage.hpp"
#include "ncm/ncm_content_meta_database.hpp"
#include "ncm/ncm_content_storage.hpp"
#include "ncm/ncm_api.hpp"

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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/ncm/ncm_types.hpp>
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_content_storage.hpp>
#include <stratosphere/ncm/ncm_i_content_manager.hpp>
namespace ams::ncm {
/* Management. */
void Initialize();
void Finalize();
void InitializeWithObject(std::shared_ptr<IContentManager> manager_object);
/* Service API. */
Result CreateContentStorage(StorageId storage_id);
Result CreateContentMetaDatabase(StorageId storage_id);
Result VerifyContentStorage(StorageId storage_id);
Result VerifyContentMetaDatabase(StorageId storage_id);
Result OpenContentStorage(ContentStorage *out, StorageId storage_id);
Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id);
Result CleanupContentMetaDatabase(StorageId storage_id);
Result ActivateContentStorage(StorageId storage_id);
Result InactivateContentStorage(StorageId storage_id);
Result ActivateContentMetaDatabase(StorageId storage_id);
Result InactivateContentMetaDatabase(StorageId storage_id);
Result InvalidateRightsIdCache();
/* Deprecated API. */
Result CloseContentStorageForcibly(StorageId storage_id);
Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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/ncm/ncm_types.hpp>
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
namespace ams::ncm {
class ContentMetaDatabase {
NON_COPYABLE(ContentMetaDatabase);
public:
struct ListCount {
u32 written;
u32 total;
};
private:
std::shared_ptr<IContentMetaDatabase> interface;
public:
ContentMetaDatabase() { /* ... */ }
explicit ContentMetaDatabase(std::shared_ptr<IContentMetaDatabase> intf) : interface(std::move(intf)) { /* ... */ }
ContentMetaDatabase(ContentMetaDatabase &&rhs) {
this->interface = std::move(rhs.interface);
}
ContentMetaDatabase &operator=(ContentMetaDatabase &&rhs) {
ContentMetaDatabase(std::move(rhs)).Swap(*this);
return *this;
}
void Swap(ContentMetaDatabase &rhs) {
std::swap(this->interface, rhs.interface);
}
public:
Result Set(const ContentMetaKey &key, const void *buf, size_t size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Set(key, sf::InBuffer(buf, size));
}
Result Get(size_t *out_size, void *dst, size_t dst_size, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
u64 size;
R_TRY(this->interface->Get(std::addressof(size), key, sf::OutBuffer(dst, dst_size)));
*out_size = size;
return ResultSuccess();
}
/* TODO: Proper ProgramId vs DataId vs ApplicationId for Get */
#define AMS_NCM_DEFINE_GETTERS(Kind) \
Result Get##Kind(ContentId *out, ProgramId id, u32 version) { \
return this->interface->GetContentIdByType(out, ContentMetaKey::MakeUnknownType(id, version), ContentType::Kind); \
} \
\
Result GetLatest##Kind(ContentId *out, ProgramId id) { \
ContentMetaKey latest_key; \
R_TRY(this->interface->GetLatestContentMetaKey(std::addressof(latest_key), id)); \
return this->interface->GetContentIdByType(out, latest_key, ContentType::Kind); \
}
AMS_NCM_DEFINE_GETTERS(Program)
AMS_NCM_DEFINE_GETTERS(Data)
AMS_NCM_DEFINE_GETTERS(Control)
AMS_NCM_DEFINE_GETTERS(HtmlDocument)
AMS_NCM_DEFINE_GETTERS(LegalInformation)
#undef AMS_NCM_DEFINE_GETTERS
/* TODO: Remove(SystemProgramId) Remove(SystemDataId) Remove(ProgramId) */
Result Remove(const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Remove(key);
}
Result GetContentIdByType(ContentId *out_content_id, const ContentMetaKey &key, ContentType type) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetContentIdByType(out_content_id, key, type);
}
Result GetContentIdByTypeAndIdOffset(ContentId *out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetContentIdByTypeAndIdOffset(out_content_id, key, type, id_offset);
}
ListCount ListApplication(ApplicationContentMetaKey *dst, size_t dst_size) {
ListCount lc = {};
R_ABORT_UNLESS(this->interface->ListApplication(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray<ApplicationContentMetaKey>(dst, dst_size), ContentMetaType::Unknown));
return lc;
}
ListCount ListContentMeta(ContentMetaKey *dst, size_t dst_size, ContentMetaType type, ProgramId app_id, ProgramId min, ProgramId max, ContentInstallType install_type) {
ListCount lc = {};
R_ABORT_UNLESS(this->interface->List(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray<ContentMetaKey>(dst, dst_size), type, app_id, min, max, install_type));
return lc;
}
Result GetLatest(ContentMetaKey *out_key, ProgramId id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetLatestContentMetaKey(out_key, id);
}
Result ListContentInfo(u32 *out_count, ContentInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->ListContentInfo(out_count, sf::OutArray<ContentInfo>(dst, dst_size), key, offset);
}
Result ListContentMetaInfo(u32 *out_count, ContentMetaInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->ListContentMetaInfo(out_count, sf::OutArray<ContentMetaInfo>(dst, dst_size), key, offset);
}
Result Has(bool *out, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Has(out, key);
}
Result HasAll(bool *out, const ContentMetaKey *keys, size_t num_keys) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->HasAll(out, sf::InArray<ContentMetaKey>(keys, num_keys));
}
Result HasContent(bool *out, const ContentMetaKey &key, const ContentId &content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->HasContent(out, key, content_id);
}
Result GetSize(size_t *out_size, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
u64 size;
R_TRY(this->interface->GetSize(std::addressof(size), key));
*out_size = size;
return ResultSuccess();
}
Result GetRequiredSystemVersion(u32 *out_version, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetRequiredSystemVersion(out_version, key);
}
Result GetPatchId(ProgramId *out_patch_id, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetPatchId(out_patch_id, key);
}
Result DisableForcibly() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->DisableForcibly();
}
Result LookupOrphanContent(bool *out_orphaned, ContentId *content_list, size_t count) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->LookupOrphanContent(sf::OutArray<bool>(out_orphaned, count), sf::InArray<ContentId>(content_list, count));
}
Result Commit() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Commit();
}
Result GetAttributes(ContentMetaAttribute *out_attributes, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetAttributes(out_attributes, key);
}
Result GetRequiredApplicationVersion(u32 *out_version, const ContentMetaKey &key) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetRequiredApplicationVersion(out_version, key);
}
};
}

View file

@ -0,0 +1,202 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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/ncm/ncm_types.hpp>
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
namespace ams::ncm {
class ContentStorage {
NON_COPYABLE(ContentStorage);
private:
std::shared_ptr<IContentStorage> interface;
public:
ContentStorage() { /* ... */ }
explicit ContentStorage(std::shared_ptr<IContentStorage> intf) : interface(std::move(intf)) { /* ... */ }
ContentStorage(ContentStorage &&rhs) {
this->interface = std::move(rhs.interface);
}
ContentStorage &operator=(ContentStorage &&rhs) {
ContentStorage(std::move(rhs)).Swap(*this);
return *this;
}
void Swap(ContentStorage &rhs) {
std::swap(this->interface, rhs.interface);
}
public:
PlaceHolderId GeneratePlaceHolderId() {
AMS_ASSERT(this->interface != nullptr);
PlaceHolderId id;
R_ABORT_UNLESS(this->interface->GeneratePlaceHolderId(std::addressof(id)));
return id;
}
Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->CreatePlaceHolder(placeholder_id, content_id, size);
}
Result DeletePlaceHolder(PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->DeletePlaceHolder(placeholder_id);
}
Result HasPlaceHolder(bool *out, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->HasPlaceHolder(out, placeholder_id);
}
Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, const void *buf, size_t size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->WritePlaceHolder(placeholder_id, offset, sf::InBuffer(buf, size));
}
Result Register(PlaceHolderId placeholder_id, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Register(placeholder_id, content_id);
}
Result Delete(ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Delete(content_id);
}
Result Has(bool *out, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->Has(out, content_id);
}
void GetPath(Path *out, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
R_ABORT_UNLESS(this->interface->GetPath(out, content_id));
}
void GetPlaceHolderPath(Path *out, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
R_ABORT_UNLESS(this->interface->GetPlaceHolderPath(out, placeholder_id));
}
Result CleanupAllPlaceHolder() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->CleanupAllPlaceHolder();
}
Result ListPlaceHolder(u32 *out_count, PlaceHolderId *out_list, size_t out_list_size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->ListPlaceHolder(out_count, sf::OutArray<PlaceHolderId>(out_list, out_list_size));
}
Result GetContentCount(u32 *out_count) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetContentCount(out_count);
}
Result ListContentId(u32 *out_count, ContentId *out_list, size_t out_list_size, u32 offset) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->ListContentId(out_count, sf::OutArray<ContentId>(out_list, out_list_size), offset);
}
Result GetSize(u64 *out_size, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetSizeFromContentId(out_size, content_id);
}
Result GetSize(u64 *out_size, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetSizeFromPlaceHolderId(out_size, placeholder_id);
}
Result DisableForcibly() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->DisableForcibly();
}
Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->RevertToPlaceHolder(placeholder_id, old_content_id, new_content_id);
}
Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->SetPlaceHolderSize(placeholder_id, size);
}
Result ReadContentIdFile(void *dst, size_t size, ContentId content_id, u64 offset) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->ReadContentIdFile(sf::OutBuffer(dst, size), content_id, offset);
}
Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
return this->interface->GetRightsIdFromPlaceHolderIdDeprecated(out_rights_id, placeholder_id);
}
Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
return this->interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id);
}
Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
return this->interface->GetRightsIdFromContentIdDeprecated(out_rights_id, content_id);
}
Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
return this->interface->GetRightsIdFromContentId(out_rights_id, content_id);
}
Result WriteContentForDebug(ContentId content_id, u64 offset, const void *buf, size_t size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->WriteContentForDebug(content_id, offset, sf::InBuffer(buf, size));
}
Result GetFreeSpaceSize(u64 *out_size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetFreeSpaceSize(out_size);
}
Result GetTotalSpaceSize(u64 *out_size) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetTotalSpaceSize(out_size);
}
Result FlushPlaceHolder() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->FlushPlaceHolder();
}
Result RepairInvalidFileAttribute() {
AMS_ASSERT(this->interface != nullptr);
return this->interface->RepairInvalidFileAttribute();
}
Result GetRightsIdFromPlaceHolderIdWithCache(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
AMS_ASSERT(this->interface != nullptr);
return this->interface->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id);
}
};
}

View file

@ -15,12 +15,12 @@
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
namespace ams::ncm {
class ContentManagerService final : public sf::IServiceObject {
class IContentManager : public sf::IServiceObject {
protected:
enum class CommandId {
CreateContentStorage = 0,
@ -39,20 +39,20 @@ namespace ams::ncm {
InvalidateRightsIdCache = 13,
};
public:
Result CreateContentStorage(StorageId storage_id);
Result CreateContentMetaDatabase(StorageId storage_id);
Result VerifyContentStorage(StorageId storage_id);
Result VerifyContentMetaDatabase(StorageId storage_id);
Result OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id);
Result OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id);
Result CloseContentStorageForcibly(StorageId storage_id);
Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
Result CleanupContentMetaDatabase(StorageId storage_id);
Result ActivateContentStorage(StorageId storage_id);
Result InactivateContentStorage(StorageId storage_id);
Result ActivateContentMetaDatabase(StorageId storage_id);
Result InactivateContentMetaDatabase(StorageId storage_id);
Result InvalidateRightsIdCache();
virtual Result CreateContentStorage(StorageId storage_id) = 0;
virtual Result CreateContentMetaDatabase(StorageId storage_id) = 0;
virtual Result VerifyContentStorage(StorageId storage_id) = 0;
virtual Result VerifyContentMetaDatabase(StorageId storage_id) = 0;
virtual Result OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) = 0;
virtual Result OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) = 0;
virtual Result CloseContentStorageForcibly(StorageId storage_id) = 0;
virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) = 0;
virtual Result CleanupContentMetaDatabase(StorageId storage_id) = 0;
virtual Result ActivateContentStorage(StorageId storage_id) = 0;
virtual Result InactivateContentStorage(StorageId storage_id) = 0;
virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0;
virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0;
virtual Result InvalidateRightsIdCache() = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(CreateContentStorage),

View file

@ -64,7 +64,7 @@ namespace ams::ncm {
virtual Result DisableForcibly() = 0;
virtual Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids) = 0;
virtual Result Commit() = 0;
virtual Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, ContentId content_id) = 0;
virtual Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id) = 0;
virtual Result ListContentMetaInfo(sf::Out<u32> out_entries_written, const sf::OutArray<ContentMetaInfo> &out_meta_info, const ContentMetaKey &key, u32 start_index) = 0;
virtual Result GetAttributes(sf::Out<ContentMetaAttribute> out_attributes, const ContentMetaKey &key) = 0;
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) = 0;

View file

@ -16,6 +16,7 @@
#pragma once
#include <stratosphere/ncm/ncm_types.hpp>
#include <stratosphere/ncm/ncm_path.hpp>
#include <stratosphere/lr/lr_types.hpp>
#include <stratosphere/sf.hpp>
@ -68,8 +69,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) = 0;
virtual Result Delete(ContentId content_id) = 0;
virtual Result Has(sf::Out<bool> out, ContentId content_id) = 0;
virtual Result GetPath(sf::Out<lr::Path> out, ContentId content_id) = 0;
virtual Result GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) = 0;
virtual Result GetPath(sf::Out<Path> out, ContentId content_id) = 0;
virtual Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) = 0;
virtual Result CleanupAllPlaceHolder() = 0;
virtual Result ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) = 0;
virtual Result GetContentCount(sf::Out<u32> out_count) = 0;

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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/ncm/ncm_types.hpp>
#include <stratosphere/fs/fs_directory.hpp>
#include <stratosphere/sf/sf_buffer_tags.hpp>
namespace ams::ncm {
struct alignas(4) Path : ams::sf::LargeData {
char str[fs::EntryNameLengthMax];
static constexpr Path Encode(const char *p) {
Path path = {};
/* Copy C string to path, terminating when a null byte is found. */
for (size_t i = 0; i < sizeof(path) - 1; i++) {
path.str[i] = p[i];
if (p[i] == '\x00') {
break;
}
}
return path;
}
};
}

View file

@ -621,6 +621,10 @@ namespace ams::ncm {
return !(*this == other);
}
static constexpr ContentMetaKey MakeUnknownType(ProgramId program_id, u32 version) {
return { .id = program_id, .version = version, .type = ContentMetaType::Unknown };
}
static constexpr ContentMetaKey Make(ProgramId program_id, u32 version, ContentMetaType type) {
return { .id = program_id, .version = version, .type = type };
}

View file

@ -86,11 +86,13 @@ namespace ams::sf {
cmif::ServiceObjectHolder *srv;
cmif::DomainObjectId *object_id;
public:
Out(cmif::ServiceObjectHolder *s) : srv(s), object_id(nullptr) { /* ... */ }
Out(cmif::ServiceObjectHolder *s, cmif::DomainObjectId *o) : srv(s), object_id(o) { /* ... */ }
void SetValue(std::shared_ptr<ServiceImpl> &&s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) {
*this->srv = cmif::ServiceObjectHolder(std::move(s));
if (new_object_id != cmif::InvalidDomainObjectId) {
AMS_ABORT_UNLESS(object_id != nullptr);
*this->object_id = new_object_id;
}
}

View file

@ -16,14 +16,6 @@
#include <stratosphere.hpp>
#include "lr_add_on_content_location_resolver_impl.hpp"
/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */
namespace ams::ncm::impl {
Result OpenContentMetaDatabase(std::shared_ptr<ncm::IContentMetaDatabase> *, ncm::StorageId);
Result OpenContentStorage(std::shared_ptr<ncm::IContentStorage> *, ncm::StorageId);
}
namespace ams::lr {
Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out<Path> out, ncm::ProgramId id) {
@ -32,19 +24,20 @@ namespace ams::lr {
R_UNLESS(this->registered_storages.Find(&storage_id, id), lr::ResultAddOnContentNotFound());
/* Obtain a Content Meta Database for the storage id. */
std::shared_ptr<ncm::IContentMetaDatabase> content_meta_database;
R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, storage_id));
ncm::ContentMetaDatabase content_meta_database;
R_TRY(ncm::OpenContentMetaDatabase(&content_meta_database, storage_id));
/* Find the latest data content id for the given program id. */
ncm::ContentId data_content_id;
R_TRY(content_meta_database->GetLatestData(&data_content_id, id));
R_TRY(content_meta_database.GetLatestData(&data_content_id, id));
/* Obtain a Content Storage for the storage id. */
std::shared_ptr<ncm::IContentStorage> content_storage;
R_TRY(ncm::impl::OpenContentStorage(&content_storage, storage_id));
ncm::ContentStorage content_storage;
R_TRY(ncm::OpenContentStorage(&content_storage, storage_id));
/* Get the path of the data content. */
R_ABORT_UNLESS(content_storage->GetPath(out.GetPointer(), data_content_id));
static_assert(sizeof(lr::Path) == sizeof(ncm::Path));
content_storage.GetPath(reinterpret_cast<ncm::Path *>(out.GetPointer()), data_content_id);
return ResultSuccess();
}

View file

@ -16,14 +16,6 @@
#include <stratosphere.hpp>
#include "lr_content_location_resolver_impl.hpp"
/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */
namespace ams::ncm::impl {
Result OpenContentMetaDatabase(std::shared_ptr<ncm::IContentMetaDatabase> *, ncm::StorageId);
Result OpenContentStorage(std::shared_ptr<ncm::IContentStorage> *, ncm::StorageId);
}
namespace ams::lr {
ContentLocationResolverImpl::~ContentLocationResolverImpl() {
@ -32,7 +24,8 @@ namespace ams::lr {
/* Helper function. */
void ContentLocationResolverImpl::GetContentStoragePath(Path *out, ncm::ContentId content_id) {
R_ABORT_UNLESS(this->content_storage->GetPath(out, content_id));
static_assert(sizeof(lr::Path) == sizeof(ncm::Path));
this->content_storage.GetPath(reinterpret_cast<ncm::Path *>(out), content_id);
}
Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out<Path> out, ncm::ProgramId id) {
@ -41,7 +34,7 @@ namespace ams::lr {
/* Find the latest program content for the program id. */
ncm::ContentId program_content_id;
R_TRY_CATCH(this->content_meta_database->GetLatestProgram(&program_content_id, id)) {
R_TRY_CATCH(this->content_meta_database.GetLatestProgram(&program_content_id, id)) {
R_CONVERT(ncm::ResultContentMetaNotFound, lr::ResultProgramNotFound())
} R_END_TRY_CATCH;
@ -69,7 +62,7 @@ namespace ams::lr {
Result ContentLocationResolverImpl::ResolveDataPath(sf::Out<Path> out, ncm::ProgramId id) {
/* Find the latest data content for the program id. */
ncm::ContentId data_content_id;
R_TRY(this->content_meta_database->GetLatestData(&data_content_id, id));
R_TRY(this->content_meta_database.GetLatestData(&data_content_id, id));
/* Obtain the content path. */
this->GetContentStoragePath(out.GetPointer(), data_content_id);
@ -114,14 +107,14 @@ namespace ams::lr {
Result ContentLocationResolverImpl::Refresh() {
/* Obtain Content Meta Database and Content Storage objects for this resolver's storage. */
std::shared_ptr<ncm::IContentMetaDatabase> content_meta_database;
std::shared_ptr<ncm::IContentStorage> content_storage;
R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, this->storage_id));
R_TRY(ncm::impl::OpenContentStorage(&content_storage, this->storage_id));
ncm::ContentMetaDatabase meta_db;
ncm::ContentStorage storage;
R_TRY(ncm::OpenContentMetaDatabase(&meta_db, this->storage_id));
R_TRY(ncm::OpenContentStorage(&storage, this->storage_id));
/* Store the acquired objects. */
this->content_meta_database = std::move(content_meta_database);
this->content_storage = std::move(content_storage);
this->content_meta_database = std::move(meta_db);
this->content_storage = std::move(storage);
/* Remove any existing redirections. */
this->ClearRedirections();

View file

@ -24,8 +24,8 @@ namespace ams::lr {
ncm::StorageId storage_id;
/* Objects for this storage type. */
std::shared_ptr<ncm::IContentMetaDatabase> content_meta_database;
std::shared_ptr<ncm::IContentStorage> content_storage;
ncm::ContentMetaDatabase content_meta_database;
ncm::ContentStorage content_storage;
public:
ContentLocationResolverImpl(ncm::StorageId storage_id) : storage_id(storage_id) { /* ... */ }

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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/>.
*/
#include <stratosphere.hpp>
#include "ncm_remote_content_manager_impl.hpp"
namespace ams::ncm {
namespace {
std::shared_ptr<IContentManager> g_content_manager;
}
void Initialize() {
AMS_ASSERT(g_content_manager == nullptr);
R_ABORT_UNLESS(ncmInitialize());
g_content_manager = std::make_shared<RemoteContentManagerImpl>();
}
void Finalize() {
AMS_ASSERT(g_content_manager != nullptr);
g_content_manager.reset();
ncmExit();
}
void InitializeWithObject(std::shared_ptr<IContentManager> manager_object) {
AMS_ASSERT(g_content_manager == nullptr);
g_content_manager = manager_object;
AMS_ASSERT(g_content_manager != nullptr);
}
/* Service API. */
Result CreateContentStorage(StorageId storage_id) {
return g_content_manager->CreateContentStorage(storage_id);
}
Result CreateContentMetaDatabase(StorageId storage_id) {
return g_content_manager->CreateContentMetaDatabase(storage_id);
}
Result VerifyContentStorage(StorageId storage_id) {
return g_content_manager->VerifyContentStorage(storage_id);
}
Result VerifyContentMetaDatabase(StorageId storage_id) {
return g_content_manager->VerifyContentMetaDatabase(storage_id);
}
Result OpenContentStorage(ContentStorage *out, StorageId storage_id) {
sf::cmif::ServiceObjectHolder object_holder;
R_TRY(g_content_manager->OpenContentStorage(std::addressof(object_holder), storage_id));
*out = ContentStorage(object_holder.GetServiceObject<IContentStorage>());
return ResultSuccess();
}
Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id) {
sf::cmif::ServiceObjectHolder object_holder;
R_TRY(g_content_manager->OpenContentMetaDatabase(std::addressof(object_holder), storage_id));
*out = ContentMetaDatabase(object_holder.GetServiceObject<IContentMetaDatabase>());
return ResultSuccess();
}
Result CleanupContentMetaDatabase(StorageId storage_id) {
return g_content_manager->CleanupContentMetaDatabase(storage_id);
}
Result ActivateContentStorage(StorageId storage_id) {
return g_content_manager->ActivateContentStorage(storage_id);
}
Result InactivateContentStorage(StorageId storage_id) {
return g_content_manager->InactivateContentStorage(storage_id);
}
Result ActivateContentMetaDatabase(StorageId storage_id) {
return g_content_manager->ActivateContentMetaDatabase(storage_id);
}
Result InactivateContentMetaDatabase(StorageId storage_id) {
return g_content_manager->InactivateContentMetaDatabase(storage_id);
}
Result InvalidateRightsIdCache() {
return g_content_manager->InvalidateRightsIdCache();
}
/* Deprecated API. */
Result CloseContentStorageForcibly(StorageId storage_id) {
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
return g_content_manager->CloseContentStorageForcibly(storage_id);
}
Result CloseContentMetaDatabaseForcibly(StorageId storage_id) {
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
return g_content_manager->CloseContentMetaDatabaseForcibly(storage_id);
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 "ncm_remote_content_storage_impl.hpp"
#include "ncm_remote_content_meta_database_impl.hpp"
namespace ams::ncm {
class RemoteContentManagerImpl final : public IContentManager {
public:
RemoteContentManagerImpl() { /* ... */ }
~RemoteContentManagerImpl() { /* ... */ }
public:
virtual Result CreateContentStorage(StorageId storage_id) override {
return ::ncmCreateContentStorage(static_cast<NcmStorageId>(storage_id));
}
virtual Result CreateContentMetaDatabase(StorageId storage_id) override {
return ::ncmCreateContentMetaDatabase(static_cast<NcmStorageId>(storage_id));
}
virtual Result VerifyContentStorage(StorageId storage_id) override {
return ::ncmVerifyContentStorage(static_cast<NcmStorageId>(storage_id));
}
virtual Result VerifyContentMetaDatabase(StorageId storage_id) override {
return ::ncmVerifyContentMetaDatabase(static_cast<NcmStorageId>(storage_id));
}
virtual Result OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) override {
NcmContentStorage cs;
R_TRY(::ncmOpenContentStorage(std::addressof(cs), static_cast<NcmStorageId>(storage_id)));
out.SetValue(std::make_shared<RemoteContentStorageImpl>(cs));
return ResultSuccess();
}
virtual Result OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) override {
NcmContentMetaDatabase db;
R_TRY(::ncmOpenContentMetaDatabase(std::addressof(db), static_cast<NcmStorageId>(storage_id)));
out.SetValue(std::make_shared<RemoteContentMetaDatabaseImpl>(db));
return ResultSuccess();
}
virtual Result CloseContentStorageForcibly(StorageId storage_id) override {
return ::ncmCloseContentStorageForcibly(static_cast<NcmStorageId>(storage_id));
}
virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override {
return ::ncmCloseContentMetaDatabaseForcibly(static_cast<NcmStorageId>(storage_id));
}
virtual Result CleanupContentMetaDatabase(StorageId storage_id) override {
return ::ncmCleanupContentMetaDatabase(static_cast<NcmStorageId>(storage_id));
}
virtual Result ActivateContentStorage(StorageId storage_id) override {
return ::ncmActivateContentStorage(static_cast<NcmStorageId>(storage_id));
}
virtual Result InactivateContentStorage(StorageId storage_id) override {
return ::ncmInactivateContentStorage(static_cast<NcmStorageId>(storage_id));
}
virtual Result ActivateContentMetaDatabase(StorageId storage_id) override {
return ::ncmActivateContentMetaDatabase(static_cast<NcmStorageId>(storage_id));
}
virtual Result InactivateContentMetaDatabase(StorageId storage_id) override {
return ::ncmInactivateContentMetaDatabase(static_cast<NcmStorageId>(storage_id));
}
virtual Result InvalidateRightsIdCache() override {
return ::ncmInvalidateRightsIdCache();
}
};
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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>
namespace ams::ncm {
class RemoteContentMetaDatabaseImpl final : public IContentMetaDatabase {
private:
::NcmContentMetaDatabase srv;
public:
RemoteContentMetaDatabaseImpl(::NcmContentMetaDatabase &db) : srv(db) { /* ... */ }
~RemoteContentMetaDatabaseImpl() { ::ncmContentMetaDatabaseClose(std::addressof(srv)); }
private:
ALWAYS_INLINE ::NcmContentMetaKey *Convert(ContentMetaKey *k) {
static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
return reinterpret_cast<::NcmContentMetaKey *>(k);
}
ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey *k) {
static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
return reinterpret_cast<const ::NcmContentMetaKey *>(k);
}
ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey &k) {
static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
return reinterpret_cast<const ::NcmContentMetaKey *>(std::addressof(k));
}
ALWAYS_INLINE ::NcmApplicationContentMetaKey *Convert(ApplicationContentMetaKey *k) {
static_assert(sizeof(ApplicationContentMetaKey) == sizeof(::NcmApplicationContentMetaKey));
return reinterpret_cast<::NcmApplicationContentMetaKey *>(k);
}
ALWAYS_INLINE ::NcmContentInfo *Convert(ContentInfo *c) {
static_assert(sizeof(ContentInfo) == sizeof(::NcmContentInfo));
return reinterpret_cast<::NcmContentInfo *>(c);
}
ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<::NcmContentId *>(c);
}
ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<::NcmContentId *>(std::addressof(c));
}
ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId *c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<const ::NcmContentId *>(c);
}
ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId &c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<const ::NcmContentId *>(std::addressof(c));
}
public:
virtual Result Set(const ContentMetaKey &key, sf::InBuffer value) override {
return ncmContentMetaDatabaseSet(std::addressof(this->srv), Convert(key), value.GetPointer(), value.GetSize());
}
virtual Result Get(sf::Out<u64> out_size, const ContentMetaKey &key, sf::OutBuffer out_value) override {
return ncmContentMetaDatabaseGet(std::addressof(this->srv), Convert(key), out_size.GetPointer(), out_value.GetPointer(), out_value.GetSize());
}
virtual Result Remove(const ContentMetaKey &key) override {
return ncmContentMetaDatabaseRemove(std::addressof(this->srv), Convert(key));
}
virtual Result GetContentIdByType(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type) override {
return ncmContentMetaDatabaseGetContentIdByType(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type));
}
virtual Result ListContentInfo(sf::Out<u32> out_entries_written, const sf::OutArray<ContentInfo> &out_info, const ContentMetaKey &key, u32 start_index) override {
return ncmContentMetaDatabaseListContentInfo(std::addressof(this->srv), reinterpret_cast<s32 *>(out_entries_written.GetPointer()), Convert(out_info.GetPointer()), out_info.GetSize(), Convert(key), start_index);
}
virtual Result List(sf::Out<u32> out_entries_total, sf::Out<u32> out_entries_written, const sf::OutArray<ContentMetaKey> &out, ContentMetaType meta_type, ProgramId application_program_id, ProgramId program_id_min, ProgramId program_id_max, ContentInstallType install_type) override {
return ncmContentMetaDatabaseList(std::addressof(this->srv), reinterpret_cast<s32 *>(out_entries_total.GetPointer()), reinterpret_cast<s32 *>(out_entries_written.GetPointer()), Convert(out.GetPointer()), out.GetSize(), static_cast<::NcmContentMetaType>(meta_type), static_cast<u64>(application_program_id), static_cast<u64>(program_id_min), static_cast<u64>(program_id_max), static_cast<::NcmContentInstallType>(install_type));
}
virtual Result GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, ProgramId id) override {
return ncmContentMetaDatabaseGetLatestContentMetaKey(std::addressof(this->srv), Convert(out_key.GetPointer()), static_cast<u64>(id));
}
virtual Result ListApplication(sf::Out<u32> out_entries_total, sf::Out<u32> out_entries_written, const sf::OutArray<ApplicationContentMetaKey> &out_keys, ContentMetaType meta_type) override {
return ncmContentMetaDatabaseListApplication(std::addressof(this->srv), reinterpret_cast<s32 *>(out_entries_total.GetPointer()), reinterpret_cast<s32 *>(out_entries_written.GetPointer()), Convert(out_keys.GetPointer()), out_keys.GetSize(), static_cast<::NcmContentMetaType>(meta_type));
}
virtual Result Has(sf::Out<bool> out, const ContentMetaKey &key) override {
return ncmContentMetaDatabaseHas(std::addressof(this->srv), out.GetPointer(), Convert(key));
}
virtual Result HasAll(sf::Out<bool> out, const sf::InArray<ContentMetaKey> &keys) override {
return ncmContentMetaDatabaseHasAll(std::addressof(this->srv), out.GetPointer(), Convert(keys.GetPointer()), keys.GetSize());
}
virtual Result GetSize(sf::Out<u64> out_size, const ContentMetaKey &key) override {
return ncmContentMetaDatabaseGetSize(std::addressof(this->srv), out_size.GetPointer(), Convert(key));
}
virtual Result GetRequiredSystemVersion(sf::Out<u32> out_version, const ContentMetaKey &key) override {
return ncmContentMetaDatabaseGetRequiredSystemVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key));
}
virtual Result GetPatchId(sf::Out<ProgramId> out_patch_id, const ContentMetaKey &key) override {
return ncmContentMetaDatabaseGetPatchId(std::addressof(this->srv), reinterpret_cast<u64 *>(out_patch_id.GetPointer()), Convert(key));
}
virtual Result DisableForcibly() override {
return ncmContentMetaDatabaseDisableForcibly(std::addressof(this->srv));
}
virtual Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids) override {
return ncmContentMetaDatabaseLookupOrphanContent(std::addressof(this->srv), out_orphaned.GetPointer(), Convert(content_ids.GetPointer()), std::min(out_orphaned.GetSize(), content_ids.GetSize()));
}
virtual Result Commit() override {
return ncmContentMetaDatabaseCommit(std::addressof(this->srv));
}
virtual Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id) override {
return ncmContentMetaDatabaseHasContent(std::addressof(this->srv), out.GetPointer(), Convert(key), Convert(content_id));
}
virtual Result ListContentMetaInfo(sf::Out<u32> out_entries_written, const sf::OutArray<ContentMetaInfo> &out_meta_info, const ContentMetaKey &key, u32 start_index) override {
return ncmContentMetaDatabaseListContentMetaInfo(std::addressof(this->srv), reinterpret_cast<s32 *>(out_entries_written.GetPointer()), out_meta_info.GetPointer(), out_meta_info.GetSize(), Convert(key), start_index);
}
virtual Result GetAttributes(sf::Out<ContentMetaAttribute> out_attributes, const ContentMetaKey &key) override {
static_assert(sizeof(ContentMetaAttribute) == sizeof(u8));
return ncmContentMetaDatabaseGetAttributes(std::addressof(this->srv), Convert(key), reinterpret_cast<u8 *>(out_attributes.GetPointer()));
}
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) override {
return ncmContentMetaDatabaseGetRequiredApplicationVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key));
}
virtual Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) override {
return ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type), id_offset);
}
};
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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>
namespace ams::ncm {
class RemoteContentStorageImpl final : public IContentStorage {
private:
::NcmContentStorage srv;
public:
RemoteContentStorageImpl(::NcmContentStorage &cs) : srv(cs) { /* ... */ }
~RemoteContentStorageImpl() { ::ncmContentStorageClose(std::addressof(srv)); }
private:
ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId *p) {
static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId));
return reinterpret_cast<::NcmPlaceHolderId *>(p);
}
ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId &p) {
static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId));
return reinterpret_cast<::NcmPlaceHolderId *>(std::addressof(p));
}
ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<::NcmContentId *>(c);
}
ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) {
static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
return reinterpret_cast<::NcmContentId *>(std::addressof(c));
}
public:
virtual Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) override {
return ncmContentStorageGeneratePlaceHolderId(std::addressof(this->srv), Convert(out.GetPointer()));
}
virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) override {
static_assert(alignof(ContentId) < alignof(PlaceHolderId));
return ncmContentStorageCreatePlaceHolder(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id), static_cast<s64>(size));
}
virtual Result DeletePlaceHolder(PlaceHolderId placeholder_id) override {
return ncmContentStorageDeletePlaceHolder(std::addressof(this->srv), Convert(placeholder_id));
}
virtual Result HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) override {
return ncmContentStorageHasPlaceHolder(std::addressof(this->srv), out.GetPointer(), Convert(placeholder_id));
}
virtual Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) override {
return ncmContentStorageWritePlaceHolder(std::addressof(this->srv), Convert(placeholder_id), offset, data.GetPointer(), data.GetSize());
}
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override {
static_assert(alignof(ContentId) < alignof(PlaceHolderId));
return ncmContentStorageRegister(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id));
}
virtual Result Delete(ContentId content_id) override {
return ncmContentStorageDelete(std::addressof(this->srv), Convert(content_id));
}
virtual Result Has(sf::Out<bool> out, ContentId content_id) override {
return ncmContentStorageHas(std::addressof(this->srv), out.GetPointer(), Convert(content_id));
}
virtual Result GetPath(sf::Out<Path> out, ContentId content_id) override {
return ncmContentStorageGetPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(content_id));
}
virtual Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) override {
return ncmContentStorageGetPlaceHolderPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(placeholder_id));
}
virtual Result CleanupAllPlaceHolder() override {
return ncmContentStorageCleanupAllPlaceHolder(std::addressof(this->srv));
}
virtual Result ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) override {
return ncmContentStorageListPlaceHolder(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast<s32 *>(out_count.GetPointer()));
}
virtual Result GetContentCount(sf::Out<u32> out_count) override {
return ncmContentStorageGetContentCount(std::addressof(this->srv), reinterpret_cast<s32 *>(out_count.GetPointer()));
}
virtual Result ListContentId(sf::Out<u32> out_count, const sf::OutArray<ContentId> &out_buf, u32 offset) override {
return ncmContentStorageListContentId(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast<s32 *>(out_count.GetPointer()), static_cast<s32>(offset));
}
virtual Result GetSizeFromContentId(sf::Out<u64> out_size, ContentId content_id) override {
return ncmContentStorageGetSizeFromContentId(std::addressof(this->srv), reinterpret_cast<s64 *>(out_size.GetPointer()), Convert(content_id));
}
virtual Result DisableForcibly() override {
return ncmContentStorageDisableForcibly(std::addressof(this->srv));
}
virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override {
return ncmContentStorageRevertToPlaceHolder(std::addressof(this->srv), Convert(placeholder_id), Convert(old_content_id), Convert(new_content_id));
}
virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override {
return ncmContentStorageSetPlaceHolderSize(std::addressof(this->srv), Convert(placeholder_id), static_cast<s64>(size));
}
virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override {
return ncmContentStorageReadContentIdFile(std::addressof(this->srv), buf.GetPointer(), buf.GetSize(), Convert(content_id), static_cast<s64>(offset));
}
virtual Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id) override {
::NcmRightsId rights_id;
R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id)));
static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
return ResultSuccess();
}
virtual Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) override {
::NcmRightsId rights_id;
R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id)));
static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
return ResultSuccess();
}
virtual Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id) override {
::NcmRightsId rights_id;
R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id)));
static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
return ResultSuccess();
}
virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) override {
::NcmRightsId rights_id;
R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id)));
static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
return ResultSuccess();
}
virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override {
return ncmContentStorageWriteContentForDebug(std::addressof(this->srv), Convert(content_id), static_cast<s64>(offset), data.GetPointer(), data.GetSize());
}
virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) override {
return ncmContentStorageGetFreeSpaceSize(std::addressof(this->srv), reinterpret_cast<s64 *>(out_size.GetPointer()));
}
virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) override {
return ncmContentStorageGetTotalSpaceSize(std::addressof(this->srv), reinterpret_cast<s64 *>(out_size.GetPointer()));
}
virtual Result FlushPlaceHolder() override {
return ncmContentStorageFlushPlaceHolder(std::addressof(this->srv));
}
virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out_size, PlaceHolderId placeholder_id) override {
return ncmContentStorageGetSizeFromPlaceHolderId(std::addressof(this->srv), reinterpret_cast<s64 *>(out_size.GetPointer()), Convert(placeholder_id));
}
virtual Result RepairInvalidFileAttribute() override {
return ncmContentStorageRepairInvalidFileAttribute(std::addressof(this->srv));
}
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) override {
static_assert(sizeof(::NcmRightsId) == sizeof(ncm::RightsId));
::NcmRightsId *out = reinterpret_cast<::NcmRightsId *>(out_rights_id.GetPointer());
return ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(std::addressof(this->srv), out, Convert(placeholder_id), Convert(cache_content_id));
}
};
}

View file

@ -72,7 +72,7 @@ namespace ams::ncm::impl {
constexpr u64 BuiltInSystemSaveDataSize = 0x6c000;
constexpr u64 BuiltInSystemSaveDataJournalSize = 0x6c000;
constexpr u32 BuiltInSystemSaveDataFlags = FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment;
constexpr SaveDataMeta BuiltInSystemSaveDataMeta = {
.id = BuiltInSystemSaveDataId,
.size = BuiltInSystemSaveDataSize,
@ -119,7 +119,7 @@ namespace ams::ncm::impl {
std::optional<kvdb::MemoryKeyValueStore<ContentMetaKey>> kvs;
u32 max_content_metas;
inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}),
inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}),
content_meta_database(nullptr), kvs(std::nullopt), max_content_metas(0) {
mount_point[0] = '\0';
meta_path[0] = '\0';
@ -268,17 +268,17 @@ namespace ams::ncm::impl {
/* First, setup the BuiltInSystem storage entry. */
g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInSystem, FsContentStorageId_System);
if (R_FAILED(VerifyContentStorage(StorageId::BuiltInSystem))) {
R_TRY(CreateContentStorage(StorageId::BuiltInSystem));
if (R_FAILED(impl::VerifyContentStorage(StorageId::BuiltInSystem))) {
R_TRY(impl::CreateContentStorage(StorageId::BuiltInSystem));
}
R_TRY(ActivateContentStorage(StorageId::BuiltInSystem));
R_TRY(impl::ActivateContentStorage(StorageId::BuiltInSystem));
/* Next, the BuiltInSystem content meta entry. */
R_TRY(g_content_meta_entries[g_num_content_meta_entries++].Initialize(StorageId::BuiltInSystem, BuiltInSystemSaveDataMeta, MaxBuiltInSystemContentMetaCount));
if (R_FAILED(VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
R_TRY(CreateContentMetaDatabase(StorageId::BuiltInSystem));
if (R_FAILED(impl::VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
R_TRY(impl::CreateContentMetaDatabase(StorageId::BuiltInSystem));
/* TODO: N supports a number of unused modes here, we don't bother implementing them currently. */
}
@ -287,8 +287,8 @@ namespace ams::ncm::impl {
if (hos::GetVersion() >= hos::Version_200 && R_SUCCEEDED(fs::GetSaveDataFlags(&current_flags, BuiltInSystemSaveDataId)) && current_flags != (FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment)) {
fs::SetSaveDataFlags(BuiltInSystemSaveDataId, FsSaveDataSpaceId_System, FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment);
}
R_TRY(ActivateContentMetaDatabase(StorageId::BuiltInSystem));
R_TRY(impl::ActivateContentMetaDatabase(StorageId::BuiltInSystem));
/* Now for BuiltInUser's content storage and content meta entries. */
g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInUser, FsContentStorageId_User);
@ -316,12 +316,12 @@ namespace ams::ncm::impl {
for (size_t i = 0; i < MaxContentStorageEntries; i++) {
ContentStorageRoot *entry = &g_content_storage_roots[i];
InactivateContentStorage(entry->storage_id);
impl::InactivateContentStorage(entry->storage_id);
}
for (size_t i = 0; i < MaxContentMetaDatabaseEntries; i++) {
ContentMetaDatabaseEntry *entry = &g_content_meta_entries[i];
InactivateContentMetaDatabase(entry->storage_id);
impl::InactivateContentMetaDatabase(entry->storage_id);
}
}
@ -374,7 +374,7 @@ namespace ams::ncm::impl {
ContentStorageRoot *root;
R_TRY(GetUniqueContentStorageRoot(std::addressof(root), storage_id));
auto content_storage = root->content_storage;
if (hos::GetVersion() >= hos::Version_200) {
@ -382,7 +382,7 @@ namespace ams::ncm::impl {
} else {
/* 1.0.0 activates content storages as soon as they are opened. */
if (!content_storage) {
R_TRY(ActivateContentStorage(storage_id));
R_TRY(impl::ActivateContentStorage(storage_id));
content_storage = root->content_storage;
}
}
@ -518,7 +518,7 @@ namespace ams::ncm::impl {
ContentMetaDatabaseEntry *entry;
R_TRY(GetUniqueContentMetaDatabaseEntry(&entry, storage_id));
auto content_meta_db = entry->content_meta_database;
if (hos::GetVersion() >= hos::Version_200) {
@ -526,7 +526,7 @@ namespace ams::ncm::impl {
} else {
/* 1.0.0 activates content meta databases as soon as they are opened. */
if (!content_meta_db) {
R_TRY(ActivateContentMetaDatabase(storage_id));
R_TRY(impl::ActivateContentMetaDatabase(storage_id));
content_meta_db = entry->content_meta_database;
}
}
@ -541,7 +541,7 @@ namespace ams::ncm::impl {
R_UNLESS(storage_id != StorageId::None, ncm::ResultUnknownStorage());
ContentMetaDatabaseEntry *entry;
R_TRY(FindContentMetaDatabaseEntry(&entry, storage_id));
auto content_meta_db = entry->content_meta_database;
if (content_meta_db) {

View file

@ -14,70 +14,70 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ncm_content_manager_impl.hpp"
#include "impl/ncm_content_manager.hpp"
#include "ncm_content_manager_service.hpp"
namespace ams::ncm {
Result ContentManagerService::CreateContentStorage(StorageId storage_id) {
Result ContentManagerImpl::CreateContentStorage(StorageId storage_id) {
return impl::CreateContentStorage(storage_id);
}
Result ContentManagerService::CreateContentMetaDatabase(StorageId storage_id) {
Result ContentManagerImpl::CreateContentMetaDatabase(StorageId storage_id) {
return impl::CreateContentMetaDatabase(storage_id);
}
Result ContentManagerService::VerifyContentStorage(StorageId storage_id) {
Result ContentManagerImpl::VerifyContentStorage(StorageId storage_id) {
return impl::VerifyContentStorage(storage_id);
}
Result ContentManagerService::VerifyContentMetaDatabase(StorageId storage_id) {
Result ContentManagerImpl::VerifyContentMetaDatabase(StorageId storage_id) {
return impl::VerifyContentMetaDatabase(storage_id);
}
Result ContentManagerService::OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) {
Result ContentManagerImpl::OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) {
std::shared_ptr<IContentStorage> content_storage;
R_TRY(impl::OpenContentStorage(&content_storage, storage_id));
out.SetValue(std::move(content_storage));
return ResultSuccess();
}
Result ContentManagerService::OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) {
Result ContentManagerImpl::OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) {
std::shared_ptr<IContentMetaDatabase> content_meta_database;
R_TRY(impl::OpenContentMetaDatabase(&content_meta_database, storage_id));
out.SetValue(std::move(content_meta_database));
return ResultSuccess();
}
Result ContentManagerService::CloseContentStorageForcibly(StorageId storage_id) {
Result ContentManagerImpl::CloseContentStorageForcibly(StorageId storage_id) {
return impl::CloseContentStorageForcibly(storage_id);
}
Result ContentManagerService::CloseContentMetaDatabaseForcibly(StorageId storage_id) {
Result ContentManagerImpl::CloseContentMetaDatabaseForcibly(StorageId storage_id) {
return impl::CloseContentMetaDatabaseForcibly(storage_id);
}
Result ContentManagerService::CleanupContentMetaDatabase(StorageId storage_id) {
Result ContentManagerImpl::CleanupContentMetaDatabase(StorageId storage_id) {
return impl::CleanupContentMetaDatabase(storage_id);
}
Result ContentManagerService::ActivateContentStorage(StorageId storage_id) {
Result ContentManagerImpl::ActivateContentStorage(StorageId storage_id) {
return impl::ActivateContentStorage(storage_id);
}
Result ContentManagerService::InactivateContentStorage(StorageId storage_id) {
Result ContentManagerImpl::InactivateContentStorage(StorageId storage_id) {
return impl::InactivateContentStorage(storage_id);
}
Result ContentManagerService::ActivateContentMetaDatabase(StorageId storage_id) {
Result ContentManagerImpl::ActivateContentMetaDatabase(StorageId storage_id) {
return impl::ActivateContentMetaDatabase(storage_id);
}
Result ContentManagerService::InactivateContentMetaDatabase(StorageId storage_id) {
Result ContentManagerImpl::InactivateContentMetaDatabase(StorageId storage_id) {
return impl::InactivateContentMetaDatabase(storage_id);
}
Result ContentManagerService::InvalidateRightsIdCache() {
Result ContentManagerImpl::InvalidateRightsIdCache() {
return impl::InvalidateRightsIdCache();
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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>
namespace ams::ncm {
class ContentManagerImpl final : public IContentManager {
public:
virtual Result CreateContentStorage(StorageId storage_id) override;
virtual Result CreateContentMetaDatabase(StorageId storage_id) override;
virtual Result VerifyContentStorage(StorageId storage_id) override;
virtual Result VerifyContentMetaDatabase(StorageId storage_id) override;
virtual Result OpenContentStorage(sf::Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) override;
virtual Result OpenContentMetaDatabase(sf::Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) override;
virtual Result CloseContentStorageForcibly(StorageId storage_id) override;
virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override;
virtual Result CleanupContentMetaDatabase(StorageId storage_id) override;
virtual Result ActivateContentStorage(StorageId storage_id) override;
virtual Result InactivateContentStorage(StorageId storage_id) override;
virtual Result ActivateContentMetaDatabase(StorageId storage_id) override;
virtual Result InactivateContentMetaDatabase(StorageId storage_id) override;
virtual Result InvalidateRightsIdCache() override;
};
}

View file

@ -297,7 +297,7 @@ namespace ams::ncm {
return fsdevCommitDevice(this->mount_name);
}
Result ContentMetaDatabaseImpl::HasContent(sf::Out<bool> out, const ContentMetaKey &key, ContentId content_id) {
Result ContentMetaDatabaseImpl::HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id) {
const void *meta;
size_t meta_size;
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key));

View file

@ -45,7 +45,7 @@ namespace ams::ncm {
virtual Result DisableForcibly() override;
virtual Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids) override;
virtual Result Commit() override;
virtual Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, ContentId content_id) override;
virtual Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id) override;
virtual Result ListContentMetaInfo(sf::Out<u32> out_entries_written, const sf::OutArray<ContentMetaInfo> &out_meta_info, const ContentMetaKey &key, u32 start_index) override;
virtual Result GetAttributes(sf::Out<ContentMetaAttribute> out_attributes, const ContentMetaKey &key) override;
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) override;

View file

@ -108,7 +108,7 @@ namespace ams::ncm {
char placeholder_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.MakePath(placeholder_path, placeholder_id);
bool has = false;
R_TRY(fs::HasFile(&has, placeholder_path));
out.SetValue(has);
@ -173,25 +173,25 @@ namespace ams::ncm {
return ResultSuccess();
}
Result ContentStorageImpl::GetPath(sf::Out<lr::Path> out, ContentId content_id) {
Result ContentStorageImpl::GetPath(sf::Out<Path> out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0};
this->GetContentPath(content_path, content_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
out.SetValue(lr::Path::Encode(common_path));
out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
Result ContentStorageImpl::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) {
Result ContentStorageImpl::GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled());
char placeholder_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.GetPath(placeholder_path, placeholder_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path));
out.SetValue(lr::Path::Encode(common_path));
out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
@ -202,7 +202,7 @@ namespace ams::ncm {
this->placeholder_accessor.InvalidateAll();
this->placeholder_accessor.MakeRootPath(placeholder_root_path);
/* Nintendo uses CleanDirectoryRecursively which is 3.0.0+.
/* Nintendo uses CleanDirectoryRecursively which is 3.0.0+.
We'll just delete the directory and recreate it to support all firmwares. */
R_TRY(fsdevDeleteDirectoryRecursively(placeholder_root_path));
R_UNLESS(mkdir(placeholder_root_path, S_IRWXU) != -1, fsdevGetLastResult());
@ -220,15 +220,15 @@ namespace ams::ncm {
R_TRY(fs::TraverseDirectory(placeholder_root_path, dir_depth, [&](bool *should_continue, bool *should_retry_dir_read, const char *current_path, struct dirent *dir_entry) -> Result {
*should_continue = true;
*should_retry_dir_read = false;
if (dir_entry->d_type == DT_REG) {
R_UNLESS(entry_count <= out_buf.GetSize(), ncm::ResultBufferInsufficient());
PlaceHolderId cur_entry_placeholder_id = {0};
R_TRY(GetPlaceHolderIdFromDirEntry(&cur_entry_placeholder_id, dir_entry));
out_buf[entry_count++] = cur_entry_placeholder_id;
}
return ResultSuccess();
}));
@ -329,7 +329,7 @@ namespace ams::ncm {
Result ContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
R_TRY(this->EnsureEnabled());
char old_content_path[FS_MAX_PATH] = {0};
char new_content_path[FS_MAX_PATH] = {0};
char placeholder_path[FS_MAX_PATH] = {0};
@ -401,7 +401,7 @@ namespace ams::ncm {
Result ContentStorageImpl::GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) {
R_TRY(this->EnsureEnabled());
if (this->rights_id_cache->Find(out_rights_id.GetPointer(), content_id)) {
return ResultSuccess();
}
@ -437,7 +437,7 @@ namespace ams::ncm {
FILE *f = nullptr;
R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Write));
ON_SCOPE_EXIT {
fclose(f);
};
@ -522,7 +522,7 @@ namespace ams::ncm {
Result ContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
R_TRY(this->EnsureEnabled());
if (this->rights_id_cache->Find(out_rights_id.GetPointer(), cache_content_id)) {
return ResultSuccess();
}

View file

@ -60,8 +60,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override;
virtual Result Delete(ContentId content_id) override;
virtual Result Has(sf::Out<bool> out, ContentId content_id) override;
virtual Result GetPath(sf::Out<lr::Path> out, ContentId content_id) override;
virtual Result GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) override;
virtual Result GetPath(sf::Out<Path> out, ContentId content_id) override;
virtual Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) override;
virtual Result CleanupAllPlaceHolder() override;
virtual Result ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) override;
virtual Result GetContentCount(sf::Out<u32> out_count) override;

View file

@ -18,7 +18,7 @@
#include <stratosphere/lr/lr_location_resolver_manager_impl.hpp>
#include "impl/ncm_content_manager.hpp"
#include "ncm_content_manager_service.hpp"
#include "ncm_content_manager_impl.hpp"
extern "C" {
extern u32 __start__;
@ -100,6 +100,39 @@ namespace {
constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm");
class ContentManagerServerManager : public sf::hipc::ServerManager<ContentManagerNumServers, ContentManagerServerOptions, ContentManagerMaxSessions> {
private:
static constexpr size_t ThreadStackSize = 0x4000;
static constexpr int ThreadPriority = 0x15;
using ServiceType = ncm::ContentManagerImpl;
private:
os::StaticThread<ThreadStackSize> thread;
std::shared_ptr<ServiceType> ncm_manager;
private:
static void ThreadFunction(void *_this) {
reinterpret_cast<ContentManagerServerManager *>(_this)->LoopProcess();
}
public:
ContentManagerServerManager(ServiceType *m)
: thread(ThreadFunction, this, ThreadPriority), ncm_manager(sf::ServiceObjectTraits<ServiceType>::SharedPointerHelper::GetEmptyDeleteSharedPointer(m))
{
/* ... */
}
ams::Result Initialize() {
return this->RegisterServer<ServiceType>(ContentManagerServiceName, ContentManagerManagerSessions, this->ncm_manager);
}
ams::Result StartThreads() {
return this->thread.Start();
}
void Wait() {
this->thread.Join();
}
};
struct LocationResolverServerOptions {
static constexpr size_t PointerBufferSize = 0x400;
static constexpr size_t MaxDomains = 0;
@ -146,7 +179,8 @@ namespace {
}
};
sf::hipc::ServerManager<ContentManagerNumServers, ContentManagerServerOptions, ContentManagerMaxSessions> g_ncm_server_manager;
ncm::ContentManagerImpl g_ncm_manager_service_object;
ContentManagerServerManager g_ncm_server_manager(std::addressof(g_ncm_manager_service_object));
lr::LocationResolverManagerImpl g_lr_manager_service_object;
LocationResolverServerManager g_lr_server_manager(std::addressof(g_lr_manager_service_object));
@ -155,7 +189,7 @@ namespace {
void ContentManagerServerMain(void *arg) {
/* Create services. */
R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer<ncm::ContentManagerService>(ContentManagerServiceName, ContentManagerManagerSessions));
R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer<ncm::ContentManagerImpl>(ContentManagerServiceName, ContentManagerManagerSessions));
/* Loop forever, servicing our services. */
g_ncm_server_manager.LoopProcess();
@ -164,19 +198,19 @@ void ContentManagerServerMain(void *arg) {
int main(int argc, char **argv)
{
/* Initialize content manager implementation. */
/* TODO: Move Initialize/Finalize into ContentManagerImpl ctor/dtor, initialize client library with static object. */
R_ABORT_UNLESS(ams::ncm::impl::InitializeContentManager());
static os::Thread s_content_manager_thread;
R_ABORT_UNLESS(s_content_manager_thread.Initialize(&ContentManagerServerMain, nullptr, 0x4000, 0x15));
R_ABORT_UNLESS(s_content_manager_thread.Start());
R_ABORT_UNLESS(g_ncm_server_manager.Initialize());
R_ABORT_UNLESS(g_ncm_server_manager.StartThreads());
R_ABORT_UNLESS(g_lr_server_manager.Initialize());
R_ABORT_UNLESS(g_lr_server_manager.StartThreads());
s_content_manager_thread.Join();
g_ncm_server_manager.Wait();
g_lr_server_manager.Wait();
/* TODO: This call is eventually automatic at scope exit. */
ams::ncm::impl::FinalizeContentManager();
return 0;

View file

@ -66,7 +66,7 @@ namespace ams::ncm {
bool has = false;
R_TRY(fs::HasFile(&has, content_path));
if (!has) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&has, content_path));
@ -76,7 +76,7 @@ namespace ams::ncm {
return ResultSuccess();
}
Result ReadOnlyContentStorageImpl::GetPath(sf::Out<lr::Path> out, ContentId content_id) {
Result ReadOnlyContentStorageImpl::GetPath(sf::Out<Path> out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0};
@ -85,18 +85,18 @@ namespace ams::ncm {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&is_content_meta_file, content_path));
if (!is_content_meta_file) {
this->make_content_path_func(content_path, content_id, this->root_path);
}
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
out.SetValue(lr::Path::Encode(common_path));
out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) {
Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation();
}
@ -124,7 +124,7 @@ namespace ams::ncm {
this->make_content_path_func(content_path, content_id, this->root_path);
R_TRY(fs::HasFile(&is_content_file, content_path));
if (!is_content_file) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
}
@ -158,18 +158,18 @@ namespace ams::ncm {
this->make_content_path_func(content_path, content_id, this->root_path);
R_TRY(fs::HasFile(&is_content_file, content_path));
if (!is_content_file) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
}
FILE *f = nullptr;
R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Read));
ON_SCOPE_EXIT {
fclose(f);
};
R_TRY(fs::ReadFile(f, offset, buf.GetPointer(), buf.GetSize()));
return ResultSuccess();
}
@ -198,13 +198,13 @@ namespace ams::ncm {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&is_content_meta_file, content_path));
if (!is_content_meta_file) {
this->make_content_path_func(content_path, content_id, this->root_path);
}
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
ncm::RightsId rights_id;
R_TRY(GetRightsId(&rights_id, common_path));
out_rights_id.SetValue(rights_id);

View file

@ -33,8 +33,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override;
virtual Result Delete(ContentId content_id) override;
virtual Result Has(sf::Out<bool> out, ContentId content_id) override;
virtual Result GetPath(sf::Out<lr::Path> out, ContentId content_id) override;
virtual Result GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) override;
virtual Result GetPath(sf::Out<Path> out, ContentId content_id) override;
virtual Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) override;
virtual Result CleanupAllPlaceHolder() override;
virtual Result ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) override;
virtual Result GetContentCount(sf::Out<u32> out_count) override;