diff --git a/nx/include/switch.h b/nx/include/switch.h index 398eb0ff..8c96622d 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -33,6 +33,7 @@ extern "C" { #include "switch/services/sm.h" #include "switch/services/fs.h" +#include "switch/services/fsldr.h" #include "switch/services/acc.h" #include "switch/services/apm.h" #include "switch/services/applet.h" diff --git a/nx/include/switch/services/fsldr.h b/nx/include/switch/services/fsldr.h new file mode 100644 index 00000000..3703129a --- /dev/null +++ b/nx/include/switch/services/fsldr.h @@ -0,0 +1,17 @@ +/** + * @file fsldr.h + * @brief FilesystemProxy-ForLoader (fsp-ldr) service IPC wrapper. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" +#include "../services/fs.h" + +Result fsldrInitialize(void); +void fsldrExit(void); + +Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out); +Result fsldrIsArchivedProgram(u64 pid, bool *out); +Result fsldrSetCurrentProcess(); \ No newline at end of file diff --git a/nx/source/services/fsldr.c b/nx/source/services/fsldr.c new file mode 100644 index 00000000..a62b73bb --- /dev/null +++ b/nx/source/services/fsldr.c @@ -0,0 +1,147 @@ +// Copyright 2018 SciresM +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "services/fs.h" +#include "services/sm.h" +#include "services/fsldr.h" + +static Service g_fsldrSrv; +static u64 g_fsldrRefCnt; + +Result fsldrSetCurrentProcess(); + +Result fsldrInitialize(void) { + atomicIncrement64(&g_fsldrRefCnt); + + if (serviceIsActive(&g_fsldrSrv)) + return 0; + + Result rc = smGetService(&g_fsldrSrv, "fsp-ldr"); + + if (R_SUCCEEDED(rc) && kernelAbove400()) { + rc = fsldrSetCurrentProcess(); + } + + return rc; + +} + +void fsldrExit(void) { + if (atomicDecrement64(&g_fsldrRefCnt) == 0) + serviceClose(&g_fsldrSrv); +} + +Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out) { + char send_path[FS_MAX_PATH] = {0}; + IpcCommand c; + ipcInitialize(&c); + ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 tid; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->tid = tid; + + strncpy(send_path, path, FS_MAX_PATH); + Result rc = serviceIpcDispatch(&g_fsldrSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + serviceCreate(&out->s, r.Handles[0]); + } + } + + return rc; +} + +Result fsldrIsArchivedProgram(u64 pid, bool *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->pid = pid; + + Result rc = serviceIpcDispatch(&g_fsldrSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u8 is_archived; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->is_archived != 0; + } + } + + return rc; +} + +Result fsldrSetCurrentProcess() { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 unk; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->unk = 0; + + Result rc = serviceIpcDispatch(&g_fsldrSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} +