Checkpoint. Just access JSON directly in FUSE handlers.

This commit is contained in:
Omar Rizwan 2018-11-22 02:52:54 -08:00
parent 66041e333c
commit b6f46e166d
3 changed files with 144 additions and 156 deletions

View file

@ -2,9 +2,13 @@ const ws = new WebSocket("ws://localhost:8888");
const ops = { const ops = {
NONE: 0, NONE: 0,
GETATTR: 1, GETATTR: 1,
READDIR: 2 OPEN: 2,
READDIR: 3,
READ: 4
}; };
const unix = { const unix = {
EPERM: 1, EPERM: 1,
ENOENT: 2, ENOENT: 2,
@ -24,6 +28,12 @@ const unix = {
S_IFSOCK: 0140000, // socket S_IFSOCK: 0140000, // socket
} }
function UnixError(error) {
this.name = "UnixError";
this.error = error;
}
UnixError.prototype = Error.prototype;
function queryTabs() { function queryTabs() {
return new Promise((resolve, reject) => chrome.tabs.query({}, resolve)); return new Promise((resolve, reject) => chrome.tabs.query({}, resolve));
} }
@ -54,22 +64,14 @@ function findRoute(path) {
for (let segment of path.split("/")) { for (let segment of path.split("/")) {
if (segment === "") continue; if (segment === "") continue;
route = route[segment] || route["*"]; route = route[segment] || route["*"];
if (!route) throw new UnixError(unix.ENOENT);
} }
return route; return route;
} }
async function readdir(path) {
let route = findRoute(path);
if (route.readdir) {
return route.readdir();
}
return Object.keys(route);
}
async function getattr(path) { async function getattr(path) {
let route = findRoute(path); let route = findRoute(path);
if (route.getattr) { if (route.getattr) {
return route.getattr(); return route.getattr();
} else { } else {
@ -78,39 +80,51 @@ async function getattr(path) {
st_nlink: 3 st_nlink: 3
}; };
} }
/* }
* const response = {};
* if (path === "/" || path === "/tabs" || path === "/tabs/by-title" || path === "/tabs/by-id") {
* response.st_mode = unix.S_IFDIR | 0755;
* response.st_nlink = 3;
* } else if (path === "/tabs/hello.txt") { async function readdir(path) {
* let route = findRoute(path);
* } else { if (route.readdir) {
* response.error = unix.ENOENT; return route.readdir();
* } }
* return response;*/ return Object.keys(route);
} }
ws.onmessage = async function(event) { ws.onmessage = async function(event) {
const req = JSON.parse(event.data); const req = JSON.parse(event.data);
console.log('req', Object.entries(ops).find(([op, opcode]) => opcode === req.op)[0], req); console.log('req', Object.entries(ops).find(([op, opcode]) => opcode === req.op)[0], req);
let response; let response = { op: req.op, error: unix.EIO };
if (req.op === ops.READDIR) { try {
response = { if (req.op === ops.GETATTR) {
op: ops.READDIR, response = {
entries: [".", "..", ...(await readdir(req.path))] op: ops.GETATTR,
}; st_mode: 0,
st_nlink: 0,
st_size: 0,
...(await getattr(req.path))
};
} else if (req.op === ops.OPEN) {
throw new UnixError(unix.EIO);
} else if (req.op === ops.GETATTR) { } else if (req.op === ops.READDIR) {
response = {
op: ops.READDIR,
entries: [".", "..", ...(await readdir(req.path))]
};
} else if (req.op === ops.READ) {
response = {
op: ops.READ,
buf: await read(req.path)
};
}
} catch (e) {
response = { response = {
op: ops.GETATTR, op: req.op,
st_mode: 0, error: e instanceof UnixError ? e.error : unix.EIO
st_nlink: 0, }
st_size: 0,
...(await getattr(req.path))
};
} }
console.log('response', Object.entries(ops).find(([op, opcode]) => opcode === response.op)[0], response); console.log('response', Object.entries(ops).find(([op, opcode]) => opcode === response.op)[0], response);

View file

@ -28,3 +28,12 @@ hello: hello.c
clean: clean:
rm -f $(TARGETS) *.o rm -f $(TARGETS) *.o
rm -rf *.dSYM rm -rf *.dSYM
remount: unmount mount
unmount:
killall -9 hello || true
diskutil unmount force mnt || true
mount: hello
./hello -s -f mnt

View file

@ -24,28 +24,14 @@ enum opcode {
NONE = 0, NONE = 0,
GETATTR, GETATTR,
READDIR OPEN,
}; READDIR,
READ
struct readdir {
char **entries;
size_t num_entries;
};
struct response {
enum opcode op;
int error;
union {
struct stat getattr;
struct readdir readdir;
} body;
}; };
pthread_cond_t response_cv = PTHREAD_COND_INITIALIZER; pthread_cond_t response_cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t response_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t response_mutex = PTHREAD_MUTEX_INITIALIZER;
struct response response = (struct response) { .op = NONE }; cJSON *response = NULL;
static const char *file_path = "/hello.txt"; static const char *file_path = "/hello.txt";
static const char file_content[] = "Hello World!\n"; static const char file_content[] = "Hello World!\n";
@ -76,34 +62,59 @@ void send_req_if_any() {
pthread_mutex_unlock(&request_data_mutex); pthread_mutex_unlock(&request_data_mutex);
} }
#define MAKE_REQ(op, body) \ static cJSON *await_response() {
do { \
pthread_mutex_lock(&request_data_mutex); \
int disconnected = (con == NULL); \
pthread_mutex_unlock(&request_data_mutex); \
if (disconnected) return -EIO; \
\
cJSON *req = cJSON_CreateObject(); \
cJSON_AddNumberToObject(req, "op", (int) op); \
body \
dispatch_send_req(req); \
cJSON_Delete(req); \
} while (0)
static struct response await_response(enum opcode op) {
pthread_mutex_lock(&response_mutex); pthread_mutex_lock(&response_mutex);
memset(&response, 0, sizeof response); response = NULL;
while (response.op == NONE) { while (response == NULL) {
pthread_cond_wait(&response_cv, &response_mutex); pthread_cond_wait(&response_cv, &response_mutex);
} }
struct response ret = response; cJSON *resp = response;
pthread_mutex_unlock(&response_mutex); pthread_mutex_unlock(&response_mutex);
return ret; return resp;
} }
#define MAKE_REQ(op, req_body, resp_handler) \
do { \
int ret = -1; \
cJSON *req = NULL; \
cJSON *resp = NULL; \
\
pthread_mutex_lock(&request_data_mutex); \
int disconnected = (con == NULL); \
pthread_mutex_unlock(&request_data_mutex); \
if (disconnected) { ret = -EIO; goto done; } \
\
req = cJSON_CreateObject(); \
cJSON_AddNumberToObject(req, "op", (int) op); \
req_body \
\
dispatch_send_req(req); \
\
resp = await_response();\
\
cJSON *error_item = cJSON_GetObjectItemCaseSensitive(resp, "error"); \
if (error_item) { \
ret = -error_item->valueint; \
if (ret != 0) goto done; \
} \
\
resp_handler \
\
ret = 0; \
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 static int
hello_getattr(const char *path, struct stat *stbuf) hello_getattr(const char *path, struct stat *stbuf)
{ {
@ -112,42 +123,24 @@ hello_getattr(const char *path, struct stat *stbuf)
MAKE_REQ(GETATTR, { MAKE_REQ(GETATTR, {
cJSON_AddStringToObject(req, "path", path); cJSON_AddStringToObject(req, "path", path);
}); }, {
JSON_GET_PROP_INT(stbuf->st_mode, "st_mode");
struct response resp = await_response(GETATTR); JSON_GET_PROP_INT(stbuf->st_nlink, "st_nlink");
if (resp.error != 0) { JSON_GET_PROP_INT(stbuf->st_size, "st_size");
printf("error re getattr(%s): %d\n", path, resp.error); printf("returning re getattr(%s)\n", path);
return -resp.error; });
}
stbuf->st_mode = resp.body.getattr.st_mode;
stbuf->st_nlink = resp.body.getattr.st_nlink;
stbuf->st_size = resp.body.getattr.st_size;
printf("returning re getattr(%s)\n", path);
/* if (strcmp(path, "/") == 0) { /\* The root directory of our file system. *\/ */
/* stbuf->st_mode = S_IFDIR | 0755; */
/* stbuf->st_nlink = 3; */
/* } else if (strcmp(path, file_path) == 0) { /\* The only file we have. *\/ */
/* stbuf->st_mode = S_IFREG | 0444; */
/* stbuf->st_nlink = 1; */
/* stbuf->st_size = file_size; */
/* } else /\* We reject everything else. *\/ */
/* return -ENOENT; */
return 0;
} }
static int static int
hello_open(const char *path, struct fuse_file_info *fi) hello_open(const char *path, struct fuse_file_info *fi)
{ {
if (strcmp(path, file_path) != 0) /* We only recognize one file. */ MAKE_REQ(OPEN, {
return -ENOENT; cJSON_AddStringToObject(req, "path", path);
cJSON_AddNumberToObject(req, "flags", fi->flags);
if ((fi->flags & O_ACCMODE) != O_RDONLY) /* Only reading allowed. */ }, {
return -EACCES; cJSON *fh_item = cJSON_GetObjectItemCaseSensitive(resp, "fh");
if (fh_item) fi->fh = fh_item->valueint;
return 0; });
} }
static int static int
@ -155,30 +148,35 @@ hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi) off_t offset, struct fuse_file_info *fi)
{ {
printf("\n\nreaddir(%s)\n", path); printf("\n\nreaddir(%s)\n", path);
// send {op: "readdir", path} to the websocket handler // send {op: READDIR, path} to the websocket handler
MAKE_REQ(READDIR, { MAKE_REQ(READDIR, {
cJSON_AddStringToObject(req, "path", path); cJSON_AddStringToObject(req, "path", path);
}); }, {
cJSON *entries = cJSON_GetObjectItemCaseSensitive(resp, "entries");
printf("awaiting response to readdir(%s)\n", path); cJSON *entry;
struct response resp = await_response(READDIR); cJSON_ArrayForEach(entry, entries) {
filler(buf, cJSON_GetStringValue(entry), NULL, 0);
struct readdir *readdir = &resp.body.readdir; printf("entry: [%s]\n", cJSON_GetStringValue(entry));
printf("response: %d files\n", (int) readdir->num_entries); }
});
for (size_t i = 0; i < readdir->num_entries; ++i) {
filler(buf, readdir->entries[i], NULL, 0);
printf("entry: [%s]\n", readdir->entries[i]);
}
return 0;
} }
static int static int
hello_read(const char *path, char *buf, size_t size, off_t offset, hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi) struct fuse_file_info *fi)
{ {
MAKE_REQ(OPEN, {
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);
}, {
});
if (strcmp(path, file_path) != 0) if (strcmp(path, file_path) != 0)
return -ENOENT; return -ENOENT;
@ -226,7 +224,7 @@ websocket_connected(struct wby_con *connection, void *userdata)
static int static int
websocket_frame(struct wby_con *connection, const struct wby_frame *frame, void *userdata) websocket_frame(struct wby_con *connection, const struct wby_frame *frame, void *userdata)
{ {
unsigned char data[1024] = {0}; unsigned char data[131072] = {0};
int i = 0; int i = 0;
printf("WebSocket frame incoming\n"); printf("WebSocket frame incoming\n");
@ -237,6 +235,7 @@ websocket_frame(struct wby_con *connection, const struct wby_frame *frame, void
if ((unsigned long) frame->payload_length > sizeof(data)) { if ((unsigned long) frame->payload_length > sizeof(data)) {
printf("Data too long!\n"); printf("Data too long!\n");
exit(1);
} }
while (i < frame->payload_length) { while (i < frame->payload_length) {
@ -266,44 +265,10 @@ websocket_frame(struct wby_con *connection, const struct wby_frame *frame, void
} }
pthread_mutex_lock(&response_mutex); pthread_mutex_lock(&response_mutex);
response = cJSON_Parse((const char *) data);
cJSON *ret = cJSON_Parse((const char *) data);
cJSON *op_item = cJSON_GetObjectItemCaseSensitive(ret, "op");
response.op = (enum opcode) op_item->valueint;
cJSON *error_item = cJSON_GetObjectItemCaseSensitive(ret, "error");
if (error_item) {
response.error = error_item->valueint;
if (response.error != 0) goto done;
}
if (response.op == READDIR) {
struct readdir *readdir = &response.body.readdir;
cJSON *entries = cJSON_GetObjectItemCaseSensitive(ret, "entries");
readdir->num_entries = cJSON_GetArraySize(entries);
readdir->entries = malloc(sizeof(char *) * readdir->num_entries);
int i = 0;
cJSON *entry;
cJSON_ArrayForEach(entry, entries) {
readdir->entries[i++] = strdup(cJSON_GetStringValue(entry));
}
} else if (response.op == GETATTR) {
struct stat *getattr = &response.body.getattr;
getattr->st_mode = cJSON_GetObjectItemCaseSensitive(ret, "st_mode")->valueint;
getattr->st_nlink = cJSON_GetObjectItemCaseSensitive(ret, "st_nlink")->valueint;
getattr->st_size = cJSON_GetObjectItemCaseSensitive(ret, "st_size")->valueint;
}
done:
if (ret) cJSON_Delete(ret);
pthread_cond_signal(&response_cv); pthread_cond_signal(&response_cv);
pthread_mutex_unlock(&response_mutex); pthread_mutex_unlock(&response_mutex);
return 0; return 0;
} }