mirror of
https://github.com/osnr/TabFS.git
synced 2024-05-17 21:16:35 +02:00
Checkpoint. Just access JSON directly in FUSE handlers.
This commit is contained in:
parent
66041e333c
commit
b6f46e166d
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
207
fs/hello.c
207
fs/hello.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue