diff options
author | Omar Rizwan <omar.rizwan@gmail.com> | 2019-02-25 13:02:25 -0800 |
---|---|---|
committer | Omar Rizwan <omar.rizwan@gmail.com> | 2019-02-25 13:02:25 -0800 |
commit | 784ec83696d9ecedc10ede022a035e671dd21607 (patch) | |
tree | a459ee535e22ce53c344dc53452050d511428a67 /fs/tabfs.c | |
parent | 90181466bd12553abef43f165b7b8a2c7ad2f1c3 (diff) |
Rewrite and refactor C half. No more shared memory! It's fast!
Three C modules:
- tabfs (main thread; talks to FUSE)
- common (tabfs<->ws communication helpers)
- ws (side thread; talks to browser over WebSocket)
It's single-threaded, but I don't think that matters anyway.
Diffstat (limited to 'fs/tabfs.c')
-rw-r--r-- | fs/tabfs.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/fs/tabfs.c b/fs/tabfs.c new file mode 100644 index 0000000..03cfeea --- /dev/null +++ b/fs/tabfs.c @@ -0,0 +1,210 @@ +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <pthread.h> +#include <fuse.h> + +#include "cJSON/cJSON.h" +#include "cJSON/cJSON.c" + +#include "common.h" +#include "ws.h" + +static cJSON *send_request_then_await_response(cJSON *req) { + char *request_data = cJSON_Print(req); // Will be freed on ws side. + common_send_tabfs_to_ws(request_data); + + char *response_data = common_receive_ws_to_tabfs(); + if (response_data == NULL) { + // Connection is dead. + return cJSON_Parse("{ \"error\": 5 }"); + } + + cJSON *resp = cJSON_Parse((const char *) response_data); + free(response_data); + + return resp; +} + +#define MAKE_REQ(op, req_body, resp_handler) \ + do { \ + int ret = -1; \ + cJSON *req = NULL; \ + cJSON *resp = NULL; \ + \ + req = cJSON_CreateObject(); \ + cJSON_AddStringToObject(req, "op", op); \ + req_body \ + \ + resp = send_request_then_await_response(req); \ + \ + cJSON *error_item = cJSON_GetObjectItemCaseSensitive(resp, "error"); \ + if (error_item) { \ + ret = -error_item->valueint; \ + if (ret != 0) goto done; \ + } \ + \ + ret = -1; \ + resp_handler \ + \ +done: \ + if (req != NULL) cJSON_Delete(req); \ + if (resp != NULL) cJSON_Delete(resp); \ + return ret; \ + } while (0) + +#define JSON_GET_PROP_INT(lvalue, key) \ + do { \ + lvalue = cJSON_GetObjectItemCaseSensitive(resp, key)->valueint; \ + } while (0) + +static int +tabfs_getattr(const char *path, struct stat *stbuf) +{ + memset(stbuf, 0, sizeof(struct stat)); + + MAKE_REQ("getattr", { + cJSON_AddStringToObject(req, "path", path); + }, { + JSON_GET_PROP_INT(stbuf->st_mode, "st_mode"); + JSON_GET_PROP_INT(stbuf->st_nlink, "st_nlink"); + JSON_GET_PROP_INT(stbuf->st_size, "st_size"); + + ret = 0; + }); +} + +static int +tabfs_readlink(const char *path, char *buf, size_t size) +{ + MAKE_REQ("readlink", { + cJSON_AddStringToObject(req, "path", path); + }, { + cJSON *resp_buf_item = cJSON_GetObjectItemCaseSensitive(resp, "buf"); + // FIXME: fix + char *resp_buf = cJSON_GetStringValue(resp_buf_item); + size_t resp_buf_len = strlen(resp_buf); + size = resp_buf_len < size ? resp_buf_len : size; + + memcpy(buf, resp_buf, size); + + ret = size; + }); +} + +static int +tabfs_open(const char *path, struct fuse_file_info *fi) +{ + MAKE_REQ("open", { + cJSON_AddStringToObject(req, "path", path); + cJSON_AddNumberToObject(req, "flags", fi->flags); + }, { + cJSON *fh_item = cJSON_GetObjectItemCaseSensitive(resp, "fh"); + if (fh_item) fi->fh = fh_item->valueint; + + ret = 0; + }); +} + +static int +tabfs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + MAKE_REQ("read", { + cJSON_AddStringToObject(req, "path", path); + cJSON_AddNumberToObject(req, "size", size); + cJSON_AddNumberToObject(req, "offset", offset); + + cJSON_AddNumberToObject(req, "fh", fi->fh); + cJSON_AddNumberToObject(req, "flags", fi->flags); + }, { + cJSON *resp_buf_item = cJSON_GetObjectItemCaseSensitive(resp, "buf"); + if (!resp_buf_item) return -EIO; + + char *resp_buf = cJSON_GetStringValue(resp_buf_item); + if (!resp_buf) return -EIO; + + size_t resp_buf_len = strlen(resp_buf); + size = resp_buf_len < size ? resp_buf_len : size; + + memcpy(buf, resp_buf, size); + + ret = size; + }); +} + +static int tabfs_release(const char *path, struct fuse_file_info *fi) { + MAKE_REQ("release", { + cJSON_AddStringToObject(req, "path", path); + cJSON_AddNumberToObject(req, "fh", fi->fh); + }, { + ret = 0; + }); +} + +static int +tabfs_opendir(const char *path, struct fuse_file_info *fi) +{ + MAKE_REQ("opendir", { + cJSON_AddStringToObject(req, "path", path); + cJSON_AddNumberToObject(req, "flags", fi->flags); + }, { + cJSON *fh_item = cJSON_GetObjectItemCaseSensitive(resp, "fh"); + if (fh_item) fi->fh = fh_item->valueint; + + ret = 0; + }); +} + +static int +tabfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + // send {op: "readdir", path} to the websocket handler + MAKE_REQ("readdir", { + cJSON_AddStringToObject(req, "path", path); + }, { + cJSON *entries = cJSON_GetObjectItemCaseSensitive(resp, "entries"); + cJSON *entry; + cJSON_ArrayForEach(entry, entries) { + filler(buf, cJSON_GetStringValue(entry), NULL, 0); + } + + ret = 0; + }); +} + +static int +tabfs_releasedir(const char *path, struct fuse_file_info *fi) +{ + MAKE_REQ("releasedir", { + cJSON_AddStringToObject(req, "path", path); + cJSON_AddNumberToObject(req, "fh", fi->fh); + }, { + ret = 0; + }); +} + +static struct fuse_operations tabfs_filesystem_operations = { + .getattr = tabfs_getattr, /* To provide size, permissions, etc. */ + .readlink = tabfs_readlink, + .open = tabfs_open, /* To enforce read-only access. */ + .read = tabfs_read, /* To provide file content. */ + .release = tabfs_release, + + .opendir = tabfs_opendir, + .readdir = tabfs_readdir, /* To provide directory listing. */ + .releasedir = tabfs_releasedir +}; + +int +main(int argc, char **argv) +{ + common_init(); + + pthread_t websocket_thread; + pthread_create(&websocket_thread, NULL, websocket_main, NULL); + + return fuse_main(argc, argv, &tabfs_filesystem_operations, NULL); +} |