ncm: refactor rights cache

This commit is contained in:
Adubbz 2020-02-29 22:21:55 +11:00
parent f93a1a987c
commit 9b34fc7ce7
12 changed files with 276 additions and 195 deletions

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 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::fs {
union RightsId {
u8 data[0x10];
u64 data64[2];
};
static_assert(sizeof(RightsId) == 0x10);
static_assert(std::is_pod<RightsId>::value);
/* Rights ID API */
Result GetRightsId(RightsId *out, const char *path);
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path);
}

View File

@ -22,6 +22,8 @@
namespace ams::ncm { namespace ams::ncm {
class IContentStorage : public sf::IServiceObject { class IContentStorage : public sf::IServiceObject {
NON_COPYABLE(IContentStorage);
NON_MOVEABLE(IContentStorage);
protected: protected:
enum class CommandId { enum class CommandId {
GeneratePlaceHolderId = 0, GeneratePlaceHolderId = 0,
@ -53,15 +55,8 @@ namespace ams::ncm {
RepairInvalidFileAttribute = 26, RepairInvalidFileAttribute = 26,
GetRightsIdFromPlaceHolderIdWithCache = 27, GetRightsIdFromPlaceHolderIdWithCache = 27,
}; };
protected: public:
char root_path[FS_MAX_PATH-1]; IContentStorage() { /* ... */ }
MakeContentPathFunc make_content_path_func;
bool disabled;
protected:
Result EnsureEnabled() {
R_UNLESS(!this->disabled, ncm::ResultInvalidContentStorage());
return ResultSuccess();
}
public: public:
virtual Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) = 0; virtual Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) = 0;
virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) = 0; virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) = 0;
@ -82,15 +77,15 @@ namespace ams::ncm {
virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) = 0; virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) = 0;
virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) = 0; virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) = 0;
virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) = 0; virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) = 0;
virtual Result GetRightsIdFromPlaceHolderId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id) = 0; virtual Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) = 0;
virtual Result GetRightsIdFromContentId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, ContentId content_id) = 0; virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) = 0;
virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) = 0; virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) = 0;
virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) = 0; virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) = 0;
virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) = 0; virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) = 0;
virtual Result FlushPlaceHolder() = 0; virtual Result FlushPlaceHolder() = 0;
virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) = 0; virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) = 0;
virtual Result RepairInvalidFileAttribute() = 0; virtual Result RepairInvalidFileAttribute() = 0;
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) = 0; virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) = 0;
public: public:
DEFINE_SERVICE_DISPATCH_TABLE { DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(GeneratePlaceHolderId), MAKE_SERVICE_COMMAND_META(GeneratePlaceHolderId),

View File

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <vapours.hpp> #include <vapours.hpp>
#include <stratosphere/fs/fs_rights_id.hpp>
namespace ams::ncm { namespace ams::ncm {
@ -542,6 +543,14 @@ namespace ams::ncm {
static_assert(sizeof(ProgramLocation) == 0x10 && std::is_pod<ProgramLocation>::value, "ProgramLocation definition!"); static_assert(sizeof(ProgramLocation) == 0x10 && std::is_pod<ProgramLocation>::value, "ProgramLocation definition!");
static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility"); static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility");
struct RightsId {
fs::RightsId id;
u8 key_generation;
u8 reserved[7];
};
static_assert(sizeof(RightsId) == 0x18);
static_assert(std::is_pod<RightsId>::value);
struct ContentMetaKey { struct ContentMetaKey {
ProgramId id; ProgramId id;
u32 version; u32 version;

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2020 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 <stratosphere/fs/fs_rights_id.hpp>
namespace ams::fs {
Result GetRightsId(RightsId *out, const char *path) {
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
return fsGetRightsIdByPath(path, reinterpret_cast<::FsRightsId *>(out));
}
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path) {
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
return fsGetRightsIdAndKeyGenerationByPath(path, out_key_generation, reinterpret_cast<::FsRightsId *>(out));
}
}

View File

@ -20,10 +20,10 @@
#include <optional> #include <optional>
#include "../ncm_content_meta_database.hpp" #include "../ncm_content_meta_database.hpp"
#include "../ncm_content_storage.hpp" #include "../ncm_content_storage_impl.hpp"
#include "../ncm_fs.hpp" #include "../ncm_fs.hpp"
#include "../ncm_make_path.hpp" #include "../ncm_make_path.hpp"
#include "../ncm_read_only_content_storage.hpp" #include "../ncm_read_only_content_storage_impl.hpp"
#include "ncm_content_manager.hpp" #include "ncm_content_manager.hpp"
#include "ncm_rights_cache.hpp" #include "ncm_rights_cache.hpp"
@ -427,14 +427,14 @@ namespace ams::ncm::impl {
auto mount_guard = SCOPE_GUARD { fs::Unmount(root->mount_point); }; auto mount_guard = SCOPE_GUARD { fs::Unmount(root->mount_point); };
if (storage_id == StorageId::GameCard) { if (storage_id == StorageId::GameCard) {
auto content_storage = std::make_shared<ReadOnlyContentStorageInterface>(); auto content_storage = std::make_shared<ReadOnlyContentStorageImpl>();
R_TRY(content_storage->Initialize(root->path, path::MakeContentPathFlat)); R_TRY(content_storage->Initialize(root->path, path::MakeContentPathFlat));
root->content_storage = std::move(content_storage); root->content_storage = std::move(content_storage);
} else { } else {
MakeContentPathFunc content_path_func = nullptr; MakeContentPathFunc content_path_func = nullptr;
MakePlaceHolderPathFunc placeholder_path_func = nullptr; MakePlaceHolderPathFunc placeholder_path_func = nullptr;
bool delay_flush = false; bool delay_flush = false;
auto content_storage = std::make_shared<ContentStorageInterface>(); auto content_storage = std::make_shared<ContentStorageImpl>();
switch (storage_id) { switch (storage_id) {
case StorageId::BuiltInSystem: case StorageId::BuiltInSystem:

View File

@ -21,21 +21,22 @@
namespace ams::ncm::impl { namespace ams::ncm::impl {
class RightsIdCache { class RightsIdCache {
public: NON_COPYABLE(RightsIdCache);
NON_MOVEABLE(RightsIdCache);
private:
static constexpr size_t MaxEntries = 0x80; static constexpr size_t MaxEntries = 0x80;
public: private:
struct Entry { struct Entry {
public: public:
util::Uuid uuid; util::Uuid uuid;
FsRightsId rights_id; ncm::RightsId rights_id;
u64 key_generation;
u64 last_accessed; u64 last_accessed;
}; };
private:
Entry entries[MaxEntries]; Entry entries[MaxEntries];
u64 counter; u64 counter;
os::Mutex mutex; os::Mutex mutex;
public:
RightsIdCache() { RightsIdCache() {
this->Invalidate(); this->Invalidate();
} }
@ -46,6 +47,45 @@ namespace ams::ncm::impl {
this->entries[i].last_accessed = 1; this->entries[i].last_accessed = 1;
} }
} }
void Store(ContentId content_id, ncm::RightsId rights_id) {
std::scoped_lock lk(this->mutex);
Entry *eviction_candidate = &this->entries[0];
/* Find a suitable existing entry to store our new one at. */
for (size_t i = 1; i < MaxEntries; i++) {
Entry *entry = &this->entries[i];
/* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */
if (content_id == entry->uuid || (content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) {
eviction_candidate = entry;
}
}
/* Update the cache. */
eviction_candidate->uuid = content_id.uuid;
eviction_candidate->rights_id = rights_id;
eviction_candidate->last_accessed = this->counter;
this->counter++;
}
bool Find(ncm::RightsId *out_rights_id, ContentId content_id) {
std::scoped_lock lk(this->mutex);
/* Attempt to locate the content id in the cache. */
for (size_t i = 0; i < MaxEntries; i++) {
Entry *entry = &this->entries[i];
if (entry->last_accessed != 1 && content_id == entry->uuid) {
entry->last_accessed = this->counter;
this->counter++;
*out_rights_id = entry->rights_id;
return true;
}
}
return false;
}
}; };
} }

View File

@ -14,18 +14,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "ncm_content_storage.hpp" #include "ncm_content_storage_impl.hpp"
#include "ncm_fs.hpp" #include "ncm_fs.hpp"
#include "ncm_make_path.hpp" #include "ncm_make_path.hpp"
#include "ncm_utils.hpp" #include "ncm_utils.hpp"
namespace ams::ncm { namespace ams::ncm {
ContentStorageInterface::~ContentStorageInterface() { ContentStorageImpl::~ContentStorageImpl() {
this->Finalize(); this->Finalize();
} }
Result ContentStorageInterface::Initialize(const char *root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache *rights_id_cache) { Result ContentStorageImpl::Initialize(const char *root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache *rights_id_cache) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
R_TRY(fs::CheckContentStorageDirectoriesExist(root_path)); R_TRY(fs::CheckContentStorageDirectoriesExist(root_path));
const size_t root_path_len = strnlen(root_path, FS_MAX_PATH-1); const size_t root_path_len = strnlen(root_path, FS_MAX_PATH-1);
@ -39,19 +39,19 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
void ContentStorageInterface::Finalize() { void ContentStorageImpl::Finalize() {
this->ClearContentCache(); this->ClearContentCache();
this->placeholder_accessor.InvalidateAll(); this->placeholder_accessor.InvalidateAll();
} }
void ContentStorageInterface::ClearContentCache() { void ContentStorageImpl::ClearContentCache() {
if (this->cached_content_id != InvalidContentId) { if (this->cached_content_id != InvalidContentId) {
fclose(this->content_cache_file_handle); fclose(this->content_cache_file_handle);
this->cached_content_id = InvalidContentId; this->cached_content_id = InvalidContentId;
} }
} }
unsigned int ContentStorageInterface::GetContentDirectoryDepth() { unsigned int ContentStorageImpl::GetContentDirectoryDepth() {
if (this->make_content_path_func == static_cast<MakeContentPathFunc>(path::MakeContentPathFlat)) { if (this->make_content_path_func == static_cast<MakeContentPathFunc>(path::MakeContentPathFlat)) {
return 1; return 1;
} else if (this->make_content_path_func == static_cast<MakeContentPathFunc>(path::MakeContentPathHashByteLayered)) { } else if (this->make_content_path_func == static_cast<MakeContentPathFunc>(path::MakeContentPathHashByteLayered)) {
@ -65,7 +65,7 @@ namespace ams::ncm {
AMS_ABORT(); AMS_ABORT();
} }
Result ContentStorageInterface::OpenCachedContentFile(ContentId content_id) { Result ContentStorageImpl::OpenCachedContentFile(ContentId content_id) {
R_UNLESS(this->cached_content_id != content_id, ResultSuccess()); R_UNLESS(this->cached_content_id != content_id, ResultSuccess());
this->ClearContentCache(); this->ClearContentCache();
@ -80,13 +80,13 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) { Result ContentStorageImpl::GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
out.SetValue({util::GenerateUuid()}); out.SetValue({util::GenerateUuid()});
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) { Result ContentStorageImpl::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -98,12 +98,12 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) { Result ContentStorageImpl::DeletePlaceHolder(PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
return this->placeholder_accessor.Delete(placeholder_id); return this->placeholder_accessor.Delete(placeholder_id);
} }
Result ContentStorageInterface::HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) { Result ContentStorageImpl::HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char placeholder_path[FS_MAX_PATH] = {0}; char placeholder_path[FS_MAX_PATH] = {0};
@ -116,7 +116,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) { Result ContentStorageImpl::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) {
/* Offset is too large */ /* Offset is too large */
R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset()); R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset());
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -124,7 +124,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) { Result ContentStorageImpl::Register(PlaceHolderId placeholder_id, ContentId content_id) {
this->ClearContentCache(); this->ClearContentCache();
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -144,7 +144,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::Delete(ContentId content_id) { Result ContentStorageImpl::Delete(ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
this->ClearContentCache(); this->ClearContentCache();
@ -160,7 +160,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::Has(sf::Out<bool> out, ContentId content_id) { Result ContentStorageImpl::Has(sf::Out<bool> out, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -173,7 +173,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetPath(sf::Out<lr::Path> out, ContentId content_id) { Result ContentStorageImpl::GetPath(sf::Out<lr::Path> out, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -184,7 +184,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) { Result ContentStorageImpl::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char placeholder_path[FS_MAX_PATH] = {0}; char placeholder_path[FS_MAX_PATH] = {0};
@ -195,7 +195,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::CleanupAllPlaceHolder() { Result ContentStorageImpl::CleanupAllPlaceHolder() {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char placeholder_root_path[FS_MAX_PATH] = {0}; char placeholder_root_path[FS_MAX_PATH] = {0};
@ -209,7 +209,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) { Result ContentStorageImpl::ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char placeholder_root_path[FS_MAX_PATH] = {0}; char placeholder_root_path[FS_MAX_PATH] = {0};
@ -236,7 +236,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetContentCount(sf::Out<u32> out_count) { Result ContentStorageImpl::GetContentCount(sf::Out<u32> out_count) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_root_path[FS_MAX_PATH] = {0}; char content_root_path[FS_MAX_PATH] = {0};
@ -259,7 +259,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::ListContentId(sf::Out<u32> out_count, const sf::OutArray<ContentId> &out_buf, u32 start_offset) { Result ContentStorageImpl::ListContentId(sf::Out<u32> out_count, const sf::OutArray<ContentId> &out_buf, u32 start_offset) {
R_UNLESS(start_offset <= std::numeric_limits<s32>::max(), ncm::ResultInvalidOffset()); R_UNLESS(start_offset <= std::numeric_limits<s32>::max(), ncm::ResultInvalidOffset());
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -308,7 +308,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetSizeFromContentId(sf::Out<u64> out_size, ContentId content_id) { Result ContentStorageImpl::GetSizeFromContentId(sf::Out<u64> out_size, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -320,14 +320,14 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::DisableForcibly() { Result ContentStorageImpl::DisableForcibly() {
this->disabled = true; this->disabled = true;
this->ClearContentCache(); this->ClearContentCache();
this->placeholder_accessor.InvalidateAll(); this->placeholder_accessor.InvalidateAll();
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { Result ContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char old_content_path[FS_MAX_PATH] = {0}; char old_content_path[FS_MAX_PATH] = {0};
@ -352,13 +352,13 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) { Result ContentStorageImpl::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
R_TRY(this->placeholder_accessor.SetSize(placeholder_id, size)); R_TRY(this->placeholder_accessor.SetSize(placeholder_id, size));
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) { Result ContentStorageImpl::ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) {
/* Offset is too large */ /* Offset is too large */
R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset()); R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset());
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -370,82 +370,43 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetRightsIdFromPlaceHolderId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id) { Result ContentStorageImpl::GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
FsRightsId rights_id = {0};
u8 key_generation = 0;
char placeholder_path[FS_MAX_PATH] = {0}; char placeholder_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.GetPath(placeholder_path, placeholder_id); this->placeholder_accessor.GetPath(placeholder_path, placeholder_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path)); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path));
R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id));
ncm::RightsId rights_id;
R_TRY(GetRightsId(&rights_id, common_path));
out_rights_id.SetValue(rights_id); out_rights_id.SetValue(rights_id);
out_key_generation.SetValue(static_cast<u64>(key_generation));
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetRightsIdFromContentId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, ContentId content_id) { Result ContentStorageImpl::GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
{ if (this->rights_id_cache->Find(out_rights_id.GetPointer(), content_id)) {
std::scoped_lock lk(this->rights_id_cache->mutex);
/* Attempt to locate the content id in the cache. */
for (size_t i = 0; i < impl::RightsIdCache::MaxEntries; i++) {
impl::RightsIdCache::Entry *entry = &this->rights_id_cache->entries[i];
if (entry->last_accessed != 1 && content_id == entry->uuid) {
entry->last_accessed = this->rights_id_cache->counter;
this->rights_id_cache->counter++;
out_rights_id.SetValue(entry->rights_id);
out_key_generation.SetValue(entry->key_generation);
return ResultSuccess(); return ResultSuccess();
} }
}
}
FsRightsId rights_id = {0};
u8 key_generation = 0;
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0};
this->GetContentPath(content_path, content_id); this->GetContentPath(content_path, content_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id));
{ ncm::RightsId rights_id;
std::scoped_lock lk(this->rights_id_cache->mutex); R_TRY(GetRightsId(&rights_id, common_path));
impl::RightsIdCache::Entry *eviction_candidate = &this->rights_id_cache->entries[0]; this->rights_id_cache->Store(content_id, rights_id);
/* Find a suitable existing entry to store our new one at. */
for (size_t i = 1; i < impl::RightsIdCache::MaxEntries; i++) {
impl::RightsIdCache::Entry *entry = &this->rights_id_cache->entries[i];
/* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */
if (content_id == entry->uuid || (content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) {
eviction_candidate = entry;
}
}
/* Update the cache. */
eviction_candidate->uuid = content_id.uuid;
eviction_candidate->rights_id = rights_id;
eviction_candidate->key_generation = key_generation;
eviction_candidate->last_accessed = this->rights_id_cache->counter;
this->rights_id_cache->counter++;
/* Set output. */ /* Set output. */
out_rights_id.SetValue(rights_id); out_rights_id.SetValue(rights_id);
out_key_generation.SetValue(key_generation);
}
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) { Result ContentStorageImpl::WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) {
/* Offset is too large */ /* Offset is too large */
R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset()); R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset());
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -472,26 +433,26 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetFreeSpaceSize(sf::Out<u64> out_size) { Result ContentStorageImpl::GetFreeSpaceSize(sf::Out<u64> out_size) {
struct statvfs st = {0}; struct statvfs st = {0};
R_UNLESS(statvfs(this->root_path, &st) != -1, fsdevGetLastResult()); R_UNLESS(statvfs(this->root_path, &st) != -1, fsdevGetLastResult());
out_size.SetValue(st.f_bfree); out_size.SetValue(st.f_bfree);
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetTotalSpaceSize(sf::Out<u64> out_size) { Result ContentStorageImpl::GetTotalSpaceSize(sf::Out<u64> out_size) {
struct statvfs st = {0}; struct statvfs st = {0};
R_UNLESS(statvfs(this->root_path, &st) != -1, fsdevGetLastResult()); R_UNLESS(statvfs(this->root_path, &st) != -1, fsdevGetLastResult());
out_size.SetValue(st.f_blocks); out_size.SetValue(st.f_blocks);
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::FlushPlaceHolder() { Result ContentStorageImpl::FlushPlaceHolder() {
this->placeholder_accessor.InvalidateAll(); this->placeholder_accessor.InvalidateAll();
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetSizeFromPlaceHolderId(sf::Out<u64> out_size, PlaceHolderId placeholder_id) { Result ContentStorageImpl::GetSizeFromPlaceHolderId(sf::Out<u64> out_size, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
bool found_in_cache = false; bool found_in_cache = false;
@ -514,7 +475,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::RepairInvalidFileAttribute() { Result ContentStorageImpl::RepairInvalidFileAttribute() {
char content_root_path[FS_MAX_PATH] = {0}; char content_root_path[FS_MAX_PATH] = {0};
this->GetContentRootPath(content_root_path); this->GetContentRootPath(content_root_path);
unsigned int dir_depth = this->GetContentDirectoryDepth(); unsigned int dir_depth = this->GetContentDirectoryDepth();
@ -545,59 +506,25 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) { Result ContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
{ if (this->rights_id_cache->Find(out_rights_id.GetPointer(), cache_content_id)) {
std::scoped_lock lk(this->rights_id_cache->mutex);
/* Attempt to locate the content id in the cache. */
for (size_t i = 0; i < impl::RightsIdCache::MaxEntries; i++) {
impl::RightsIdCache::Entry *entry = &this->rights_id_cache->entries[i];
if (entry->last_accessed != 1 && cache_content_id == entry->uuid) {
entry->last_accessed = this->rights_id_cache->counter;
this->rights_id_cache->counter++;
out_rights_id.SetValue(entry->rights_id);
out_key_generation.SetValue(entry->key_generation);
return ResultSuccess(); return ResultSuccess();
} }
}
}
FsRightsId rights_id = {0};
u8 key_generation = 0;
char placeholder_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0};
char placeholder_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.GetPath(placeholder_path, placeholder_id); this->placeholder_accessor.GetPath(placeholder_path, placeholder_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path)); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path));
R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id));
{ ncm::RightsId rights_id;
std::scoped_lock lk(this->rights_id_cache->mutex); R_TRY(GetRightsId(&rights_id, common_path));
impl::RightsIdCache::Entry *eviction_candidate = &this->rights_id_cache->entries[0]; this->rights_id_cache->Store(cache_content_id, rights_id);
/* Find a suitable existing entry to store our new one at. */
for (size_t i = 1; i < impl::RightsIdCache::MaxEntries; i++) {
impl::RightsIdCache::Entry *entry = &this->rights_id_cache->entries[i];
/* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */
if (cache_content_id == entry->uuid || (cache_content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) {
eviction_candidate = entry;
}
}
/* Update the cache. */
eviction_candidate->uuid = cache_content_id.uuid;
eviction_candidate->rights_id = rights_id;
eviction_candidate->key_generation = key_generation;
eviction_candidate->last_accessed = this->rights_id_cache->counter;
this->rights_id_cache->counter++;
/* Set output. */ /* Set output. */
out_rights_id.SetValue(rights_id); out_rights_id.SetValue(rights_id);
out_key_generation.SetValue(key_generation);
}
return ResultSuccess(); return ResultSuccess();
} }

View File

@ -20,18 +20,19 @@
#include "impl/ncm_placeholder_accessor.hpp" #include "impl/ncm_placeholder_accessor.hpp"
#include "impl/ncm_rights_cache.hpp" #include "impl/ncm_rights_cache.hpp"
#include "ncm_content_storage_impl_base.hpp"
#include "ncm_path_utils.hpp" #include "ncm_path_utils.hpp"
namespace ams::ncm { namespace ams::ncm {
class ContentStorageInterface : public IContentStorage { class ContentStorageImpl : public ContentStorageImplBase {
protected: protected:
impl::PlaceHolderAccessor placeholder_accessor; impl::PlaceHolderAccessor placeholder_accessor;
ContentId cached_content_id; ContentId cached_content_id;
FILE *content_cache_file_handle; FILE *content_cache_file_handle;
impl::RightsIdCache *rights_id_cache; impl::RightsIdCache *rights_id_cache;
public: public:
~ContentStorageInterface(); ~ContentStorageImpl();
Result Initialize(const char *root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache *rights_id_cache); Result Initialize(const char *root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache *rights_id_cache);
void Finalize(); void Finalize();
@ -70,15 +71,15 @@ namespace ams::ncm {
virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override; virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override;
virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override; virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override;
virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override; virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override;
virtual Result GetRightsIdFromPlaceHolderId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id) override; virtual Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) override;
virtual Result GetRightsIdFromContentId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, ContentId content_id) override; virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) override;
virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override; virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override;
virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) override; virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) override;
virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) override; virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) override;
virtual Result FlushPlaceHolder() override; virtual Result FlushPlaceHolder() override;
virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) override; virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) override;
virtual Result RepairInvalidFileAttribute() override; virtual Result RepairInvalidFileAttribute() override;
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) override; virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) override;
}; };
} }

View File

@ -0,0 +1,48 @@
/*
* 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 ContentStorageImplBase : public IContentStorage {
NON_COPYABLE(ContentStorageImplBase);
NON_MOVEABLE(ContentStorageImplBase);
protected:
char root_path[FS_MAX_PATH-1];
MakeContentPathFunc make_content_path_func;
bool disabled;
protected:
ContentStorageImplBase() { /* ... */ }
protected:
Result EnsureEnabled() {
R_UNLESS(!this->disabled, ncm::ResultInvalidContentStorage());
return ResultSuccess();
}
static Result GetRightsId(ncm::RightsId *out_rights_id, const char *path) {
if (hos::GetVersion() >= hos::Version_300) {
R_TRY(ams::fs::GetRightsId(std::addressof(out_rights_id->id), std::addressof(out_rights_id->key_generation), path));
} else {
R_TRY(ams::fs::GetRightsId(std::addressof(out_rights_id->id), path));
out_rights_id->key_generation = 0;
}
return ResultSuccess();
}
};
}

View File

@ -44,7 +44,7 @@ namespace ams::ncm::fs {
return ResultSuccess(); return ResultSuccess();
} }
Result WriteFile(FILE *f, size_t offset, const void *buffer, size_t size, u32 option) { Result WriteFile(FILE *f, size_t offset, const void *buffer, size_t size, ams::fs::WriteOption option) {
R_UNLESS(fseek(f, 0, SEEK_END) == 0, fsdevGetLastResult()); R_UNLESS(fseek(f, 0, SEEK_END) == 0, fsdevGetLastResult());
size_t existing_size = ftell(f); size_t existing_size = ftell(f);
@ -52,7 +52,7 @@ namespace ams::ncm::fs {
R_UNLESS(fseek(f, offset, SEEK_SET) == 0, fsdevGetLastResult()); R_UNLESS(fseek(f, offset, SEEK_SET) == 0, fsdevGetLastResult());
R_UNLESS(fwrite(buffer, 1, size, f) == size, fsdevGetLastResult()); R_UNLESS(fwrite(buffer, 1, size, f) == size, fsdevGetLastResult());
if (option & FsWriteOption_Flush) { if (option.HasFlushFlag()) {
fflush(f); fflush(f);
} }

View File

@ -16,11 +16,11 @@
#include "ncm_fs.hpp" #include "ncm_fs.hpp"
#include "ncm_path_utils.hpp" #include "ncm_path_utils.hpp"
#include "ncm_read_only_content_storage.hpp" #include "ncm_read_only_content_storage_impl.hpp"
namespace ams::ncm { namespace ams::ncm {
Result ReadOnlyContentStorageInterface::Initialize(const char *root_path, MakeContentPathFunc content_path_func) { Result ReadOnlyContentStorageImpl::Initialize(const char *root_path, MakeContentPathFunc content_path_func) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
const size_t root_path_len = strnlen(root_path, FS_MAX_PATH-1); const size_t root_path_len = strnlen(root_path, FS_MAX_PATH-1);
@ -30,35 +30,35 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) { Result ReadOnlyContentStorageImpl::GeneratePlaceHolderId(sf::Out<PlaceHolderId> out) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) { Result ReadOnlyContentStorageImpl::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) { Result ReadOnlyContentStorageImpl::DeletePlaceHolder(PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) { Result ReadOnlyContentStorageImpl::HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) { Result ReadOnlyContentStorageImpl::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) { Result ReadOnlyContentStorageImpl::Register(PlaceHolderId placeholder_id, ContentId content_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::Delete(ContentId content_id) { Result ReadOnlyContentStorageImpl::Delete(ContentId content_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::Has(sf::Out<bool> out, ContentId content_id) { Result ReadOnlyContentStorageImpl::Has(sf::Out<bool> out, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -76,7 +76,7 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::GetPath(sf::Out<lr::Path> out, ContentId content_id) { Result ReadOnlyContentStorageImpl::GetPath(sf::Out<lr::Path> out, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -96,27 +96,27 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) { Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out<lr::Path> out, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::CleanupAllPlaceHolder() { Result ReadOnlyContentStorageImpl::CleanupAllPlaceHolder() {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) { Result ReadOnlyContentStorageImpl::ListPlaceHolder(sf::Out<u32> out_count, const sf::OutArray<PlaceHolderId> &out_buf) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetContentCount(sf::Out<u32> out_count) { Result ReadOnlyContentStorageImpl::GetContentCount(sf::Out<u32> out_count) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::ListContentId(sf::Out<u32> out_count, const sf::OutArray<ContentId> &out_buf, u32 start_offset) { Result ReadOnlyContentStorageImpl::ListContentId(sf::Out<u32> out_count, const sf::OutArray<ContentId> &out_buf, u32 start_offset) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetSizeFromContentId(sf::Out<u64> out_size, ContentId content_id) { Result ReadOnlyContentStorageImpl::GetSizeFromContentId(sf::Out<u64> out_size, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
@ -135,20 +135,20 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::DisableForcibly() { Result ReadOnlyContentStorageImpl::DisableForcibly() {
this->disabled = true; this->disabled = true;
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { Result ReadOnlyContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) { Result ReadOnlyContentStorageImpl::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) { Result ReadOnlyContentStorageImpl::ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) {
/* Offset is too large */ /* Offset is too large */
R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset()); R_UNLESS(offset <= std::numeric_limits<s64>::max(), ncm::ResultInvalidOffset());
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
@ -174,16 +174,13 @@ namespace ams::ncm {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id) { Result ReadOnlyContentStorageImpl::GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetRightsIdFromContentId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, ContentId content_id) { Result ReadOnlyContentStorageImpl::GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) {
R_TRY(this->EnsureEnabled()); R_TRY(this->EnsureEnabled());
FsRightsId rights_id = {0};
u8 key_generation = 0;
char content_path[FS_MAX_PATH] = {0}; char content_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0}; char common_path[FS_MAX_PATH] = {0};
bool is_content_meta_file = false; bool is_content_meta_file = false;
@ -196,41 +193,41 @@ namespace ams::ncm {
} }
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id));
ncm::RightsId rights_id;
R_TRY(GetRightsId(&rights_id, common_path));
out_rights_id.SetValue(rights_id); out_rights_id.SetValue(rights_id);
out_key_generation.SetValue(static_cast<u64>(key_generation));
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) { Result ReadOnlyContentStorageImpl::WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetFreeSpaceSize(sf::Out<u64> out_size) { Result ReadOnlyContentStorageImpl::GetFreeSpaceSize(sf::Out<u64> out_size) {
out_size.SetValue(0); out_size.SetValue(0);
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::GetTotalSpaceSize(sf::Out<u64> out_size) { Result ReadOnlyContentStorageImpl::GetTotalSpaceSize(sf::Out<u64> out_size) {
out_size.SetValue(0); out_size.SetValue(0);
return ResultSuccess(); return ResultSuccess();
} }
Result ReadOnlyContentStorageInterface::FlushPlaceHolder() { Result ReadOnlyContentStorageImpl::FlushPlaceHolder() {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) { Result ReadOnlyContentStorageImpl::GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::RepairInvalidFileAttribute() { Result ReadOnlyContentStorageImpl::RepairInvalidFileAttribute() {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }
Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) { Result ReadOnlyContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
return ResultInvalidContentStorageOperation(); return ResultInvalidContentStorageOperation();
} }

View File

@ -17,10 +17,11 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ncm_content_storage_impl_base.hpp"
namespace ams::ncm { namespace ams::ncm {
class ReadOnlyContentStorageInterface : public IContentStorage { class ReadOnlyContentStorageImpl : public ContentStorageImplBase {
public: public:
Result Initialize(const char *root_path, MakeContentPathFunc content_path_func); Result Initialize(const char *root_path, MakeContentPathFunc content_path_func);
public: public:
@ -43,15 +44,15 @@ namespace ams::ncm {
virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override; virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override;
virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override; virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override;
virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override; virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override;
virtual Result GetRightsIdFromPlaceHolderId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id) override; virtual Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id) override;
virtual Result GetRightsIdFromContentId(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, ContentId content_id) override; virtual Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id) override;
virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override; virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override;
virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) override; virtual Result GetFreeSpaceSize(sf::Out<u64> out_size) override;
virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) override; virtual Result GetTotalSpaceSize(sf::Out<u64> out_size) override;
virtual Result FlushPlaceHolder() override; virtual Result FlushPlaceHolder() override;
virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) override; virtual Result GetSizeFromPlaceHolderId(sf::Out<u64> out, PlaceHolderId placeholder_id) override;
virtual Result RepairInvalidFileAttribute() override; virtual Result RepairInvalidFileAttribute() override;
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<FsRightsId> out_rights_id, sf::Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) override; virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) override;
}; };
} }