From 74b14f4c63f64d341bb060e0dba4d57e78e6b3c3 Mon Sep 17 00:00:00 2001 From: plutoo Date: Sat, 7 Oct 2017 22:49:16 +0200 Subject: [PATCH] Introducing fs.. --- nx/include/switch.h | 1 + nx/include/switch/ipc.h | 8 +- nx/include/switch/services/fs.h | 57 +++ nx/source/services/fs.c | 720 ++++++++++++++++++++++++++++++++ 4 files changed, 782 insertions(+), 4 deletions(-) create mode 100644 nx/include/switch/services/fs.h create mode 100644 nx/source/services/fs.c diff --git a/nx/include/switch.h b/nx/include/switch.h index c6826efa..8c7f4988 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -19,6 +19,7 @@ extern "C" { #include #include +#include #include #include #include diff --git a/nx/include/switch/ipc.h b/nx/include/switch/ipc.h index e2dc2e88..0ddef2c3 100644 --- a/nx/include/switch/ipc.h +++ b/nx/include/switch/ipc.h @@ -8,13 +8,13 @@ typedef struct { size_t NumSend; // A size_t NumRecv; // B size_t NumTransfer; // W - void* Buffers[4]; + const void* Buffers[4]; size_t BufferSizes[4]; u8 Flags[4]; size_t NumStaticIn; // X size_t NumStaticOut; // C - void* Statics[4]; + const void* Statics[4]; size_t StaticSizes[4]; u8 Indices[4]; @@ -53,7 +53,7 @@ typedef struct { u32 Packed; } IpcStaticRecvDescriptor; -static inline void ipcAddSendBuffer(IpcCommand* cmd, void* buffer, size_t size, u8 flags) { +static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, u8 flags) { size_t off = cmd->NumSend; cmd->Buffers[off] = buffer; cmd->BufferSizes[off] = size; @@ -77,7 +77,7 @@ static inline void ipcAddTransferBuffer(IpcCommand* cmd, void* buffer, size_t si cmd->NumTransfer++; } -static inline void ipcAddSendStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) { +static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) { size_t off = cmd->NumStaticIn; cmd->Statics[off] = buffer; cmd->StaticSizes[off] = size; diff --git a/nx/include/switch/services/fs.h b/nx/include/switch/services/fs.h new file mode 100644 index 00000000..ba0b26c6 --- /dev/null +++ b/nx/include/switch/services/fs.h @@ -0,0 +1,57 @@ +// Copyright 2017 plutoo + +// We use wrapped handles for type safety. + +typedef struct { + Handle h; +} FsFileSystem; + +typedef struct { + Handle h; +} FsFile; + +typedef struct { + Handle h; +} FsDir; + +typedef struct { + Handle h; +} FsStorage; + +typedef enum { + ENTRYTYPE_FILE=0, + ENTRYTYPE_DIR =1 +} FsEntryType; + +#define FS_MAX_PATH 0x301 + +Result fsInitialize(); +Result fsMountSdcard(FsFileSystem* out); +// todo: Rest of commands here + +// IFileSystem +Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags); +Result fsFsDeleteFile(FsFileSystem* fs, const char* path); +Result fsFsCreateDirectory(FsFileSystem* fs, const char* path); +Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path); +Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path); +Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1); +Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path1); +Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out); +Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out); +Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* out); +Result fsFsCommit(FsFileSystem* fs); +Result fsFsGetFreeSpace(FsFileSystem* fs, u64* out); +Result fsFsGetTotalSpace(FsFileSystem* fs, u64* out); +void fsFsClose(FsFileSystem* fs); + +// IFile +Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out); +Result fsFileWrite(FsFile* f, u64 off, void* buf, size_t len, size_t* out); +Result fsFileFlush(FsFile* f); +Result fsFileSetSize(FsFile* f, u64 sz); +Result fsFileGetSize(FsFile* f, u64* out); +void fsFileClose(FsFile* f); + +// todo: IDirectory +// todo: IStorage diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c new file mode 100644 index 00000000..d4251ff9 --- /dev/null +++ b/nx/source/services/fs.c @@ -0,0 +1,720 @@ +// Copyright 2017 plutoo +#include + +static Handle g_fsHandle = -1; + +Result fsInitialize() { + Result rc = smGetService(&g_fsHandle, "fsp-srv"); + + if (R_SUCCEEDED(rc)) { + 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 = ipcDispatch(g_fsHandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + } + } + + 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 = ipcDispatch(g_fsHandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + out->h = r.Handles[0]; + } + } + + return rc; +} + +// 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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result fsRenameFile(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, 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + + Result rc = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result fsRenameDirectory(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, 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 6; + + Result rc = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + out->h = 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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + out->h = 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 = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result fsFsGetFreeSpace(FsFileSystem* fs, 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 = 11; + + Result rc = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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, 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 = 12; + + Result rc = ipcDispatch(fs->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 space; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->space; + } + } + + return rc; +} + +void fsFsClose(FsFileSystem* fs) { + svcCloseHandle(fs->h); +} + +// 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 = ipcDispatch(f->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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, void* buf, size_t len, size_t* out) { + 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 = ipcDispatch(f->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 bytes_written; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->bytes_written; + } + } + + 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 = ipcDispatch(f->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(f->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&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 = ipcDispatch(f->h); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 size; + } *resp = r.Raw; + + rc = resp->size; + } + + return rc; +} + +void fsFileClose(FsFile* f) { + svcCloseHandle(f->h); +} +