ncm: updated to 13.0.0

This commit is contained in:
Adubbz 2021-09-17 18:33:17 +10:00
parent 575f62a41b
commit 71eaeb78d2
9 changed files with 422 additions and 26 deletions

View file

@ -38,6 +38,7 @@
#include <stratosphere/ncm/ncm_package_install_task.hpp>
#include <stratosphere/ncm/ncm_package_system_downgrade_task.hpp>
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
#include <stratosphere/ncm/ncm_registered_host_content.hpp>
#include <stratosphere/ncm/ncm_submission_package_install_task.hpp>
#include <stratosphere/ncm/ncm_storage_utils.hpp>
#include <stratosphere/ncm/ncm_api.hpp>

View file

@ -26,6 +26,7 @@
#include <stratosphere/ncm/ncm_rights_id_cache.hpp>
#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/kvdb/kvdb_memory_key_value_store.hpp>
namespace ams::ncm {
@ -108,8 +109,11 @@ namespace ams::ncm {
u32 num_content_storage_entries;
u32 num_content_meta_entries;
RightsIdCache rights_id_cache;
RegisteredHostContent registered_host_content;
public:
ContentManagerImpl() : mutex(true), initialized(false) { /* ... */ };
ContentManagerImpl() : mutex(true), initialized(false), num_content_storage_entries(0), num_content_meta_entries(0), rights_id_cache(), registered_host_content() {
/* ... */
};
~ContentManagerImpl();
public:
Result Initialize(const ContentManagerConfig &config);

View file

@ -1,21 +0,0 @@
/*
* 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>
namespace ams::ncm {
}

View file

@ -0,0 +1,42 @@
/*
* 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/os.hpp>
#include <stratosphere/ncm/ncm_content_id.hpp>
#include <stratosphere/ncm/ncm_path.hpp>
namespace ams::ncm {
class RegisteredHostContent {
NON_COPYABLE(RegisteredHostContent);
NON_MOVEABLE(RegisteredHostContent);
private:
class RegisteredPath;
private:
using RegisteredPathList = ams::util::IntrusiveListBaseTraits<RegisteredPath>::ListType;
private:
os::SdkMutex mutex;
RegisteredPathList path_list;
public:
RegisteredHostContent() : mutex(), path_list() { /* ... */ }
~RegisteredHostContent();
Result RegisterPath(const ncm::ContentId &content_id, const ncm::Path &path);
Result GetPath(Path *out, const ncm::ContentId &content_id);
void ClearPaths();
};
}

View file

@ -35,9 +35,9 @@ namespace ams::ncm {
private:
Entry entries[MaxEntries];
u64 counter;
os::Mutex mutex;
os::SdkMutex mutex;
public:
RightsIdCache() : mutex(false) {
RightsIdCache() : mutex() {
this->Invalidate();
}

View file

@ -16,6 +16,7 @@
#include <stratosphere.hpp>
#include "ncm_content_storage_impl.hpp"
#include "ncm_read_only_content_storage_impl.hpp"
#include "ncm_host_content_storage_impl.hpp"
#include "ncm_content_meta_database_impl.hpp"
#include "ncm_on_memory_content_meta_database_impl.hpp"
#include "ncm_fs_utils.hpp"
@ -551,7 +552,11 @@ namespace ams::ncm {
/* Unmount on failure. */
auto mount_guard = SCOPE_GUARD { fs::Unmount(root->mount_name); };
if (storage_id == StorageId::GameCard) {
if (storage_id == StorageId::Host) {
/* Create a host content storage. */
auto content_storage = sf::CreateSharedObjectEmplaced<IContentStorage, HostContentStorageImpl>(std::addressof(this->registered_host_content));
root->content_storage = std::move(content_storage);
} else if (storage_id == StorageId::GameCard) {
/* Game card content storage is read only. */
auto content_storage = sf::CreateSharedObjectEmplaced<IContentStorage, ReadOnlyContentStorageImpl>();
R_TRY(content_storage.GetImpl().Initialize(root->path, MakeFlatContentFilePath));
@ -593,7 +598,12 @@ namespace ams::ncm {
/* N doesn't bother checking the result of this */
root->content_storage->DisableForcibly();
root->content_storage = nullptr;
fs::Unmount(root->mount_name);
if (storage_id == StorageId::Host) {
this->registered_host_content.ClearPaths();
} else {
fs::Unmount(root->mount_name);
}
}
return ResultSuccess();

View file

@ -0,0 +1,193 @@
/*
* 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_host_content_storage_impl.hpp"
namespace ams::ncm {
Result HostContentStorageImpl::GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::DeletePlaceHolder(PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::Register(PlaceHolderId placeholder_id, ContentId content_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::Delete(ContentId content_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::Has(sf::Out<bool> out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
/* Attempt to locate the content. */
Path path;
R_TRY_CATCH(this->registered_content->GetPath(std::addressof(path), content_id)) {
/* The content is absent, this is fine. */
R_CATCH(ncm::ResultContentNotFound) {
out.SetValue(false);
return ResultSuccess();
}
} R_END_TRY_CATCH;
out.SetValue(true);
return ResultSuccess();
}
Result HostContentStorageImpl::GetPath(sf::Out<Path> out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
return this->registered_content->GetPath(out.GetPointer(), content_id);
}
Result HostContentStorageImpl::GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::CleanupAllPlaceHolder() {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::ListPlaceHolder(sf::Out<s32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetContentCount(sf::Out<s32> out_count) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::ListContentId(sf::Out<s32> out_count, const sf::OutArray<ContentId> &out_buf, s32 offset) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetSizeFromContentId(sf::Out<s64> out_size, ContentId content_id) {
return ncm::ResultInvalidOperation();
}
Result HostContentStorageImpl::DisableForcibly() {
this->disabled = true;
return ResultSuccess();
}
Result HostContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset) {
return ncm::ResultInvalidOperation();
}
Result HostContentStorageImpl::GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id) {
/* Obtain the regular rights id for the content id. */
ncm::RightsId rights_id;
R_TRY(this->GetRightsIdFromContentId(&rights_id, content_id));
/* Output the fs rights id. */
out_rights_id.SetValue(rights_id.id);
return ResultSuccess();
}
Result HostContentStorageImpl::GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) {
R_TRY(this->EnsureEnabled());
/* Get the content path. */
Path path;
R_TRY(this->registered_content->GetPath(std::addressof(path), content_id));
/* Acquire the rights id for the content. */
RightsId rights_id;
R_TRY_CATCH(GetRightsId(std::addressof(rights_id), path)) {
/* The content is absent, output a blank rights id. */
R_CATCH(fs::ResultTargetNotFound) {
out_rights_id.SetValue({});
return ResultSuccess();
}
} R_END_TRY_CATCH;
/* Output the rights id. */
out_rights_id.SetValue(rights_id);
return ResultSuccess();
}
Result HostContentStorageImpl::WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetFreeSpaceSize(sf::Out<s64> out_size) {
out_size.SetValue(0);
return ResultSuccess();
}
Result HostContentStorageImpl::GetTotalSpaceSize(sf::Out<s64> out_size) {
out_size.SetValue(0);
return ResultSuccess();
}
Result HostContentStorageImpl::FlushPlaceHolder() {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetSizeFromPlaceHolderId(sf::Out<s64> out, PlaceHolderId placeholder_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::RepairInvalidFileAttribute() {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
return ncm::ResultNotSupported();
}
Result HostContentStorageImpl::RegisterPath(const ContentId &content_id, const Path &path) {
AMS_ABORT_UNLESS(spl::IsDevelopment());
return this->registered_content->RegisterPath(content_id, path);
}
Result HostContentStorageImpl::ClearRegisteredPath() {
AMS_ABORT_UNLESS(spl::IsDevelopment());
this->registered_content->ClearPaths();
return ResultSuccess();
}
}

View file

@ -0,0 +1,81 @@
/*
* 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 HostContentStorageImpl {
protected:
RegisteredHostContent *registered_content;
bool disabled;
protected:
/* Helpers. */
Result EnsureEnabled() const {
R_UNLESS(!this->disabled, ncm::ResultInvalidContentStorage());
return ResultSuccess();
}
static Result GetRightsId(ncm::RightsId *out_rights_id, const Path &path) {
if (hos::GetVersion() >= hos::Version_3_0_0) {
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), std::addressof(out_rights_id->key_generation), path.str));
} else {
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), path.str));
out_rights_id->key_generation = 0;
}
return ResultSuccess();
}
public:
HostContentStorageImpl(RegisteredHostContent *registered_content) : registered_content(registered_content), disabled(false) { /* ... */ }
~HostContentStorageImpl();
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 GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id);
virtual Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id);
virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id);
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 GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id);
virtual Result RegisterPath(const ContentId &content_id, const Path &path);
virtual Result ClearRegisteredPath();
};
static_assert(ncm::IsIContentStorage<HostContentStorageImpl>);
}

View file

@ -0,0 +1,86 @@
/*
* 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>
namespace ams::ncm {
class RegisteredHostContent::RegisteredPath : public util::IntrusiveListBaseNode<RegisteredPath> {
NON_COPYABLE(RegisteredPath);
NON_MOVEABLE(RegisteredPath);
private:
ContentId content_id;
Path path;
public:
RegisteredPath(const ncm::ContentId &content_id, const Path &p) : content_id(content_id), path(p) {
/* ... */
}
ncm::ContentId GetContentId() const {
return this->content_id;
}
void GetPath(Path *out) const {
*out = this->path;
}
void SetPath(const Path &path) {
this->path = path;
}
};
Result RegisteredHostContent::RegisterPath(const ncm::ContentId &content_id, const ncm::Path &path) {
std::scoped_lock lk(this->mutex);
/* Replace the path of any existing entries. */
for (auto &registered_path : this->path_list) {
if (registered_path.GetContentId() == content_id) {
registered_path.SetPath(path);
return ResultSuccess();
}
}
/* Allocate a new registered path. TODO: Verify allocator. */
RegisteredPath *registered_path = new RegisteredPath(content_id, path);
R_UNLESS(registered_path != nullptr, ncm::ResultBufferInsufficient());
/* Insert the path into the list. */
this->path_list.push_back(*registered_path);
return ResultSuccess();
}
Result RegisteredHostContent::GetPath(Path *out, const ncm::ContentId &content_id) {
std::scoped_lock lk(this->mutex);
/* Obtain the path of the content. */
for (const auto &registered_path : this->path_list) {
if (registered_path.GetContentId() == content_id) {
registered_path.GetPath(out);
return ResultSuccess();
}
}
return ncm::ResultContentNotFound();
}
void RegisteredHostContent::ClearPaths() {
/* Remove all paths. */
for (auto it = this->path_list.begin(); it != this->path_list.end(); /* ... */) {
auto *obj = std::addressof(*it);
it = this->path_list.erase(it);
delete obj;
}
}
}