mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
1378 lines
25 KiB
C
1378 lines
25 KiB
C
// Copyright 2017 plutoo
|
|
#include <string.h>
|
|
#include "types.h"
|
|
#include "result.h"
|
|
#include "arm/atomics.h"
|
|
#include "kernel/ipc.h"
|
|
#include "services/fs.h"
|
|
#include "services/sm.h"
|
|
|
|
static Service g_fsSrv;
|
|
static u64 g_refCnt;
|
|
|
|
Result fsInitialize(void)
|
|
{
|
|
atomicIncrement64(&g_refCnt);
|
|
|
|
if (serviceIsActive(&g_fsSrv))
|
|
return 0;
|
|
|
|
Result rc = smGetService(&g_fsSrv, "fsp-srv");
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
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 = 1;
|
|
raw->unk = 0;
|
|
|
|
rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsExit(void)
|
|
{
|
|
if (atomicDecrement64(&g_refCnt) == 0)
|
|
serviceClose(&g_fsSrv);
|
|
}
|
|
|
|
Service* fsGetServiceSession(void) {
|
|
return &g_fsSrv;
|
|
}
|
|
|
|
Result fsOpenBisStorage(FsStorage* out, u32 PartitionId) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u32 PartitionId;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 12;
|
|
raw->PartitionId = PartitionId;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsOpenBisFileSystem(FsFileSystem* out, u32 PartitionId, const char* string) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
char tmpstr[FS_MAX_PATH] = {0};
|
|
strncpy(tmpstr, string, sizeof(tmpstr)-1);
|
|
ipcAddSendStatic(&c, tmpstr, sizeof(tmpstr), 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u32 PartitionId;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 11;
|
|
raw->PartitionId = PartitionId;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsMountSdcard(FsFileSystem* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 18;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 inval;//Actually u8.
|
|
FsSave save;
|
|
} PACKED *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 51;
|
|
raw->inval = (u64)inval;
|
|
memcpy(&raw->save, save, sizeof(FsSave));
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 inval;//Actually u8.
|
|
FsSave save;
|
|
} PACKED *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 52;
|
|
raw->inval = (u64)inval;
|
|
memcpy(&raw->save, save, sizeof(FsSave));
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 SaveDataSpaceId) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u8 SaveDataSpaceId;
|
|
} *raw2;
|
|
|
|
if (SaveDataSpaceId == FsSaveDataSpaceId_All) {
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 60;
|
|
}
|
|
else {
|
|
raw2 = ipcPrepareHeader(&c, sizeof(*raw2));
|
|
|
|
raw2->magic = SFCI_MAGIC;
|
|
raw2->cmd_id = 61;
|
|
raw2->SaveDataSpaceId = SaveDataSpaceId;
|
|
}
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsOpenDataStorageByCurrentProcess(FsStorage* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 200;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsOpenDeviceOperator(FsDeviceOperator* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 400;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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 fsOpenSdCardDetectionEventNotifier(FsEventNotifier* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 500;
|
|
|
|
Result rc = serviceIpcDispatch(&g_fsSrv);
|
|
|
|
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;
|
|
}
|
|
|
|
// Wrapper(s) for fsMountSaveData.
|
|
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
|
|
FsSave save;
|
|
|
|
memset(&save, 0, sizeof(save));
|
|
save.titleID = titleID;
|
|
save.userID = userID;
|
|
save.SaveDataType = FsSaveDataType_SaveData;
|
|
|
|
return fsMountSaveData(out, FsSaveDataSpaceId_NandUser, &save);
|
|
}
|
|
|
|
Result fsMount_SystemSaveData(FsFileSystem* out, u64 saveID) {
|
|
FsSave save;
|
|
|
|
memset(&save, 0, sizeof(save));
|
|
save.saveID = saveID;
|
|
save.SaveDataType = FsSaveDataType_SystemSaveData;
|
|
|
|
return fsMountSystemSaveData(out, FsSaveDataSpaceId_NandSystem, &save);
|
|
}
|
|
|
|
// IFileSystem impl
|
|
Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 zero;
|
|
u64 size;
|
|
u32 flags;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
raw->zero = 0;
|
|
raw->size = size;
|
|
raw->flags = flags;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsDeleteFile(FsFileSystem* fs, const char* path) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 1;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsCreateDirectory(FsFileSystem* fs, const char* path) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 2;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 3;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 4;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path0, FS_MAX_PATH, 0);
|
|
ipcAddSendStatic(&c, path1, FS_MAX_PATH, 1);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 5;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path1) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path0, FS_MAX_PATH, 0);
|
|
ipcAddSendStatic(&c, path1, FS_MAX_PATH, 1);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 6;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 7;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u32 type;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = resp->type;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u32 flags;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 8;
|
|
raw->flags = flags;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
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 fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u32 flags;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 9;
|
|
raw->flags = flags;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
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 fsFsCommit(FsFileSystem* fs) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 10;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 11;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 space;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = resp->space;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 12;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 space;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = resp->space;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 13;
|
|
|
|
Result rc = serviceIpcDispatch(&fs->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsFsClose(FsFileSystem* fs) {
|
|
serviceClose(&fs->s);
|
|
}
|
|
|
|
// IFile implementation
|
|
Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddRecvBuffer(&c, buf, len, 1);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 zero;
|
|
u64 offset;
|
|
u64 read_size;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
raw->zero = 0;
|
|
raw->offset = off;
|
|
raw->read_size = len;
|
|
|
|
Result rc = serviceIpcDispatch(&f->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 bytes_read;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = resp->bytes_read;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddSendBuffer(&c, buf, len, 1);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 zero;
|
|
u64 offset;
|
|
u64 write_size;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 1;
|
|
raw->zero = 0;
|
|
raw->offset = off;
|
|
raw->write_size = len;
|
|
|
|
Result rc = serviceIpcDispatch(&f->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFileFlush(FsFile* f) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 2;
|
|
|
|
Result rc = serviceIpcDispatch(&f->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFileSetSize(FsFile* f, u64 sz) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 size;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 3;
|
|
raw->size = sz;
|
|
|
|
Result rc = serviceIpcDispatch(&f->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsFileGetSize(FsFile* f, u64* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 4;
|
|
|
|
Result rc = serviceIpcDispatch(&f->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 size;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
if (R_SUCCEEDED(rc) && out) *out = resp->size;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsFileClose(FsFile* f) {
|
|
serviceClose(&f->s);
|
|
}
|
|
|
|
// IDirectory implementation
|
|
void fsDirClose(FsDir* d) {
|
|
serviceClose(&d->s);
|
|
}
|
|
|
|
Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddRecvBuffer(&c, buf, sizeof(FsDirectoryEntry)*max_entries, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 inval;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
raw->inval = inval;
|
|
|
|
Result rc = serviceIpcDispatch(&d->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 total_entries;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
if (total_entries) *total_entries = resp->total_entries;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsDirGetEntryCount(FsDir* d, u64* count) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 1;
|
|
|
|
Result rc = serviceIpcDispatch(&d->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 count;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
if (R_SUCCEEDED(rc) && count) *count = resp->count;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
// IStorage implementation
|
|
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddRecvBuffer(&c, buf, len, 1);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
u64 offset;
|
|
u64 read_size;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
raw->offset = off;
|
|
raw->read_size = len;
|
|
|
|
Result rc = serviceIpcDispatch(&s->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result fsStorageGetSize(FsStorage* s, u64* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 4;
|
|
|
|
Result rc = serviceIpcDispatch(&s->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 size;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
if (R_SUCCEEDED(rc) && out) *out = resp->size;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsStorageClose(FsStorage* s) {
|
|
serviceClose(&s->s);
|
|
}
|
|
|
|
// ISaveDataInfoReader
|
|
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
ipcAddRecvBuffer(&c, buf, sizeof(FsSaveDataInfo)*max_entries, 0);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
|
|
Result rc = serviceIpcDispatch(&s->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u64 total_entries;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
if (total_entries) *total_entries = resp->total_entries;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsSaveDataIteratorClose(FsSaveDataIterator* s) {
|
|
serviceClose(&s->s);
|
|
}
|
|
|
|
// IEventNotifier
|
|
Result fsEventNotifierGetEventHandle(FsEventNotifier* e, Handle* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
|
|
Result rc = serviceIpcDispatch(&e->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = r.Handles[0];
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsEventNotifierClose(FsEventNotifier* e) {
|
|
serviceClose(&e->s);
|
|
}
|
|
|
|
// IDeviceOperator
|
|
Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out) {
|
|
IpcCommand c;
|
|
ipcInitialize(&c);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 cmd_id;
|
|
} *raw;
|
|
|
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
|
|
raw->magic = SFCI_MAGIC;
|
|
raw->cmd_id = 0;
|
|
|
|
Result rc = serviceIpcDispatch(&d->s);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
IpcParsedCommand r;
|
|
ipcParse(&r);
|
|
|
|
struct {
|
|
u64 magic;
|
|
u64 result;
|
|
u8 is_inserted;
|
|
} *resp = r.Raw;
|
|
|
|
rc = resp->result;
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*out = resp->is_inserted != 0;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void fsDeviceOperatorClose(FsDeviceOperator* d) {
|
|
serviceClose(&d->s);
|
|
}
|