mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-12 19:12:27 +00:00
loader: add SetExternalContentSource extension
This commit is contained in:
parent
18f51e9b2e
commit
5c147e5188
9 changed files with 132 additions and 4 deletions
|
@ -19,11 +19,12 @@
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "ldr_registration.hpp"
|
#include "ldr_registration.hpp"
|
||||||
#include "ldr_content_management.hpp"
|
#include "ldr_content_management.hpp"
|
||||||
#include "ldr_hid.hpp"
|
#include "ldr_hid.hpp"
|
||||||
|
#include "ldr_npdm.hpp"
|
||||||
|
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
|
|
||||||
|
@ -43,6 +44,9 @@ static u64 g_override_hbl_tid = 0x010000000000100D;
|
||||||
/* Static buffer for loader.ini contents at runtime. */
|
/* Static buffer for loader.ini contents at runtime. */
|
||||||
static char g_config_ini_data[0x800];
|
static char g_config_ini_data[0x800];
|
||||||
|
|
||||||
|
/* SetExternalContentSource extension */
|
||||||
|
static std::map<u64, ContentManagement::ExternalContentSource> g_external_content_sources;
|
||||||
|
|
||||||
Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
|
Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
|
||||||
char path[FS_MAX_PATH] = {0};
|
char path[FS_MAX_PATH] = {0};
|
||||||
Result rc;
|
Result rc;
|
||||||
|
@ -312,3 +316,54 @@ bool ContentManagement::ShouldOverrideContents(u64 tid) {
|
||||||
return g_has_initialized_fs_dev;
|
return g_has_initialized_fs_dev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SetExternalContentSource extension */
|
||||||
|
ContentManagement::ExternalContentSource *ContentManagement::GetExternalContentSource(u64 tid) {
|
||||||
|
auto i = g_external_content_sources.find(tid);
|
||||||
|
if (i == g_external_content_sources.end()) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return &i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContentManagement::SetExternalContentSource(u64 tid, FsFileSystem filesystem) {
|
||||||
|
if (g_external_content_sources.size() >= 16) {
|
||||||
|
return 0x409; /* LAUNCH_QUEUE_FULL */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove any existing ECS for this title. */
|
||||||
|
ClearExternalContentSource(tid);
|
||||||
|
|
||||||
|
char mountpoint[32];
|
||||||
|
ExternalContentSource::GenerateMountpointName(tid, mountpoint, sizeof(mountpoint));
|
||||||
|
if (fsdevMountDevice(mountpoint, filesystem) == -1) {
|
||||||
|
return 0x7802; /* specified mount name already exists */
|
||||||
|
}
|
||||||
|
g_external_content_sources.emplace(
|
||||||
|
std::piecewise_construct,
|
||||||
|
std::make_tuple(tid),
|
||||||
|
std::make_tuple(tid, mountpoint));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentManagement::ClearExternalContentSource(u64 tid) {
|
||||||
|
auto i = g_external_content_sources.find(tid);
|
||||||
|
if (i != g_external_content_sources.end()) {
|
||||||
|
g_external_content_sources.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentManagement::ExternalContentSource::GenerateMountpointName(u64 tid, char *out, size_t max_length) {
|
||||||
|
snprintf(out, max_length, "ecs-%016lx", tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentManagement::ExternalContentSource::ExternalContentSource(u64 tid, const char *mountpoint) : tid(tid) {
|
||||||
|
strncpy(this->mountpoint, mountpoint, sizeof(this->mountpoint));
|
||||||
|
NpdmUtils::InvalidateCache(tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentManagement::ExternalContentSource::~ExternalContentSource() {
|
||||||
|
fsdevUnmountDevice(mountpoint);
|
||||||
|
}
|
||||||
|
|
|
@ -39,4 +39,24 @@ class ContentManagement {
|
||||||
|
|
||||||
static bool ShouldReplaceWithHBL(u64 tid);
|
static bool ShouldReplaceWithHBL(u64 tid);
|
||||||
static bool ShouldOverrideContents(u64 tid);
|
static bool ShouldOverrideContents(u64 tid);
|
||||||
|
|
||||||
|
/* SetExternalContentSource extension */
|
||||||
|
class ExternalContentSource {
|
||||||
|
public:
|
||||||
|
static void GenerateMountpointName(u64 tid, char *out, size_t max_length);
|
||||||
|
|
||||||
|
ExternalContentSource(u64 tid, const char *mountpoint);
|
||||||
|
~ExternalContentSource();
|
||||||
|
|
||||||
|
ExternalContentSource(const ExternalContentSource &other) = delete;
|
||||||
|
ExternalContentSource(ExternalContentSource &&other) = delete;
|
||||||
|
ExternalContentSource &operator=(const ExternalContentSource &other) = delete;
|
||||||
|
ExternalContentSource &operator=(ExternalContentSource &&other) = delete;
|
||||||
|
|
||||||
|
const u64 tid;
|
||||||
|
char mountpoint[32];
|
||||||
|
};
|
||||||
|
static ExternalContentSource *GetExternalContentSource(u64 tid); /* returns nullptr if no ECS is set */
|
||||||
|
static Result SetExternalContentSource(u64 tid, FsFileSystem filesystem); /* takes ownership of filesystem */
|
||||||
|
static void ClearExternalContentSource(u64 tid);
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,6 +33,12 @@ Result NpdmUtils::LoadNpdmFromCache(u64 tid, NpdmInfo *out) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *NpdmUtils::OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs) {
|
||||||
|
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
|
||||||
|
snprintf(g_npdm_path, FS_MAX_PATH, "%s:/main.npdm", ecs->mountpoint);
|
||||||
|
return fopen(g_npdm_path, "rb");
|
||||||
|
}
|
||||||
|
|
||||||
FILE *NpdmUtils::OpenNpdmFromHBL() {
|
FILE *NpdmUtils::OpenNpdmFromHBL() {
|
||||||
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
|
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
|
||||||
snprintf(g_npdm_path, FS_MAX_PATH, "hbl:/main.npdm");
|
snprintf(g_npdm_path, FS_MAX_PATH, "hbl:/main.npdm");
|
||||||
|
@ -53,6 +59,11 @@ FILE *NpdmUtils::OpenNpdmFromSdCard(u64 title_id) {
|
||||||
|
|
||||||
|
|
||||||
FILE *NpdmUtils::OpenNpdm(u64 title_id) {
|
FILE *NpdmUtils::OpenNpdm(u64 title_id) {
|
||||||
|
ContentManagement::ExternalContentSource *ecs = nullptr;
|
||||||
|
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
|
||||||
|
return OpenNpdmFromECS(ecs);
|
||||||
|
}
|
||||||
|
|
||||||
if (ContentManagement::ShouldOverrideContents(title_id)) {
|
if (ContentManagement::ShouldOverrideContents(title_id)) {
|
||||||
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
|
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
|
||||||
return OpenNpdmFromHBL();
|
return OpenNpdmFromHBL();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "ldr_registration.hpp"
|
#include "ldr_registration.hpp"
|
||||||
|
#include "ldr_content_management.hpp" /* for ExternalContentSource */
|
||||||
|
|
||||||
#define MAGIC_META 0x4154454D
|
#define MAGIC_META 0x4154454D
|
||||||
#define MAGIC_ACI0 0x30494341
|
#define MAGIC_ACI0 0x30494341
|
||||||
|
@ -101,7 +102,7 @@ class NpdmUtils {
|
||||||
static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining);
|
static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining);
|
||||||
static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps);
|
static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps);
|
||||||
|
|
||||||
|
static FILE *OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs);
|
||||||
static FILE *OpenNpdmFromHBL();
|
static FILE *OpenNpdmFromHBL();
|
||||||
static FILE *OpenNpdmFromExeFS();
|
static FILE *OpenNpdmFromExeFS();
|
||||||
static FILE *OpenNpdmFromSdCard(u64 tid);
|
static FILE *OpenNpdmFromSdCard(u64 tid);
|
||||||
|
|
|
@ -31,6 +31,12 @@ static bool g_nso_present[NSO_NUM_MAX] = {0};
|
||||||
|
|
||||||
static char g_nso_path[FS_MAX_PATH] = {0};
|
static char g_nso_path[FS_MAX_PATH] = {0};
|
||||||
|
|
||||||
|
FILE *NsoUtils::OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs) {
|
||||||
|
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
|
||||||
|
snprintf(g_nso_path, FS_MAX_PATH, "%s:/%s", ecs->mountpoint, NsoUtils::GetNsoFileName(index));
|
||||||
|
return fopen(g_nso_path, "rb");
|
||||||
|
}
|
||||||
|
|
||||||
FILE *NsoUtils::OpenNsoFromHBL(unsigned int index) {
|
FILE *NsoUtils::OpenNsoFromHBL(unsigned int index) {
|
||||||
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
|
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
|
||||||
snprintf(g_nso_path, FS_MAX_PATH, "hbl:/%s", NsoUtils::GetNsoFileName(index));
|
snprintf(g_nso_path, FS_MAX_PATH, "hbl:/%s", NsoUtils::GetNsoFileName(index));
|
||||||
|
@ -61,6 +67,11 @@ bool NsoUtils::CheckNsoStubbed(unsigned int index, u64 title_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) {
|
FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) {
|
||||||
|
ContentManagement::ExternalContentSource *ecs = nullptr;
|
||||||
|
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
|
||||||
|
return OpenNsoFromECS(index, ecs);
|
||||||
|
}
|
||||||
|
|
||||||
if (ContentManagement::ShouldOverrideContents(title_id)) {
|
if (ContentManagement::ShouldOverrideContents(title_id)) {
|
||||||
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
|
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
|
||||||
return OpenNsoFromHBL(index);
|
return OpenNsoFromHBL(index);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "ldr_content_management.hpp" /* for ExternalContentSource */
|
||||||
|
|
||||||
#define MAGIC_NSO0 0x304F534E
|
#define MAGIC_NSO0 0x304F534E
|
||||||
#define NSO_NUM_MAX 13
|
#define NSO_NUM_MAX 13
|
||||||
|
|
||||||
|
@ -96,7 +98,8 @@ class NsoUtils {
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FILE *OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs);
|
||||||
static FILE *OpenNsoFromHBL(unsigned int index);
|
static FILE *OpenNsoFromHBL(unsigned int index);
|
||||||
static FILE *OpenNsoFromExeFS(unsigned int index);
|
static FILE *OpenNsoFromExeFS(unsigned int index);
|
||||||
static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id);
|
static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id);
|
||||||
|
|
|
@ -215,6 +215,8 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
CREATE_PROCESS_END:
|
CREATE_PROCESS_END:
|
||||||
|
/* ECS is a one-shot operation. */
|
||||||
|
ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id);
|
||||||
if (mounted_code) {
|
if (mounted_code) {
|
||||||
if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) {
|
if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) {
|
||||||
rc = ContentManagement::UnmountCode();
|
rc = ContentManagement::UnmountCode();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "ldr_shell.hpp"
|
#include "ldr_shell.hpp"
|
||||||
#include "ldr_launch_queue.hpp"
|
#include "ldr_launch_queue.hpp"
|
||||||
|
#include "ldr_content_management.hpp"
|
||||||
|
|
||||||
Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||||
|
|
||||||
|
@ -30,6 +31,9 @@ Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id
|
||||||
case Shell_Cmd_ClearLaunchQueue:
|
case Shell_Cmd_ClearLaunchQueue:
|
||||||
rc = WrapIpcCommandImpl<&ShellService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
rc = WrapIpcCommandImpl<&ShellService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||||
break;
|
break;
|
||||||
|
case Shell_Cmd_AtmosphereSetExternalContentSource:
|
||||||
|
rc = WrapIpcCommandImpl<&ShellService::set_external_content_source>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -46,3 +50,19 @@ std::tuple<Result> ShellService::clear_launch_queue(u64 dat) {
|
||||||
LaunchQueue::clear();
|
LaunchQueue::clear();
|
||||||
return {0};
|
return {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SetExternalContentSource extension */
|
||||||
|
std::tuple<Result, MovedHandle> ShellService::set_external_content_source(u64 tid) {
|
||||||
|
Handle server_h;
|
||||||
|
Handle client_h;
|
||||||
|
|
||||||
|
Result rc;
|
||||||
|
if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) {
|
||||||
|
return {rc, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
Service service;
|
||||||
|
serviceCreate(&service, client_h);
|
||||||
|
ContentManagement::SetExternalContentSource(tid, FsFileSystem {service});
|
||||||
|
return {0, server_h};
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
enum ShellServiceCmd {
|
enum ShellServiceCmd {
|
||||||
Shell_Cmd_AddTitleToLaunchQueue = 0,
|
Shell_Cmd_AddTitleToLaunchQueue = 0,
|
||||||
Shell_Cmd_ClearLaunchQueue = 1
|
Shell_Cmd_ClearLaunchQueue = 1,
|
||||||
|
|
||||||
|
Shell_Cmd_AtmosphereSetExternalContentSource = 65000,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShellService final : public IServiceObject {
|
class ShellService final : public IServiceObject {
|
||||||
|
@ -39,4 +41,7 @@ class ShellService final : public IServiceObject {
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args);
|
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args);
|
||||||
std::tuple<Result> clear_launch_queue(u64 dat);
|
std::tuple<Result> clear_launch_queue(u64 dat);
|
||||||
|
|
||||||
|
/* Atmosphere commands. */
|
||||||
|
std::tuple<Result, MovedHandle> set_external_content_source(u64 tid);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue