mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes
This commit is contained in:
parent
b2dd198dc8
commit
ef28b7d395
16 changed files with 639 additions and 174 deletions
142
stratosphere/ncm/source/debug.cpp
Normal file
142
stratosphere/ncm/source/debug.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include <stratosphere/sm.hpp>
|
||||
|
||||
#include "impl/ncm_content_manager.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "ncm_fs.hpp"
|
||||
|
||||
namespace sts::debug {
|
||||
|
||||
#define IRAM_BASE 0x40000000ull
|
||||
#define IRAM_SIZE 0x40000
|
||||
|
||||
#define IRAM_PAYLOAD_MAX_SIZE 0x2F000
|
||||
#define IRAM_PAYLOAD_BASE 0x40010000ull
|
||||
|
||||
#define IRAM_SAFE_START 0x40038000ull
|
||||
#define IRAM_SAFE_END 0x4003D000ull
|
||||
#define IRAM_SAFE_SIZE IRAM_SAFE_END - IRAM_SAFE_START
|
||||
|
||||
namespace {
|
||||
|
||||
HosMutex g_log_mutex;
|
||||
|
||||
}
|
||||
|
||||
size_t g_curr_log_offset = 0;
|
||||
size_t g_log_skip = 4;
|
||||
|
||||
char __attribute__ ((aligned (0x1000))) g_work_page[0x1000];
|
||||
|
||||
void clear_iram(void) {
|
||||
/* Fill with null*/
|
||||
memset(g_work_page, 0, sizeof(g_work_page));
|
||||
|
||||
/* Overwrite all of our log's IRAM with 0s. */
|
||||
for (size_t ofs = 0; ofs < IRAM_SAFE_SIZE; ofs += sizeof(g_work_page)) {
|
||||
CopyToIram(IRAM_SAFE_START + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
}
|
||||
|
||||
void clear_log(void) {
|
||||
std::scoped_lock lk(g_log_mutex);
|
||||
|
||||
clear_iram();
|
||||
}
|
||||
|
||||
Result Initialize() {
|
||||
clear_log();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void DebugLog(const char* format, ...) {
|
||||
std::scoped_lock lk(g_log_mutex);
|
||||
memset(g_work_page, 0, sizeof(g_work_page));
|
||||
|
||||
/* Format a string with our arguments. */
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(g_work_page, 0x1000, format, args);
|
||||
va_end(args);
|
||||
|
||||
size_t msg_len = strnlen(g_work_page, 0x1000);
|
||||
|
||||
/* Nothing to log. */
|
||||
if (msg_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Attempt to put some of our new string in the previous 4 bytes. */
|
||||
if (g_curr_log_offset >= 4) {
|
||||
char __attribute__ ((aligned (0x4))) prev_4[4] = {0};
|
||||
CopyFromIram(prev_4, IRAM_SAFE_START+g_curr_log_offset-4, 4);
|
||||
size_t prev_4_size = strnlen(prev_4, 4);
|
||||
|
||||
/* Do we have room to put some of our new string in the old one? */
|
||||
if (prev_4_size < 4) {
|
||||
size_t spare_4_space = 4 - prev_4_size;
|
||||
memcpy(prev_4 + prev_4_size, g_work_page, spare_4_space);
|
||||
|
||||
/* Copy the previous 4 bytes back. */
|
||||
CopyToIram(IRAM_SAFE_START+g_curr_log_offset-4, prev_4, 4);
|
||||
memmove(g_work_page, g_work_page + spare_4_space, 0x1000-spare_4_space);
|
||||
/* Update our size again. */
|
||||
msg_len = strnlen(g_work_page, 0x1000);
|
||||
}
|
||||
}
|
||||
|
||||
size_t msg_len_aligned = (msg_len + 3) & ~3;
|
||||
|
||||
if (g_curr_log_offset + msg_len_aligned > IRAM_SAFE_SIZE) {
|
||||
if (g_log_skip == 0) {
|
||||
/* Log is full. Reboot to RCM to read it. */
|
||||
RebootToRcm();
|
||||
return;
|
||||
}
|
||||
|
||||
g_log_skip--;
|
||||
clear_iram();
|
||||
g_curr_log_offset = 0;
|
||||
}
|
||||
|
||||
/* Fill remainder with 0s. */
|
||||
if (msg_len_aligned > msg_len) {
|
||||
memset(g_work_page + msg_len, '\0', msg_len_aligned - msg_len);
|
||||
}
|
||||
|
||||
uintptr_t iram_out_start = IRAM_SAFE_START+g_curr_log_offset;
|
||||
uintptr_t iram_next_page = (iram_out_start + 0x1000-1) & ~(0x1000-1);
|
||||
|
||||
/* We are copying across two pages */
|
||||
if (iram_out_start + msg_len_aligned > iram_next_page) {
|
||||
size_t first_page_size = iram_next_page - iram_out_start;
|
||||
CopyToIram(iram_out_start, g_work_page, first_page_size);
|
||||
CopyToIram(iram_next_page, g_work_page+first_page_size, msg_len_aligned-first_page_size);
|
||||
} else {
|
||||
CopyToIram(iram_out_start, g_work_page, msg_len_aligned);
|
||||
}
|
||||
|
||||
g_curr_log_offset += msg_len_aligned;
|
||||
}
|
||||
|
||||
void LogBytes(const void* buf, size_t len) {
|
||||
if (buf == NULL || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u8* bytes = static_cast<const u8*>(buf);
|
||||
int count = 0;
|
||||
DebugLog("\n\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
||||
DebugLog("-----------------------------------------------\n");
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
DebugLog("%02x ", bytes[i]);
|
||||
count++;
|
||||
if ((count % 16) == 0) {
|
||||
DebugLog("\n");
|
||||
}
|
||||
}
|
||||
|
||||
DebugLog("\n");
|
||||
}
|
||||
}
|
||||
|
39
stratosphere/ncm/source/debug.hpp
Normal file
39
stratosphere/ncm/source/debug.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Adubbz
|
||||
*
|
||||
* 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace sts::debug {
|
||||
#define STR_(X) #X
|
||||
#define STR(X) STR_(X)
|
||||
|
||||
#define D_LOG(format, ...) \
|
||||
debug::DebugLog("%s:" STR(__LINE__) " " format, __FUNCTION__, ##__VA_ARGS__);
|
||||
#define R_DEBUG_START \
|
||||
Result rc = [&]() -> Result {
|
||||
#define R_DEBUG_END \
|
||||
}(); \
|
||||
D_LOG(" -> 0x%08" PRIX32 "\n", rc); \
|
||||
return rc;
|
||||
|
||||
Result Initialize();
|
||||
void DebugLog(const char* format, ...);
|
||||
void LogBytes(const void* buf, size_t len);
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp>
|
||||
#include <optional>
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "../ncm_contentmetadatabase.hpp"
|
||||
#include "../ncm_contentstorage.hpp"
|
||||
#include "../ncm_fs.hpp"
|
||||
|
@ -62,7 +63,7 @@ namespace sts::ncm::impl {
|
|||
u64 journal_size;
|
||||
u32 flags;
|
||||
FsSaveDataSpaceId space_id;
|
||||
} PACKED;
|
||||
};
|
||||
|
||||
static_assert(sizeof(SaveDataMeta) == 0x20, "SaveDataMeta definition!");
|
||||
|
||||
|
@ -150,6 +151,9 @@ namespace sts::ncm::impl {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
R_ASSERT(debug::Initialize());
|
||||
debug::DebugLog("ContentManager::InitializeContentManager\n");
|
||||
|
||||
size_t cur_storage_index = g_num_content_storage_entries;
|
||||
|
||||
for (size_t i = 0; i < MaxContentStorageEntries; i++) {
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "../ncm_make_path.hpp"
|
||||
#include "../ncm_path_utils.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
|
||||
namespace sts::ncm::impl {
|
||||
|
||||
unsigned int PlaceHolderAccessor::GetDirectoryDepth() {
|
||||
|
@ -78,6 +80,8 @@ namespace sts::ncm::impl {
|
|||
|
||||
this->GetPlaceHolderPathUncached(placeholder_path, placeholder_id);
|
||||
|
||||
debug::DebugLog("Deleting %s\n", placeholder_path);
|
||||
|
||||
R_TRY_CATCH(fsdevDeleteDirectoryRecursively(placeholder_path)) {
|
||||
R_CATCH(ResultFsPathNotFound) {
|
||||
return ResultNcmPlaceHolderNotFound;
|
||||
|
@ -97,6 +101,7 @@ namespace sts::ncm::impl {
|
|||
FILE* f = fopen(placeholder_path, "r+b");
|
||||
|
||||
if (f == nullptr) {
|
||||
debug::DebugLog("Failed to open placeholder %s\n", placeholder_path);
|
||||
return fsdevGetLastResult();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "impl/ncm_content_manager.hpp"
|
||||
#include "lr_contentlocationresolver.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::lr {
|
||||
|
||||
ContentLocationResolverInterface::~ContentLocationResolverInterface() {
|
||||
|
@ -28,6 +30,7 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->program_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -46,14 +49,18 @@ namespace sts::lr {
|
|||
R_ASSERT(this->content_storage->GetPath(&path, program_content_id));
|
||||
*out.pointer = path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.SetRedirection(tid, *path.pointer);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveApplicationControlPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->app_control_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -62,9 +69,11 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrControlNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveApplicationHtmlDocumentPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->html_docs_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -73,9 +82,11 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrHtmlDocumentNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveDataPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
ncm::ContentId data_content_id;
|
||||
|
||||
|
@ -83,19 +94,25 @@ namespace sts::lr {
|
|||
R_ASSERT(this->content_storage->GetPath(&path, data_content_id));
|
||||
*out.pointer = path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectApplicationControlPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->app_control_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectApplicationHtmlDocumentPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->html_docs_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveApplicationLegalInformationPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->legal_info_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -104,14 +121,18 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrLegalInformationNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectApplicationLegalInformationPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->legal_info_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::Refresh() {
|
||||
R_DEBUG_START
|
||||
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));
|
||||
|
@ -126,43 +147,57 @@ namespace sts::lr {
|
|||
this->legal_info_redirector.ClearRedirections();
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectApplicationProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ClearApplicationRedirection() {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->debug_program_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->app_control_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->html_docs_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->legal_info_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::EraseProgramRedirection(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::EraseApplicationControlRedirection(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->app_control_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::EraseApplicationHtmlDocumentRedirection(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->html_docs_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::EraseApplicationLegalInformationRedirection(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->legal_info_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::ResolveProgramPathForDebug(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->debug_program_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -178,21 +213,28 @@ namespace sts::lr {
|
|||
|
||||
*out.pointer = path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectProgramPathForDebug(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->debug_program_redirector.SetRedirection(tid, *path.pointer);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::RedirectApplicationProgramPathForDebug(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->debug_program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentLocationResolverInterface::EraseProgramRedirectionForDebug(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->debug_program_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -13,26 +13,37 @@
|
|||
* 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 <inttypes.h>
|
||||
|
||||
#include "impl/lr_manager.hpp"
|
||||
#include "lr_manager_service.hpp"
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::lr {
|
||||
|
||||
Result LocationResolverManagerService::OpenLocationResolver(Out<std::shared_ptr<ILocationResolver>> out, ncm::StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::OpenLocationResolver(out, storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result LocationResolverManagerService::OpenRegisteredLocationResolver(Out<std::shared_ptr<RegisteredLocationResolverInterface>> out) {
|
||||
R_DEBUG_START
|
||||
return impl::OpenRegisteredLocationResolver(out);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result LocationResolverManagerService::RefreshLocationResolver(ncm::StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
D_LOG("storage_id: 0x%x\n", static_cast<u8>(storage_id));
|
||||
return impl::RefreshLocationResolver(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result LocationResolverManagerService::OpenAddOnContentLocationResolver(Out<std::shared_ptr<AddOnContentLocationResolverInterface>> out) {
|
||||
R_DEBUG_START
|
||||
return impl::OpenAddOnContentLocationResolver(out);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,8 @@
|
|||
#include "impl/ncm_content_manager.hpp"
|
||||
#include "lr_redirectonlylocationresolver.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::lr {
|
||||
|
||||
RedirectOnlyLocationResolverInterface::~RedirectOnlyLocationResolverInterface() {
|
||||
|
@ -28,6 +30,7 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->program_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -36,14 +39,18 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrProgramNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::RedirectProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.SetRedirection(tid, *path.pointer);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ResolveApplicationControlPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->app_control_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -52,9 +59,11 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrControlNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ResolveApplicationHtmlDocumentPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->html_docs_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -63,23 +72,31 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrHtmlDocumentNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ResolveDataPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
return ResultLrDataNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::RedirectApplicationControlPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->app_control_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::RedirectApplicationHtmlDocumentPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->html_docs_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ResolveApplicationLegalInformationPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (this->legal_info_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -88,39 +105,50 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultLrLegalInformationNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::RedirectApplicationLegalInformationPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->legal_info_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::Refresh() {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.ClearRedirections();
|
||||
this->debug_program_redirector.ClearRedirections();
|
||||
this->app_control_redirector.ClearRedirections();
|
||||
this->html_docs_redirector.ClearRedirections();
|
||||
this->legal_info_redirector.ClearRedirections();
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::RedirectApplicationProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::ClearApplicationRedirection() {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->debug_program_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->app_control_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->html_docs_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
this->legal_info_redirector.ClearRedirections(impl::RedirectionFlags_Application);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::EraseProgramRedirection(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->program_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RedirectOnlyLocationResolverInterface::EraseApplicationControlRedirection(ncm::TitleId tid) {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "lr_registeredlocationresolver.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::lr {
|
||||
|
||||
RegisteredLocationResolverInterface::RegisteredLocationResolverInterface() {
|
||||
|
@ -30,6 +32,7 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (!this->program_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -40,9 +43,11 @@ namespace sts::lr {
|
|||
|
||||
*out.pointer = path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::RegisterProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path tmp_path = *path.pointer;
|
||||
|
||||
if (!this->registered_program_redirector.SetRedirection(tid, tmp_path)) {
|
||||
|
@ -51,20 +56,26 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::UnregisterProgramPath(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->registered_program_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::RedirectProgramPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path tmp_path = *path.pointer;
|
||||
this->program_redirector.SetRedirection(tid, tmp_path);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::ResolveHtmlDocumentPath(OutPointerWithServerSize<Path, 0x1> out, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path path;
|
||||
|
||||
if (!this->html_docs_redirector.FindRedirection(&path, tid)) {
|
||||
|
@ -75,9 +86,11 @@ namespace sts::lr {
|
|||
|
||||
*out.pointer = path;
|
||||
return ResultLrHtmlDocumentNotFound;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::RegisterHtmlDocumentPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path tmp_path = *path.pointer;
|
||||
|
||||
if (!this->registered_html_docs_redirector.SetRedirection(tid, tmp_path)) {
|
||||
|
@ -86,23 +99,30 @@ namespace sts::lr {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::UnregisterHtmlDocumentPath(ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
this->registered_html_docs_redirector.EraseRedirection(tid);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::RedirectHtmlDocumentPath(InPointer<const Path> path, ncm::TitleId tid) {
|
||||
R_DEBUG_START
|
||||
Path tmp_path = *path.pointer;
|
||||
this->html_docs_redirector.SetRedirection(tid, tmp_path);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result RegisteredLocationResolverInterface::Refresh() {
|
||||
R_DEBUG_START
|
||||
this->registered_program_redirector.ClearRedirections();
|
||||
this->registered_html_docs_redirector.ClearRedirections();
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,8 @@
|
|||
#include "impl/ncm_content_manager.hpp"
|
||||
#include "ncm_content_manager_service.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::ncm {
|
||||
|
||||
ContentManagerService::~ContentManagerService() {
|
||||
|
@ -24,61 +26,87 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
Result ContentManagerService::CreateContentStorage(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::CreateContentStorage(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::CreateContentMetaDatabase(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::CreateContentMetaDatabase(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::VerifyContentStorage(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::VerifyContentStorage(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::VerifyContentMetaDatabase(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::VerifyContentMetaDatabase(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::OpenContentStorage(Out<std::shared_ptr<IContentStorage>> out, StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
std::shared_ptr<IContentStorage> content_storage;
|
||||
R_TRY(impl::OpenContentStorage(&content_storage, storage_id));
|
||||
out.SetValue(std::move(content_storage));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::OpenContentMetaDatabase(Out<std::shared_ptr<IContentMetaDatabase>> out, StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
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;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::CloseContentStorageForcibly(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::CloseContentStorageForcibly(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::CloseContentMetaDatabaseForcibly(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::CloseContentMetaDatabaseForcibly(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::CleanupContentMetaDatabase(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::CleanupContentMetaDatabase(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::ActivateContentStorage(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::ActivateContentStorage(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::InactivateContentStorage(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::InactivateContentStorage(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::ActivateContentMetaDatabase(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::ActivateContentMetaDatabase(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentManagerService::InactivateContentMetaDatabase(StorageId storage_id) {
|
||||
R_DEBUG_START
|
||||
return impl::InactivateContentMetaDatabase(storage_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,8 @@
|
|||
#include "ncm_contentmetadatabase.hpp"
|
||||
#include "ncm_utils.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::ncm {
|
||||
|
||||
namespace {
|
||||
|
@ -91,9 +93,7 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetContentIdByTypeImpl(ContentId* out, const ContentMetaKey& key, ContentType type, std::optional<u8> id_offset) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
const auto it = this->kvs->lower_bound(key);
|
||||
if (it == this->kvs->end() || it->GetKey().id != key.id) {
|
||||
|
@ -146,25 +146,13 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetLatestContentMetaKeyImpl(ContentMetaKey* out_key, TitleId tid) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
ContentMetaKey key = {0};
|
||||
key.id = tid;
|
||||
|
||||
if (this->kvs->GetCount() == 0) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
}
|
||||
|
||||
auto entry = this->kvs->lower_bound(key);
|
||||
if (entry == this->kvs->end()) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
}
|
||||
|
||||
bool found_key = false;
|
||||
|
||||
for (; entry != this->kvs->end(); entry++) {
|
||||
for (auto entry = this->kvs->lower_bound(key); entry != this->kvs->end(); entry++) {
|
||||
if (entry->GetKey().id != key.id) {
|
||||
break;
|
||||
}
|
||||
|
@ -183,31 +171,41 @@ namespace sts::ncm {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::Set(ContentMetaKey key, InBuffer<u8> value) {
|
||||
Result ContentMetaDatabaseInterface::EnsureEnabled() {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
||||
Result ContentMetaDatabaseInterface::Set(ContentMetaKey key, InBuffer<u8> value) {
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
D_LOG(" set title_id: 0x%lx\n", key.id);
|
||||
D_LOG(" set version: 0x%x\n", key.version);
|
||||
|
||||
R_TRY(this->kvs->Set(key, value.buffer, value.num_elements));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::Get(Out<u64> out_size, ContentMetaKey key, OutBuffer<u8> out_value) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
R_TRY(this->kvs->Get(out_size.GetPointer(), out_value.buffer, out_value.num_elements, key));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::Remove(ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
R_TRY(this->kvs->Remove(key));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetContentIdByType(Out<ContentId> out_content_id, ContentMetaKey key, ContentType type) {
|
||||
|
@ -217,45 +215,33 @@ namespace sts::ncm {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::ListContentInfo(Out<u32> out_entries_written, OutBuffer<ContentInfo> out_info, ContentMetaKey key, u32 start_index) {
|
||||
if (start_index >> 0x1f != 0) {
|
||||
Result ContentMetaDatabaseInterface::ListContentInfo(Out<u32> out_count, OutBuffer<ContentInfo> out_info, ContentMetaKey key, u32 offset) {
|
||||
R_DEBUG_START
|
||||
if (offset >> 0x1f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
}
|
||||
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
const void* value = nullptr;
|
||||
const void *value = nullptr;
|
||||
size_t value_size = 0;
|
||||
R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs));
|
||||
const auto header = GetValueHeader(value);
|
||||
const auto content_infos = GetValueContentInfos(value);
|
||||
size_t entries_written = 0;
|
||||
|
||||
if (out_info.num_elements == 0) {
|
||||
out_entries_written.SetValue(0);
|
||||
return ResultSuccess;
|
||||
|
||||
size_t count;
|
||||
for (count = 0; offset + count < header->content_count && count < out_info.num_elements; count++) {
|
||||
out_info[count] = content_infos[offset + count];
|
||||
}
|
||||
|
||||
for (size_t i = start_index; i < out_info.num_elements; i++) {
|
||||
/* We have no more entries we can read out. */
|
||||
if (header->content_count <= start_index + i) {
|
||||
break;
|
||||
}
|
||||
|
||||
out_info[i] = content_infos[i];
|
||||
entries_written = i + 1;
|
||||
}
|
||||
|
||||
out_entries_written.SetValue(entries_written);
|
||||
out_count.SetValue(count);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::List(Out<u32> out_entries_total, Out<u32> out_entries_written, OutBuffer<ContentMetaKey> out_info, ContentMetaType type, TitleId application_title_id, TitleId title_id_min, TitleId title_id_max, ContentInstallType install_type) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
size_t entries_total = 0;
|
||||
size_t entries_written = 0;
|
||||
|
@ -311,23 +297,22 @@ namespace sts::ncm {
|
|||
out_entries_total.SetValue(entries_total);
|
||||
out_entries_written.SetValue(entries_written);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetLatestContentMetaKey(Out<ContentMetaKey> out_key, TitleId title_id) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetLatestContentMetaKey(Out<ContentMetaKey> out_key, TitleId title_id) {
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
ContentMetaKey key;
|
||||
R_TRY(this->GetLatestContentMetaKeyImpl(&key, title_id));
|
||||
out_key.SetValue(key);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::ListApplication(Out<u32> out_entries_total, Out<u32> out_entries_written, OutBuffer<ApplicationContentMetaKey> out_keys, ContentMetaType type) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
size_t entries_total = 0;
|
||||
size_t entries_written = 0;
|
||||
|
@ -377,12 +362,12 @@ namespace sts::ncm {
|
|||
out_entries_total.SetValue(entries_total);
|
||||
out_entries_written.SetValue(entries_written);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::Has(Out<bool> out, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (this->kvs->GetCount() == 0) {
|
||||
out.SetValue(false);
|
||||
|
@ -397,36 +382,26 @@ namespace sts::ncm {
|
|||
|
||||
out.SetValue(has);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::HasAll(Out<bool> out, InBuffer<ContentMetaKey> keys) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (keys.num_elements == 0) {
|
||||
out.SetValue(true);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < keys.num_elements; i++) {
|
||||
bool has = false;
|
||||
bool has = true;
|
||||
for (size_t i = 0; i < keys.num_elements && has; i++) {
|
||||
R_TRY(this->Has(&has, keys[i]));
|
||||
|
||||
if (!has) {
|
||||
out.SetValue(false);
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
out.SetValue(true);
|
||||
out.SetValue(has);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetSize(Out<u64> out_size, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (this->kvs->GetCount() == 0) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
|
@ -439,12 +414,12 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(it->GetValueSize());
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetRequiredSystemVersion(Out<u32> out_version, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (key.type != ContentMetaType::Application && key.type != ContentMetaType::Patch) {
|
||||
return ResultNcmInvalidContentMetaKey;
|
||||
|
@ -459,34 +434,41 @@ namespace sts::ncm {
|
|||
const auto ext_header = GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value);
|
||||
out_version.SetValue(ext_header->required_system_version);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetPatchId(Out<TitleId> out_patch_id, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (key.type != ContentMetaType::Application) {
|
||||
return ResultNcmInvalidContentMetaKey;
|
||||
}
|
||||
|
||||
D_LOG(" key title_id: 0x%lx\n", key.id);
|
||||
D_LOG(" key version: 0x%x\n", key.version);
|
||||
|
||||
const void* value = nullptr;
|
||||
size_t value_size = 0;
|
||||
R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs));
|
||||
const auto ext_header = GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value);
|
||||
|
||||
out_patch_id.SetValue(ext_header->patch_id);
|
||||
D_LOG(" patch title_id: 0x%lx\n", *out_patch_id);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::DisableForcibly() {
|
||||
R_DEBUG_START
|
||||
this->disabled = true;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::LookupOrphanContent(OutBuffer<bool> out_orphaned, InBuffer<ContentId> content_ids) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (out_orphaned.num_elements < content_ids.num_elements) {
|
||||
return ResultNcmBufferInsufficient;
|
||||
|
@ -531,19 +513,20 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::Commit() {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
R_TRY(this->kvs->Save());
|
||||
R_TRY(fsdevCommitDevice(this->mount_name));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::HasContent(Out<bool> out, ContentMetaKey key, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
const void* value = nullptr;
|
||||
size_t value_size = 0;
|
||||
R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs));
|
||||
|
@ -563,16 +546,16 @@ namespace sts::ncm {
|
|||
|
||||
out.SetValue(false);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::ListContentMetaInfo(Out<u32> out_entries_written, OutBuffer<ContentMetaInfo> out_meta_info, ContentMetaKey key, u32 start_index) {
|
||||
R_DEBUG_START
|
||||
if (start_index >> 0x1f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
}
|
||||
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
const void* value = nullptr;
|
||||
size_t value_size = 0;
|
||||
|
@ -598,12 +581,12 @@ namespace sts::ncm {
|
|||
|
||||
out_entries_written.SetValue(entries_written);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetAttributes(Out<ContentMetaAttribute> out_attributes, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
const void* value = nullptr;
|
||||
size_t value_size = 0;
|
||||
|
@ -611,12 +594,12 @@ namespace sts::ncm {
|
|||
const auto header = GetValueHeader(value);
|
||||
out_attributes.SetValue(header->attributes);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetRequiredApplicationVersion(Out<u32> out_version, ContentMetaKey key) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
if (key.type != ContentMetaType::AddOnContent) {
|
||||
return ResultNcmInvalidContentMetaKey;
|
||||
|
@ -628,13 +611,16 @@ namespace sts::ncm {
|
|||
const auto ext_header = GetValueExtendedHeader<AddOnContentMetaExtendedHeader>(value);
|
||||
out_version.SetValue(ext_header->required_application_version);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetContentIdByTypeAndIdOffset(Out<ContentId> out_content_id, ContentMetaKey key, ContentType type, u8 id_offset) {
|
||||
R_DEBUG_START
|
||||
ContentId content_id;
|
||||
R_TRY(this->GetContentIdByTypeImpl(&content_id, key, type, std::optional(id_offset)));
|
||||
out_content_id.SetValue(content_id);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseInterface::GetLatestProgram(ContentId* out_content_id, TitleId title_id) {
|
||||
|
@ -653,33 +639,28 @@ namespace sts::ncm {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseInterface::GetLatestContentMetaKey(Out<ContentMetaKey> out_key, TitleId tid) {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
Result OnMemoryContentMetaDatabaseInterface::GetLatestContentMetaKey(Out<ContentMetaKey> out_key, TitleId title_id) {
|
||||
R_DEBUG_START
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
const ContentMetaKey key = ContentMetaKey::Make(title_id, 0, ContentMetaType::Unknown);
|
||||
|
||||
ContentMetaKey key = {0};
|
||||
key.id = tid;
|
||||
|
||||
if (this->kvs->GetCount() == 0) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
}
|
||||
|
||||
auto entry = this->kvs->lower_bound(key);
|
||||
if (entry == this->kvs->end() || entry->GetKey().id != key.id) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
}
|
||||
|
||||
for (; entry != this->kvs->end(); entry++) {
|
||||
if (entry->GetKey().id != key.id) {
|
||||
std::optional<ContentMetaKey> found_key;
|
||||
for (auto entry = this->kvs->lower_bound(key); entry != this->kvs->end(); entry++) {
|
||||
if (entry->GetKey().id != title_id) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = entry->GetKey();
|
||||
found_key = entry->GetKey();
|
||||
}
|
||||
|
||||
*out_key = key;
|
||||
if (!found_key) {
|
||||
return ResultNcmContentMetaNotFound;
|
||||
}
|
||||
|
||||
*out_key = *found_key;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseInterface::LookupOrphanContent(OutBuffer<bool> out_orphaned, InBuffer<ContentId> content_ids) {
|
||||
|
@ -687,9 +668,7 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseInterface::Commit() {
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentMetaDatabase;
|
||||
}
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace sts::ncm {
|
|||
private:
|
||||
Result GetContentIdByTypeImpl(ContentId* out, const ContentMetaKey& key, ContentType type, std::optional<u8> id_offset);
|
||||
Result GetLatestContentMetaKeyImpl(ContentMetaKey* out_key, TitleId tid);
|
||||
protected:
|
||||
Result EnsureEnabled();
|
||||
public:
|
||||
virtual Result Set(ContentMetaKey key, InBuffer<u8> value) override;
|
||||
virtual Result Get(Out<u64> out_size, ContentMetaKey key, OutBuffer<u8> out_value) override;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "ncm_make_path.hpp"
|
||||
#include "ncm_utils.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::ncm {
|
||||
|
||||
ContentStorageInterface::~ContentStorageInterface() {
|
||||
|
@ -95,15 +97,18 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
Result ContentStorageInterface::GeneratePlaceHolderId(Out<PlaceHolderId> out) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
||||
sts::rnd::GenerateRandomBytes(out.GetPointer(), sizeof(NcmNcaId));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -115,17 +120,21 @@ namespace sts::ncm {
|
|||
R_TRY(this->placeholder_accessor.Create(placeholder_id, size));
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
||||
return this->placeholder_accessor.Delete(placeholder_id);
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::HasPlaceHolder(Out<bool> out, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -138,9 +147,11 @@ namespace sts::ncm {
|
|||
out.SetValue(has);
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, InBuffer<u8> data) {
|
||||
R_DEBUG_START
|
||||
/* Offset is too large */
|
||||
if (offset >> 0x3f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
|
@ -173,9 +184,11 @@ namespace sts::ncm {
|
|||
this->placeholder_accessor.StoreToCache(f, placeholder_id);
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
this->ClearContentCache();
|
||||
|
||||
if (this->disabled) {
|
||||
|
@ -200,9 +213,11 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::Delete(ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -220,9 +235,11 @@ namespace sts::ncm {
|
|||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::Has(Out<bool> out, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -235,9 +252,11 @@ namespace sts::ncm {
|
|||
out.SetValue(has);
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetPath(OutPointerWithServerSize<lr::Path, 0x1> out, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -248,9 +267,11 @@ namespace sts::ncm {
|
|||
R_TRY(ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
|
||||
*out.pointer = common_path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetPlaceHolderPath(OutPointerWithServerSize<lr::Path, 0x1> out, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -261,9 +282,11 @@ namespace sts::ncm {
|
|||
R_TRY(ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path));
|
||||
*out.pointer = common_path;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::CleanupAllPlaceHolder() {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -281,9 +304,11 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::ListPlaceHolder(Out<u32> out_count, OutBuffer<PlaceHolderId> out_buf) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -312,9 +337,11 @@ namespace sts::ncm {
|
|||
|
||||
out_count.SetValue(static_cast<u32>(entry_count));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetContentCount(Out<u32> out_count) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -337,9 +364,11 @@ namespace sts::ncm {
|
|||
|
||||
out_count.SetValue(content_count);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::ListContentId(Out<u32> out_count, OutBuffer<ContentId> out_buf, u32 start_offset) {
|
||||
R_DEBUG_START
|
||||
if (start_offset >> 0x1f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
}
|
||||
|
@ -386,9 +415,11 @@ namespace sts::ncm {
|
|||
|
||||
out_count.SetValue(static_cast<u32>(entry_count));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetSizeFromContentId(Out<u64> out_size, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -403,16 +434,20 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(st.st_size);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::DisableForcibly() {
|
||||
R_DEBUG_START
|
||||
this->disabled = true;
|
||||
this->ClearContentCache();
|
||||
this->placeholder_accessor.ClearAllCaches();
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -441,18 +476,22 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
||||
R_TRY(this->placeholder_accessor.SetSize(placeholder_id, size));
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::ReadContentIdFile(OutBuffer<u8> buf, ContentId content_id, u64 offset) {
|
||||
R_DEBUG_START
|
||||
/* Offset is too large */
|
||||
if (offset >> 0x3f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
|
@ -475,9 +514,11 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetRightsIdFromPlaceHolderId(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -495,9 +536,11 @@ namespace sts::ncm {
|
|||
out_key_generation.SetValue(static_cast<u64>(key_generation));
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetRightsIdFromContentId(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -556,9 +599,11 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, InBuffer<u8> data) {
|
||||
R_DEBUG_START
|
||||
/* Offset is too large */
|
||||
if (offset >> 0x3f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
|
@ -599,9 +644,11 @@ namespace sts::ncm {
|
|||
fflush(f);
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetFreeSpaceSize(Out<u64> out_size) {
|
||||
R_DEBUG_START
|
||||
struct statvfs st = {0};
|
||||
if (statvfs(this->root_path, &st) == -1) {
|
||||
return fsdevGetLastResult();
|
||||
|
@ -609,9 +656,11 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(st.f_bfree);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetTotalSpaceSize(Out<u64> out_size) {
|
||||
R_DEBUG_START
|
||||
struct statvfs st = {0};
|
||||
if (statvfs(this->root_path, &st) == -1) {
|
||||
return fsdevGetLastResult();
|
||||
|
@ -619,14 +668,18 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(st.f_blocks);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::FlushPlaceHolder() {
|
||||
R_DEBUG_START
|
||||
this->placeholder_accessor.ClearAllCaches();
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetSizeFromPlaceHolderId(Out<u64> out_size, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -651,9 +704,11 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(st.st_size);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::RepairInvalidFileAttribute() {
|
||||
R_DEBUG_START
|
||||
char content_root_path[FS_MAX_PATH] = {0};
|
||||
this->GetContentRootPath(content_root_path);
|
||||
unsigned int dir_depth = this->GetContentDirectoryDepth();
|
||||
|
@ -682,9 +737,11 @@ namespace sts::ncm {
|
|||
R_TRY(TraverseDirectory(placeholder_root_path, dir_depth, fix_file_attributes));
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -743,6 +800,7 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -180,7 +180,15 @@ namespace sts::ncm {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
std::map<std::string, FsContentStorageId> g_mount_content_storage;
|
||||
constexpr const char* SystemContentMountName = "@SystemContent";
|
||||
constexpr const char* UserContentMountName = "@UserContent";
|
||||
constexpr const char* SdCardContentMountName = "@SdCardContent";
|
||||
constexpr const char* GameCardMountNameBase = "@Gc";
|
||||
|
||||
constexpr const char* GameCardPartitionLetters[3] = { "U", "N", "S" };
|
||||
|
||||
/* Maps mount names to their common mount names. */
|
||||
std::map<std::string, std::string> g_mount_content_storage;
|
||||
|
||||
Result MountContentStorage(const char* mount_point, FsContentStorageId id) {
|
||||
if (!mount_point) {
|
||||
|
@ -194,11 +202,30 @@ namespace sts::ncm {
|
|||
std::abort();
|
||||
}
|
||||
|
||||
g_mount_content_storage[mount_point] = id;
|
||||
switch (id) {
|
||||
case FS_CONTENTSTORAGEID_NandSystem:
|
||||
g_mount_content_storage[mount_point] = SystemContentMountName;
|
||||
break;
|
||||
|
||||
case FS_CONTENTSTORAGEID_NandUser:
|
||||
g_mount_content_storage[mount_point] = UserContentMountName;
|
||||
break;
|
||||
|
||||
case FS_CONTENTSTORAGEID_SdCard:
|
||||
g_mount_content_storage[mount_point] = SdCardContentMountName;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
};
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result MountGameCardPartition(const char* mount_point, const FsGameCardHandle handle, FsGameCardPartiton partition) {
|
||||
if (partition > 2) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
FsFileSystem fs;
|
||||
R_TRY(fsOpenGameCardFileSystem(&fs, &handle, partition));
|
||||
|
||||
|
@ -206,6 +233,9 @@ namespace sts::ncm {
|
|||
std::abort();
|
||||
}
|
||||
|
||||
MountName mount = {0};
|
||||
snprintf(mount.name, sizeof(MountName), "%s%s%08x", GameCardMountNameBase, GameCardPartitionLetters[partition], handle.value);
|
||||
g_mount_content_storage[mount_point] = mount.name;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
@ -224,10 +254,6 @@ namespace sts::ncm {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
constexpr const char* SystemContentMountName = "@SystemContent";
|
||||
constexpr const char* UserContentMountName = "@UserContent";
|
||||
constexpr const char* SdCardContentMountName = "@SdCardContent";
|
||||
|
||||
Result ConvertToFsCommonPath(char* out_common_path, size_t out_len, const char* path) {
|
||||
if (!out_common_path || !path) {
|
||||
return ResultFsNullptrArgument;
|
||||
|
@ -247,32 +273,14 @@ namespace sts::ncm {
|
|||
return ResultFsMountNameNotFound;
|
||||
}
|
||||
|
||||
FsContentStorageId content_storage_id = g_mount_content_storage[mount_name.name];
|
||||
char translated_path[FS_MAX_PATH] = {0};
|
||||
const char* common_mount_name;
|
||||
|
||||
switch (content_storage_id) {
|
||||
case FS_CONTENTSTORAGEID_NandSystem:
|
||||
common_mount_name = SystemContentMountName;
|
||||
break;
|
||||
|
||||
case FS_CONTENTSTORAGEID_NandUser:
|
||||
common_mount_name = UserContentMountName;
|
||||
break;
|
||||
|
||||
case FS_CONTENTSTORAGEID_SdCard:
|
||||
common_mount_name = SdCardContentMountName;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
};
|
||||
std::string common_mount_name = g_mount_content_storage[mount_name.name];
|
||||
|
||||
if (fsdevTranslatePath(path, NULL, translated_path) == -1) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
snprintf(out_common_path, out_len, "%s:%s", common_mount_name, translated_path);
|
||||
snprintf(out_common_path, out_len, "%s:%s", common_mount_name.c_str(), translated_path);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ extern "C" {
|
|||
|
||||
u32 __nx_applet_type = AppletType_None;
|
||||
|
||||
#define INNER_HEAP_SIZE 0x60000
|
||||
#define INNER_HEAP_SIZE 0x100000
|
||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||
|
@ -45,10 +44,52 @@ extern "C" {
|
|||
|
||||
sts::ncm::TitleId __stratosphere_title_id = sts::ncm::TitleId::Ncm;
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr uintptr_t IramBase = 0x40000000ull;
|
||||
constexpr uintptr_t IramPayloadBase = 0x40010000ull;
|
||||
constexpr size_t IramSize = 0x40000;
|
||||
constexpr size_t IramPayloadMaxSize = 0x2E000;
|
||||
|
||||
/* Globals. */
|
||||
u8 __attribute__ ((aligned (0x1000))) g_work_page[0x1000];
|
||||
|
||||
/* Helpers. */
|
||||
void ClearIram() {
|
||||
/* Make page FFs. */
|
||||
memset(g_work_page, 0xFF, sizeof(g_work_page));
|
||||
|
||||
/* Overwrite all of IRAM with FFs. */
|
||||
for (size_t ofs = 0; ofs < IramSize; ofs += sizeof(g_work_page)) {
|
||||
CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
}
|
||||
|
||||
void DoReboot(AtmosphereFatalErrorContext *ctx) {
|
||||
/* Ensure clean IRAM state. */
|
||||
ClearIram();
|
||||
|
||||
/* Copy in fatal error context, if relevant. */
|
||||
if (ctx != nullptr) {
|
||||
std::memset(g_work_page, 0xCC, sizeof(g_work_page));
|
||||
std::memcpy(g_work_page, ctx, sizeof(*ctx));
|
||||
CopyToIram(IramPayloadBase + IramPayloadMaxSize, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
|
||||
RebootToRcm();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
||||
StratosphereCrashHandler(ctx);
|
||||
}
|
||||
|
||||
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
|
||||
DoReboot(ctx);
|
||||
}
|
||||
|
||||
void __libnx_initheap(void) {
|
||||
void* addr = nx_inner_heap;
|
||||
size_t size = nx_inner_heap_size;
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
#include "ncm_path_utils.hpp"
|
||||
#include "ncm_readonlycontentstorage.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace sts::ncm {
|
||||
|
||||
Result ReadOnlyContentStorageInterface::Initialize(const char* root_path, MakeContentPathFunc content_path_func) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -34,37 +37,53 @@ namespace sts::ncm {
|
|||
strncpy(this->root_path, root_path, FS_MAX_PATH-2);
|
||||
this->make_content_path_func = *content_path_func;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GeneratePlaceHolderId(Out<PlaceHolderId> out) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::HasPlaceHolder(Out<bool> out, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, InBuffer<u8> data) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::Delete(ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::Has(Out<bool> out, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -82,9 +101,11 @@ namespace sts::ncm {
|
|||
|
||||
out.SetValue(has);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetPath(OutPointerWithServerSize<lr::Path, 0x1> out, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -104,29 +125,41 @@ namespace sts::ncm {
|
|||
*out.pointer = common_path;
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetPlaceHolderPath(OutPointerWithServerSize<lr::Path, 0x1> out, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::CleanupAllPlaceHolder() {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::ListPlaceHolder(Out<u32> out_count, OutBuffer<PlaceHolderId> out_buf) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetContentCount(Out<u32> out_count) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::ListContentId(Out<u32> out_count, OutBuffer<ContentId> out_buf, u32 start_offset) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetSizeFromContentId(Out<u64> out_size, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -148,22 +181,30 @@ namespace sts::ncm {
|
|||
|
||||
out_size.SetValue(st.st_size);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::DisableForcibly() {
|
||||
R_DEBUG_START
|
||||
this->disabled = true;
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::ReadContentIdFile(OutBuffer<u8> buf, ContentId content_id, u64 offset) {
|
||||
R_DEBUG_START
|
||||
/* Offset is too large */
|
||||
if (offset >> 0x3f != 0) {
|
||||
return ResultNcmInvalidOffset;
|
||||
|
@ -201,13 +242,17 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderId(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetRightsIdFromContentId(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, ContentId content_id) {
|
||||
R_DEBUG_START
|
||||
if (this->disabled) {
|
||||
return ResultNcmInvalidContentStorage;
|
||||
}
|
||||
|
@ -233,36 +278,51 @@ namespace sts::ncm {
|
|||
out_key_generation.SetValue(static_cast<u64>(key_generation));
|
||||
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, InBuffer<u8> data) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetFreeSpaceSize(Out<u64> out_size) {
|
||||
R_DEBUG_START
|
||||
out_size.SetValue(0);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetTotalSpaceSize(Out<u64> out_size) {
|
||||
R_DEBUG_START
|
||||
out_size.SetValue(0);
|
||||
return ResultSuccess;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::FlushPlaceHolder() {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetSizeFromPlaceHolderId(Out<u64> out, PlaceHolderId placeholder_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::RepairInvalidFileAttribute() {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(Out<FsRightsId> out_rights_id, Out<u64> out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) {
|
||||
R_DEBUG_START
|
||||
return ResultNcmInvalidContentStorageOperation;
|
||||
R_DEBUG_END
|
||||
}
|
||||
|
||||
}
|
|
@ -44,6 +44,7 @@ namespace sts::ncm {
|
|||
typedef Uuid PlaceHolderId;
|
||||
|
||||
enum class ContentMetaType : u8 {
|
||||
Unknown = 0x0,
|
||||
SystemProgram = 0x1,
|
||||
SystemData = 0x2,
|
||||
SystemUpdate = 0x3,
|
||||
|
@ -107,29 +108,24 @@ namespace sts::ncm {
|
|||
}
|
||||
|
||||
bool operator==(const ContentMetaKey& other) const {
|
||||
if (this->id != other.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->version != other.version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->type != other.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->install_type != other.install_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return this->id == other.id &&
|
||||
this->version == other.version &&
|
||||
this->type == other.type &&
|
||||
this->install_type == other.install_type;
|
||||
}
|
||||
|
||||
bool operator!=(const ContentMetaKey& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
} PACKED;
|
||||
|
||||
static constexpr ContentMetaKey Make(TitleId title_id, u32 version, ContentMetaType type) {
|
||||
return { .id = title_id, .version = version, .type = type };
|
||||
}
|
||||
|
||||
static constexpr ContentMetaKey Make(TitleId title_id, u32 version, ContentMetaType type, ContentInstallType install_type) {
|
||||
return { .id = title_id, .version = version, .type = type, .install_type = install_type };
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(ContentMetaKey) == 0x10, "ContentMetaKey definition!");
|
||||
|
||||
|
@ -139,14 +135,16 @@ namespace sts::ncm {
|
|||
struct ApplicationContentMetaKey {
|
||||
ContentMetaKey key;
|
||||
TitleId application_title_id;
|
||||
} PACKED;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ApplicationContentMetaKey) == 0x18, "ApplicationContentMetaKey definition!");
|
||||
|
||||
struct ContentInfo {
|
||||
ContentId content_id;
|
||||
u8 size[6];
|
||||
ContentType content_type;
|
||||
u8 id_offset;
|
||||
} PACKED;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ContentInfo) == 0x18, "ContentInfo definition!");
|
||||
|
||||
|
|
Loading…
Reference in a new issue