From bd8c03601071119f96ebdc942865f0f2a1c261f5 Mon Sep 17 00:00:00 2001 From: Andrew Osheroff Date: Wed, 31 Jul 2019 23:59:36 +0200 Subject: [PATCH] big macro refactor compiles --- fuse-native.c | 746 +++++++++++++++++++++++++------------------------- index.js | 355 ++++++++++++++++-------- 2 files changed, 614 insertions(+), 487 deletions(-) diff --git a/fuse-native.c b/fuse-native.c index 9c47902..ec1c79f 100644 --- a/fuse-native.c +++ b/fuse-native.c @@ -13,7 +13,6 @@ #include #include - #include #include #include @@ -29,15 +28,43 @@ blk \ napi_close_handle_scope(env, scope); -#define FUSE_NATIVE_HANDLER(blk) \ +#define FUSE_NATIVE_HANDLER(name, blk) \ struct fuse_context *ctx = fuse_get_context(); \ fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; \ fuse_thread_locals_t *l = get_thread_locals(); \ + l->fuse = ft; \ + l->op = op_##name; \ blk \ uv_async_send(&(l->async)); \ fuse_native_semaphore_wait(&(l->sem)); \ return l->res; +#define FUSE_METHOD(name, callbackArgs, signalArgs, signature, callBlk, callbackBlk, signalBlk) \ + static void fuse_native_dispatch_##name (uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { \ + uint32_t op = op_##name; \ + FUSE_NATIVE_CALLBACK(ft->handlers[op], { \ + napi_value argv[callbackArgs + 2]; \ + napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); \ + napi_create_uint32(env, l->op, &(argv[1])); \ + callbackBlk \ + NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, callbackArgs + 2, argv, NULL) \ + }) \ + } \ + NAPI_METHOD(fuse_native_signal_##name) { \ + NAPI_ARGV(signalArgs + 2) \ + NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); \ + NAPI_ARGV_INT32(res, 1); \ + signalBlk \ + l->res = res; \ + fuse_native_semaphore_signal(&(l->sem)); \ + return NULL; \ + } \ + static int fuse_native_##name signature { \ + FUSE_NATIVE_HANDLER(name, callBlk) \ + } \ + +// Opcodes + static const uint32_t op_init = 0; static const uint32_t op_error = 1; static const uint32_t op_access = 2; @@ -74,6 +101,8 @@ static const uint32_t op_mkdir = 32; static const uint32_t op_rmdir = 33; static const uint32_t op_destroy = 34; +// Data structures + typedef struct { napi_env env; pthread_t thread; @@ -81,13 +110,7 @@ typedef struct { napi_ref ctx; // Operation handlers - napi_ref on_path_op; - napi_ref on_stat_op; - napi_ref on_buffer_op; - napi_ref on_xattr_op; - napi_ref on_statfs; - napi_ref on_readdir; - napi_ref on_symlink; + napi_ref handlers[34]; struct fuse *fuse; struct fuse_chan *ch; @@ -133,6 +156,7 @@ typedef struct { } fuse_thread_locals_t; static pthread_key_t thread_locals_key; +static fuse_thread_locals_t* get_thread_locals (); // Helpers // TODO: Extract into a separate file. @@ -184,456 +208,400 @@ static void populate_statvfs (uint32_t *ints, struct statvfs* statvfs) { statvfs->f_namemax = *ints++; } -// Dispatchers - -static void fuse_native_dispatch_statfs(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_statfs, { - napi_value argv[2]; +// Methods - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 2, argv, NULL) +FUSE_METHOD(statfs, 0, 1, (struct statvfs *statvfs), { + l->statvfs = statvfs; + }, + {}, + { + NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) + populate_statvfs(ints, l->statvfs); }) -} -static void fuse_native_dispatch_stat(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_stat_op, { - napi_value argv[4]; +FUSE_METHOD(getattr, 1, 1, (const char *path, struct stat *stat, struct fuse_file_info *info), { + l->path = path; + l->stat = stat; + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + }, + { + NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) + populate_stat(ints, l->stat); + }) - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); +FUSE_METHOD(fgetattr, 2, 1, (const char *path, struct stat *stat, struct fuse_file_info *info), { + l->path = path; + l->stat = stat; + l->info = info; + }, + { napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); if (l->info != NULL) { napi_create_uint32(env, l->info->fh, &(argv[3])); } else { napi_create_uint32(env, 0, &(argv[3])); } - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 4, argv, NULL) + }, + { + NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) + populate_stat(ints, l->stat); }) -} - -static void fuse_native_dispatch_path(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_path_op, { - napi_value argv[7]; - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); +FUSE_METHOD(access, 2, 0, (const char *path, int mode), { + l->path = path; + l->mode = mode; + }, + { napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); napi_create_uint32(env, l->mode, &(argv[3])); + }, + {}) +FUSE_METHOD(open, 1, 1, (const char *path, struct fuse_file_info *info), { + l->path = path; + l->info = info; + }, + { if (l->info != NULL) { - napi_create_uint32(env, l->info->fh, &(argv[4])); + napi_create_uint32(env, l->info->fh, &(argv[2])); } else { - napi_create_uint32(env, 0, &(argv[4])); + napi_create_uint32(env, 0, &(argv[2])); } - - if (l->atim != NULL) { - napi_create_external_arraybuffer(env, l->atim, 2 * sizeof(uint32_t), &fin, NULL, &argv[5]); - napi_create_external_arraybuffer(env, l->mtim, 2 * sizeof(uint32_t), &fin, NULL, &argv[6]); - } else { - napi_create_external_arraybuffer(env, NULL, 0, &fin, NULL, &argv[5]); - napi_create_external_arraybuffer(env, NULL, 0, &fin, NULL, &argv[6]); + }, + { + NAPI_ARGV_INT32(fd, 2) + if (fd != 0) { + l->info->fh = fd; } - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 7, argv, NULL) }) -} - -static void fuse_native_dispatch_readdir(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_readdir, { - napi_value argv[3]; - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); - napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 3, argv, NULL) - }) -} - -static void fuse_native_dispatch_buffer(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_buffer_op, { - napi_value argv[7]; - - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); - napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); - napi_create_uint32(env, l->info->fh, &(argv[3])); - napi_create_external_buffer(env, l->len, l->buf, &fin, NULL, &(argv[4])); - napi_create_uint32(env, l->len, &(argv[5])); - napi_create_uint32(env, l->offset, &(argv[6])); - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 3, argv, NULL) - }) -} - -static void fuse_native_dispatch_xattr(uv_async_t* handle, int status, fuse_thread_locals_t* l, fuse_thread_t* ft) { - FUSE_NATIVE_CALLBACK(ft->on_xattr_op, { - napi_value argv[9]; - - napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); - napi_create_uint32(env, l->op, &(argv[1])); - napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); - napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); - napi_create_string_utf8(env, l->value, NAPI_AUTO_LENGTH, &(argv[4])); - napi_create_external_buffer(env, l->size, l->list, &fin, NULL, &(argv[5])); - napi_create_uint32(env, l->size, &(argv[6])); - napi_create_uint32(env, l->flags, &(argv[7])); - napi_create_uint32(env, l->position, &(argv[8])); - - NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 9, argv, NULL) - }) -} - -static void fuse_native_dispatch (uv_async_t* handle, int status) { - fuse_thread_locals_t *l = (fuse_thread_locals_t *) handle->data; - fuse_thread_t *ft = l->fuse; - - switch (l->op) { - case (op_statfs): - return fuse_native_dispatch_statfs(handle, status, l, ft); - case (op_fgetattr): - case (op_getattr): - return fuse_native_dispatch_stat(handle, status, l, ft); - case (op_readdir): - return fuse_native_dispatch_readdir(handle, status, l, ft); - case (op_open): - case (op_create): - case (op_access): - case (op_utimens): - return fuse_native_dispatch_path(handle, status, l, ft); - case (op_release): - case (op_releasedir): - case (op_read): - case (op_write): - return fuse_native_dispatch_buffer(handle, status, l, ft); - case (op_getxattr): - case (op_setxattr): - case (op_listxattr): - case (op_removexattr): - return fuse_native_dispatch_xattr(handle, status, l, ft); - } -} - -static fuse_thread_locals_t* get_thread_locals () { - void *data = pthread_getspecific(thread_locals_key); - - if (data != NULL) { - return (fuse_thread_locals_t *) data; - } - - fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t)); - - // TODO: mutex me?? - int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch); - - l->async.data = l; - - if (err < 0) { - printf("uv_async failed: %i\n", err); - return NULL; - } - - fuse_native_semaphore_init(&(l->sem)); - pthread_setspecific(thread_locals_key, (void *) l); - - return l; -} - -static void* start_fuse_thread (void *data) { - fuse_thread_t *ft = (fuse_thread_t *) data; - fuse_loop_mt(ft->fuse); - - // printf("her nu\n"); - // fuse_unmount(mnt, ch); - // fuse_session_remove_chan(ch); - // fuse_destroy(fuse); - - return NULL; -} - -// Handlers - -static int fuse_native_create (const char *path, mode_t mode, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(create, 2, 1, (const char *path, mode_t mode, struct fuse_file_info *info), { l->path = path; l->mode = mode; l->info = info; - l->op = op_create; - }) -} - -static int fuse_native_access(const char *path, int mode) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; - l->path = path; - l->mode = mode; - l->op = op_access; + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_uint32(env, l->mode, &(argv[3])); + }, + { + NAPI_ARGV_INT32(fd, 2) + if (fd != 0) { + l->info->fh = fd; + } }) -} -static int fuse_native_open(const char *path, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(utimens, 2, 0, (const char *path, const struct timespec tv[2]), { l->path = path; - l->info = info; - l->op = op_open; - }) -} - -static int fuse_native_release (const char *path, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; + from_timespec(&tv[0], l->atim); + from_timespec(&tv[1], l->mtim); + }, + { + napi_create_external_arraybuffer(env, l->atim, 2 * sizeof(uint32_t), &fin, NULL, &argv[2]); + napi_create_external_arraybuffer(env, l->mtim, 2 * sizeof(uint32_t), &fin, NULL, &argv[3]); + }, + {}) + +FUSE_METHOD(release, 2, 0, (const char *path, struct fuse_file_info *info), { l->path = path; l->info = info; - l->op = op_release; - }) -} + }, + { + if (l->info != NULL) { + napi_create_uint32(env, l->info->fh, &(argv[2])); + } else { + napi_create_uint32(env, 0, &(argv[2])); + } + }, + {}) -static int fuse_native_releasedir (const char *path, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(releasedir, 2, 0, (const char *path, struct fuse_file_info *info), { l->path = path; l->info = info; - l->op = op_releasedir; - }) -} + }, + { + if (l->info != NULL) { + napi_create_uint32(env, l->info->fh, &(argv[2])); + } else { + napi_create_uint32(env, 0, &(argv[2])); + } + }, + {}) -static int fuse_native_write (const char *path, const char *buf, size_t len, off_t offset, struct fuse_file_info * info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(read, 5, 1, (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info), { l->path = path; l->buf = buf; l->len = len; l->offset = offset; l->info = info; - l->op = op_write; + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_uint32(env, l->info->fh, &(argv[3])); + napi_create_external_buffer(env, l->len, l->buf, &fin, NULL, &(argv[4])); + napi_create_uint32(env, l->len, &(argv[5])); + napi_create_uint32(env, l->offset, &(argv[6])); + }, + { + // TODO: handle bytes processed? }) -} -static int fuse_native_read (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(write, 5, 1, (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info), { l->path = path; l->buf = buf; l->len = len; l->offset = offset; l->info = info; - l->op = op_read; - }) -} - -static int fuse_native_fgetattr (const char *path, struct stat *stat, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; - l->path = path; - l->stat = stat; - l->info = info; - l->op = op_getattr; - }) -} - -static int fuse_native_statfs (struct statvfs *statvfs) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; - l->statvfs = statvfs; - l->op = op_statfs; + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_uint32(env, l->info->fh, &(argv[3])); + napi_create_external_buffer(env, l->len, l->buf, &fin, NULL, &(argv[4])); + napi_create_uint32(env, l->len, &(argv[5])); + napi_create_uint32(env, l->offset, &(argv[6])); + }, + { + // TODO: handle bytes processed? }) -} -static int fuse_native_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(readdir, 1, 2, (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info), { l->buf = buf; l->path = path; l->offset = offset; l->info = info; l->readdir_filler = filler; - l->op = op_readdir; + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + }, + { + uint32_t stats_length; + uint32_t names_length; + napi_get_array_length(env, argv[3], &stats_length); + napi_get_array_length(env, argv[2], &names_length); + + napi_value raw_names = argv[2]; + napi_value raw_stats = argv[3]; + + if (names_length != stats_length) { + NAPI_FOR_EACH(raw_names, raw_name) { + NAPI_UTF8(name, 1024, raw_name) + int err = l->readdir_filler(l->buf, name, NULL, 0); + if (err == 1) { + break; + } + } + } else { + NAPI_FOR_EACH(raw_names, raw_name) { + NAPI_UTF8(name, 1024, raw_name) + napi_value raw_stat; + napi_get_element(env, raw_stats, i, &raw_stat); + + NAPI_BUFFER_CAST(uint32_t*, stats_array, raw_stat); + struct stat st; + populate_stat(stats_array, &st); + + int err = l->readdir_filler(l->buf, name, stat, 0); + if (err == 1) { + break; + } + } + } }) -} #ifdef __APPLE__ -static int fuse_native_setxattr (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; + +FUSE_METHOD(setxattr, 6, 0, (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position), { l->path = path; l->name = name; l->value = value; l->size = size; l->flags = flags; l->position = position; - l->op = op_setxattr; - }) -} + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); + napi_create_string_utf8(env, l->value, NAPI_AUTO_LENGTH, &(argv[4])); + napi_create_uint32(env, l->size, &(argv[5])); + napi_create_uint32(env, l->flags, &(argv[6])); + napi_create_uint32(env, l->position, &(argv[7])); + }, + {}) -static int fuse_native_getxattr (const char *path, const char *name, const char *value, size_t size, uint32_t position) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(getxattr, 5, 0, (const char *path, const char *name, const char *value, size_t size, uint32_t position), { l->path = path; l->name = name; l->value = value; l->size = size; l->position = position; - l->op = op_getxattr; - }) -} + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); + napi_create_string_utf8(env, l->value, NAPI_AUTO_LENGTH, &(argv[4])); + napi_create_uint32(env, l->size, &(argv[5])); + napi_create_uint32(env, l->position, &(argv[6])); + }, + {}) + #else -static int fuse_native_setxattr (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; + +FUSE_METHOD(setxattr, 5, 0, (const char *path, const char *name, const char *value, size_t size, int flags), { l->path = path; l->name = name; l->value = value; l->size = size; l->flags = flags; - l->position = position; - l->op = op_setxattr; - }) -} + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); + napi_create_string_utf8(env, l->value, NAPI_AUTO_LENGTH, &(argv[4])); + napi_create_uint32(env, l->size, &(argv[5])); + napi_create_uint32(env, l->flags, &(argv[6])); + }, + {}) -static int fuse_native_getxattr (const char *path, const char *name, const char *value, size_t size, uint32_t position) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(getxattr, 4, 0, (const char *path, const char *name, const char *value, size_t size), { l->path = path; l->name = name; l->value = value; l->size = size; - l->position = position; - l->op = op_getxattr; - }) -} + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); + napi_create_string_utf8(env, l->value, NAPI_AUTO_LENGTH, &(argv[4])); + napi_create_uint32(env, l->size, &(argv[5])); + }, + {}) + #endif -static int fuse_native_listxattr (const char *path, char *list, size_t size) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(listxattr, 3, 0, (const char *path, char *list, size_t size), { l->path = path; l->list = list; l->size = size; - l->op = op_listxattr; - }) -} + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_external_buffer(env, l->size, l->list, &fin, NULL, &(argv[3])); + napi_create_uint32(env, l->size, &(argv[4])); + }, + {}) -static int fuse_native_removexattr (const char *path, const char *name) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; +FUSE_METHOD(removexattr, 2, 0, (const char *path, const char *name), { l->path = path; l->name = name; - l->op = op_removexattr; - }) -} - -static int fuse_native_utimens (const char *path, const struct timespec tv[2]) { - FUSE_NATIVE_HANDLER({ - l->fuse = ft; - l->path = path; - from_timespec(&tv[0], l->atim); - from_timespec(&tv[1], l->mtim); - l->op = op_utimens; - }) -} - -// Signallers + }, + { + napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); + napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3])); + }, + {}) + +FUSE_METHOD(init, 0, 0, (struct fuse_conn_info *conn, struct fuse_config *cfg), {}, {}, {}) + +FUSE_METHOD(error, 0, 0, (), {}, {}, {}) +FUSE_METHOD(flush, 0, 0, (), {}, {}, {}) +FUSE_METHOD(fsync, 0, 0, (), {}, {}, {}) +FUSE_METHOD(fsyncdir, 0, 0, (), {}, {}, {}) +FUSE_METHOD(truncate, 0, 0, (), {}, {}, {}) +FUSE_METHOD(ftruncate, 0, 0, (), {}, {}, {}) +FUSE_METHOD(readlink, 0, 0, (), {}, {}, {}) +FUSE_METHOD(chown, 0, 0, (), {}, {}, {}) +FUSE_METHOD(chmod, 0, 0, (), {}, {}, {}) +FUSE_METHOD(mknod, 0, 0, (), {}, {}, {}) +FUSE_METHOD(opendir, 0, 0, (), {}, {}, {}) +FUSE_METHOD(unlink, 0, 0, (), {}, {}, {}) +FUSE_METHOD(rename, 0, 0, (), {}, {}, {}) +FUSE_METHOD(link, 0, 0, (), {}, {}, {}) +FUSE_METHOD(symlink, 0, 0, (), {}, {}, {}) +FUSE_METHOD(mkdir, 0, 0, (), {}, {}, {}) +FUSE_METHOD(rmdir, 0, 0, (), {}, {}, {}) +FUSE_METHOD(destroy, 0, 0, (), {}, {}, {}) -NAPI_METHOD(fuse_native_signal_path) { - NAPI_ARGV(3) - NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); - NAPI_ARGV_INT32(res, 1) - NAPI_ARGV_INT32(fd, 2) +static void fuse_native_dispatch (uv_async_t* handle, int status) { + fuse_thread_locals_t *l = (fuse_thread_locals_t *) handle->data; + fuse_thread_t *ft = l->fuse; - l->res = res; - if (fd != 0) { - l->info->fh = fd; + // TODO: Either use a function pointer (like ft->handlers[op]) or generate with a macro. + switch (l->op) { + case (op_init): return fuse_native_dispatch_init(handle, status, l, ft); + case (op_statfs): return fuse_native_dispatch_statfs(handle, status, l, ft); + case (op_fgetattr): return fuse_native_dispatch_fgetattr(handle, status, l, ft); + case (op_getattr): return fuse_native_dispatch_getattr(handle, status, l, ft); + case (op_readdir): return fuse_native_dispatch_readdir(handle, status, l, ft); + case (op_open): return fuse_native_dispatch_open(handle, status, l, ft); + case (op_create): return fuse_native_dispatch_create(handle, status, l, ft); + case (op_access): return fuse_native_dispatch_access(handle, status, l, ft); + case (op_utimens): return fuse_native_dispatch_utimens(handle, status, l, ft); + case (op_release): return fuse_native_dispatch_release(handle, status, l, ft); + case (op_releasedir): return fuse_native_dispatch_releasedir(handle, status, l, ft); + case (op_read): return fuse_native_dispatch_read(handle, status, l, ft); + case (op_write): return fuse_native_dispatch_write(handle, status, l, ft); + case (op_getxattr): return fuse_native_dispatch_getxattr(handle, status, l, ft); + case (op_setxattr): return fuse_native_dispatch_setxattr(handle, status, l, ft); + case (op_listxattr): return fuse_native_dispatch_listxattr(handle, status, l, ft); + case (op_removexattr): return fuse_native_dispatch_removexattr(handle, status, l, ft); + case (op_error): return fuse_native_dispatch_error(handle, status, l, ft); + case (op_flush): return fuse_native_dispatch_flush(handle, status, l, ft); + case (op_fsync): return fuse_native_dispatch_fsync(handle, status, l, ft); + case (op_fsyncdir): return fuse_native_dispatch_fsyncdir(handle, status, l, ft); + case (op_truncate): return fuse_native_dispatch_truncate(handle, status, l, ft); + case (op_ftruncate): return fuse_native_dispatch_ftruncate(handle, status, l, ft); + case (op_readlink): return fuse_native_dispatch_readlink(handle, status, l, ft); + case (op_chown): return fuse_native_dispatch_chown(handle, status, l, ft); + case (op_chmod): return fuse_native_dispatch_chmod(handle, status, l, ft); + case (op_mknod): return fuse_native_dispatch_mknod(handle, status, l, ft); + case (op_opendir): return fuse_native_dispatch_opendir(handle, status, l, ft); + case (op_unlink): return fuse_native_dispatch_unlink(handle, status, l, ft); + case (op_rename): return fuse_native_dispatch_rename(handle, status, l, ft); + case (op_link): return fuse_native_dispatch_link(handle, status, l, ft); + case (op_symlink): return fuse_native_dispatch_symlink(handle, status, l, ft); + case (op_mkdir): return fuse_native_dispatch_mkdir(handle, status, l, ft); + case (op_rmdir): return fuse_native_dispatch_rmdir(handle, status, l, ft); + case (op_destroy): return fuse_native_dispatch_destroy(handle, status, l, ft); + default: return; } - fuse_native_semaphore_signal(&(l->sem)); - - return NULL; } -NAPI_METHOD(fuse_native_signal_stat) { - NAPI_ARGV(4) - NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); - NAPI_ARGV_INT32(res, 1) - NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) - - populate_stat(ints, l->stat); - l->res = res; - fuse_native_semaphore_signal(&(l->sem)); - - return NULL; -} +static fuse_thread_locals_t* get_thread_locals () { + void *data = pthread_getspecific(thread_locals_key); -NAPI_METHOD(fuse_native_signal_buffer) { - NAPI_ARGV(2) - NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); - NAPI_ARGV_INT32(res, 1) + if (data != NULL) { + return (fuse_thread_locals_t *) data; + } - l->res = res; - fuse_native_semaphore_signal(&(l->sem)); + fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t)); - return NULL; -} + // TODO: mutex me?? + int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch); -NAPI_METHOD(fuse_native_signal_xattr) { -} + l->async.data = l; -NAPI_METHOD(fuse_native_signal_statfs) { - NAPI_ARGV(3) - NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); - NAPI_ARGV_INT32(res, 1) - NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) + if (err < 0) { + printf("uv_async failed: %i\n", err); + return NULL; + } - populate_statvfs(ints, l->statvfs); - l->res = res; - fuse_native_semaphore_signal(&(l->sem)); + fuse_native_semaphore_init(&(l->sem)); + pthread_setspecific(thread_locals_key, (void *) l); - return NULL; + return l; } -NAPI_METHOD(fuse_native_signal_readdir) { - NAPI_ARGV(4) - NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); - NAPI_ARGV_INT32(res, 1) - - uint32_t stats_length; - uint32_t names_length; - napi_get_array_length(env, argv[3], &stats_length); - napi_get_array_length(env, argv[2], &names_length); - - napi_value raw_names = argv[2]; - napi_value raw_stats = argv[3]; - - if (names_length != stats_length) { - NAPI_FOR_EACH(raw_names, raw_name) { - NAPI_UTF8(name, 1024, raw_name) - int err = l->readdir_filler(l->buf, name, NULL, 0); - if (err == 1) { - break; - } - } - } else { - NAPI_FOR_EACH(raw_names, raw_name) { - NAPI_UTF8(name, 1024, raw_name) - napi_value raw_stat; - napi_get_element(env, raw_stats, i, &raw_stat); - - NAPI_BUFFER_CAST(uint32_t*, stats_array, raw_stat); - struct stat st; - populate_stat(stats_array, &st); - - int err = l->readdir_filler(l->buf, name, stat, 0); - if (err == 1) { - break; - } - } - } +static void* start_fuse_thread (void *data) { + fuse_thread_t *ft = (fuse_thread_t *) data; + fuse_loop_mt(ft->fuse); - l->res = res; - fuse_native_semaphore_signal(&(l->sem)); + // printf("her nu\n"); + // fuse_unmount(mnt, ch); + // fuse_session_remove_chan(ch); + // fuse_destroy(fuse); return NULL; } @@ -646,18 +614,17 @@ NAPI_METHOD(fuse_native_mount) { NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 2); napi_create_reference(env, argv[3], 1, &(ft->ctx)); - napi_create_reference(env, argv[4], 1, &(ft->on_path_op)); - napi_create_reference(env, argv[5], 1, &(ft->on_stat_op)); - napi_create_reference(env, argv[6], 1, &(ft->on_buffer_op)); - napi_create_reference(env, argv[7], 1, &(ft->on_xattr_op)); - napi_create_reference(env, argv[8], 1, &(ft->on_statfs)); - napi_create_reference(env, argv[9], 1, &(ft->on_readdir)); - napi_create_reference(env, argv[10], 1, &(ft->on_symlink)); + napi_ref handlers; + napi_create_reference(env, argv[4], 1, &handlers); + + NAPI_FOR_EACH(handlers, handler) { + napi_create_reference(env, handler, 1, &ft->handlers[i]); + } ft->env = env; struct fuse_operations ops = { - .getattr = fuse_native_fgetattr, + .getattr = fuse_native_getattr, .fgetattr = fuse_native_fgetattr, .statfs = fuse_native_statfs, .readdir = fuse_native_readdir, @@ -673,9 +640,7 @@ NAPI_METHOD(fuse_native_mount) { .listxattr = fuse_native_listxattr, .removexattr = fuse_native_removexattr, .utimens = fuse_native_utimens, - /* .init = fuse_native_init, - .error = fuse_native_error, .flush = fuse_native_flush, .fsync = fuse_native_fsync, .fsyncdir = fuse_native_fsyncdir, @@ -692,8 +657,7 @@ NAPI_METHOD(fuse_native_mount) { .symlink = fuse_native_symlink, .mkdir = fuse_native_mkdir, .rmdir = fuse_native_rmdir, - .destroy = fuse_native_destroy, - */ + .destroy = fuse_native_destroy }; int _argc = 2; @@ -746,14 +710,48 @@ NAPI_METHOD(fuse_native_unmount) { NAPI_INIT() { pthread_key_create(&(thread_locals_key), NULL); // TODO: add destructor + NAPI_EXPORT_SIZEOF(fuse_thread_t) + NAPI_EXPORT_FUNCTION(fuse_native_mount) NAPI_EXPORT_FUNCTION(fuse_native_unmount) - NAPI_EXPORT_FUNCTION(fuse_native_signal_path) - NAPI_EXPORT_FUNCTION(fuse_native_signal_stat) + + NAPI_EXPORT_FUNCTION(fuse_native_signal_getattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_init) + NAPI_EXPORT_FUNCTION(fuse_native_signal_error) + NAPI_EXPORT_FUNCTION(fuse_native_signal_access) NAPI_EXPORT_FUNCTION(fuse_native_signal_statfs) - NAPI_EXPORT_FUNCTION(fuse_native_signal_buffer) + NAPI_EXPORT_FUNCTION(fuse_native_signal_fgetattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_getattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_flush) + NAPI_EXPORT_FUNCTION(fuse_native_signal_fsync) + NAPI_EXPORT_FUNCTION(fuse_native_signal_fsyncdir) NAPI_EXPORT_FUNCTION(fuse_native_signal_readdir) - NAPI_EXPORT_SIZEOF(fuse_thread_t) + NAPI_EXPORT_FUNCTION(fuse_native_signal_truncate) + NAPI_EXPORT_FUNCTION(fuse_native_signal_ftruncate) + NAPI_EXPORT_FUNCTION(fuse_native_signal_utimens) + NAPI_EXPORT_FUNCTION(fuse_native_signal_readlink) + NAPI_EXPORT_FUNCTION(fuse_native_signal_chown) + NAPI_EXPORT_FUNCTION(fuse_native_signal_chmod) + NAPI_EXPORT_FUNCTION(fuse_native_signal_mknod) + NAPI_EXPORT_FUNCTION(fuse_native_signal_setxattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_getxattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_listxattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_removexattr) + NAPI_EXPORT_FUNCTION(fuse_native_signal_open) + NAPI_EXPORT_FUNCTION(fuse_native_signal_opendir) + NAPI_EXPORT_FUNCTION(fuse_native_signal_read) + NAPI_EXPORT_FUNCTION(fuse_native_signal_write) + NAPI_EXPORT_FUNCTION(fuse_native_signal_release) + NAPI_EXPORT_FUNCTION(fuse_native_signal_releasedir) + NAPI_EXPORT_FUNCTION(fuse_native_signal_create) + NAPI_EXPORT_FUNCTION(fuse_native_signal_unlink) + NAPI_EXPORT_FUNCTION(fuse_native_signal_rename) + NAPI_EXPORT_FUNCTION(fuse_native_signal_link) + NAPI_EXPORT_FUNCTION(fuse_native_signal_symlink) + NAPI_EXPORT_FUNCTION(fuse_native_signal_mkdir) + NAPI_EXPORT_FUNCTION(fuse_native_signal_rmdir) + NAPI_EXPORT_FUNCTION(fuse_native_signal_destroy) + NAPI_EXPORT_UINT32(op_getattr) NAPI_EXPORT_UINT32(op_init) NAPI_EXPORT_UINT32(op_error) diff --git a/index.js b/index.js index 2896f8d..0924855 100644 --- a/index.js +++ b/index.js @@ -8,42 +8,116 @@ const OSX_FOLDER_ICON = '/System/Library/CoreServices/CoreTypes.bundle/Contents/ const HAS_FOLDER_ICON = IS_OSX && fs.existsSync(OSX_FOLDER_ICON) const binding = require('node-gyp-build')(__dirname) -const Opcodes = new Map([ - [ 'init', 0 ], - [ 'error', 1 ], - [ 'access', 2 ], - [ 'statfs', 3 ], - [ 'fgetattr', 4 ], - [ 'getattr', 5 ], - [ 'flush', 6 ], - [ 'fsync', 7 ], - [ 'fsyncdir', 8 ], - [ 'readdir', 9 ], - [ 'truncate', 10 ], - [ 'ftruncate', 11 ], - [ 'utimens', 12 ], - [ 'readlink', 13 ], - [ 'chown', 14 ], - [ 'chmod', 15 ], - [ 'mknod', 16 ], - [ 'setxattr', 17 ], - [ 'getxattr', 18 ], - [ 'listxattr', 19 ], - [ 'removexattr', 20 ], - [ 'open', 21 ], - [ 'opendir', 22 ], - [ 'read', 23 ], - [ 'write', 24 ], - [ 'release', 25 ], - [ 'releasedir', 26 ], - [ 'create', 27 ], - [ 'unlink', 28 ], - [ 'rename', 29 ], - [ 'link', 30 ], - [ 'symlink', 31 ], - [ 'mkdir', 32 ], - [ 'rmdir', 33 ], - [ 'destroy', 34 ] +const OpcodesAndDefaults = new Map([ + [ 'init', { + op: 0 + } ], + [ 'error', { + op: 1 + } ], + [ 'access', { + op: 2, + defaults: [ 0 ] + } ], + [ 'statfs', { + op: 3, + defaults: [ getStatfsArray() ] + } ], + [ 'fgetattr', { + op: 4, + defaults: [ getStatArray() ] + } ], + [ 'getattr', { + op: 5, + defaults: [ getStatArray() ] + } ], + [ 'flush', { + op: 6, + } ], + [ 'fsync', { + op: 7 + } ], + [ 'fsyncdir', { + op: 8 + } ], + [ 'readdir', { + op: 9 + } ], + [ 'truncate', { + op: 10 + } ], + [ 'ftruncate', { + op: 11 + } ], + [ 'utimens', { + op: 12 + } ], + [ 'readlink', { + op: 13 + } ], + [ 'chown', { + op: 14 + } ], + [ 'chmod', { + op: 15 + } ], + [ 'mknod', { + op: 16 + } ], + [ 'setxattr', { + op: 17 + } ], + [ 'getxattr', { + op: 18 + } ], + [ 'listxattr', { + op: 19 + } ], + [ 'removexattr', { + op: 20 + } ], + [ 'open', { + op: 21 + } ], + [ 'opendir', { + op: 22 + } ], + [ 'read', { + op: 23 + } ], + [ 'write', { + op: 24 + } ], + [ 'release', { + op: 25 + } ], + [ 'releasedir', { + op: 26 + } ], + [ 'create', { + op: 27 + } ], + [ 'unlink', { + op: 28 + } ], + [ 'rename', { + op: 29 + } ], + [ 'link', { + op: 30 + } ], + [ 'symlink', { + op: 31 + } ], + [ 'mkdir', { + op: 32 + } ], + [ 'rmdir', { + op: 33 + } ], + [ 'destroy', { + op: 34 + } ] ]) class Fuse { @@ -53,10 +127,11 @@ class Fuse { this.ops = ops this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t) + this._handlers = this._makeHandlerArray() // Keep the process alive while fuse is mounted. this._timer = null - const implemented = ['init', 'error', 'getattr'] + const implemented = [0, 1, 5] if (ops) { for (const [name, code] of Opcodes) { if (ops[name]) implemented.push(code) @@ -68,39 +143,6 @@ class Fuse { this._sync = true } - _withDefaultOps (cb) { - const withDefaults = { ...this.ops } - - const callback = function (err) { - callback = noop - setImmediate(cb.bind(null, err)) - } - - var init = this.ops.init || call - withDefaults.init = function (next) { - console.log('IN INIT') - callback() - if (init.length > 1) init(this.mnt, next) // backwards compat for now - else init(next) - } - - var error = this.ops.error || call - withDefaults.error = function (next) { - console.log('IN ERROR') - callback(new Error('Mount failed')) - error(next) - } - - if (!this.ops.getattr) { // we need this for unmount to work on osx - withDefaults.getattr = function (path, cb) { - if (path !== '/') return cb(Fuse.EPERM) - cb(null, { mtime: new Date(0), atime: new Date(0), ctime: new Date(0), mode: 16877, size: 4096 }) - } - } - - return withDefaults - } - _fuseOptions () { const options = [] @@ -144,72 +186,117 @@ class Fuse { process.nextTick(() => signalFunc.apply(null, args)) } - mount (cb) { - this.ops = this._withDefaultOps(this.ops, cb) - const opts = this._fuseOptions() + // Handlers - fs.stat(this.mnt, (err, stat) => { - if (err) return cb(new Error('Mountpoint does not exist')) - if (!stat.isDirectory()) return cb(new Error('Mountpoint is not a directory')) - fs.stat(path.join(this.mnt, '..'), (_, parent) => { - if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) - try { - // TODO: asyncify - binding.fuse_native_mount(this.mnt, opts, this._thread, this, - this.on_path_op, this.on_stat_op, this.on_fd_op, this.on_xattr_op, - this.on_statfs, this.on_readdir, this.on_symlink) - } catch (err) { - return cb(err) - } - this._timer = setInterval(() => {}, 10000) - return cb(null) - }) + _makeHandlerArray () { + const handlers = new Array(OpcodesAndDefaults.size) + for (const [name, { op, defaults }] of OpcodesAndDefaults) { + const nativeSignal = binding[`fuse_native_signal_${name}`] + if (!nativeSignal) continue + + handlers[op] = makeHandler(name, op, defaults, nativeSignal) + } + + return handlers + + function makeHandler (name, op, defaults, nativeSignal) { + return () => { + const boundSignal = signal.bind(arguments[0]) + const funcName = `_$name` + if (!this[funcName] || !this._implemented.has(op)) return boundSignal(-1, defaults) + this[funcName].apply(null, [boundSignal, [...arguments].slice(1) ]) + } + + function signal (nativeHandler, err, args) { + const args = [nativeHandler, err] + if (defaults) args.concat(defaults) + return nativeSignal(args) + } + } + } + + _init (signal) { + if (!this.ops.init) return signal(0) + this.ops.init(err => { + return signal(err) }) } - unmount (cb) { - // TODO: asyncify - try { - binding.fuse_native_unmount(this.mnt, this._thread) - } catch (err) { - clearInterval(this._timer) - return process.nextTick(cb, err) + _error (signal) { + if (!this.ops.error) return signal(0) + this.ops.error(err => { + return signal(err) + }) + } + + _getattr (signal, path) { + if (!this.ops.getattr) { + if (path !== '/') return signal(Fuse.EPERM) + return signal(0, getStatArray({ mtime: new Date(0), atime: new Date(0), ctime: new Date(0), mode: 16877, size: 4096 })) } - clearInterval(this._timer) - return process.nextTick(cb, null) + this.ops.getattr(path, (err, stat) => { + if (err) return signal(err) + return signal(0, getStatArray(stat)) + }) } - errno (code) { - return (code && Fuse[code.toUpperCase()]) || -1 + _fgetattr (signal, path, fd) { + } - on_symlink (handle, op, path, target) { - const signalFunc = binding.fuse_native_signal_path.bind(binding) - if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) + _setxattr (signal, path, name, value, size, position, flags) { + + } + + _getxattr (signal, path, name, value, size, position) { + + } + + _listxattr (signal, path, list, size) { + } - on_readdir (handle, op, path) { - const signalFunc = binding.fuse_native_signal_readdir.bind(binding) + _open (signal, path) { - if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) + } + + _create (signal, path, mode) { + + } + + _read (signal, path, fd, buf, len, offset) { + + } + + _write (signal, path, fd, buf, len, offset) { + + } + + _release (signal, path, fd) { + + } + + _releasedir (signal, path, fd) { + + } + _readdir (signal, path) { this.ops.readdir(path, (err, names, stats) => { + if (err) return signal(err) if (stats) stats = stats.map(getStatArray) - return this._signal(signalFunc, [handle, err, names, stats || []]) + return signal(null, [names, stats || []]) }) } - on_statfs (handle, op) { - const signalFunc = binding.fuse_native_signal_statfs.bind(binding) - if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, ...getStatfsArray()]) - + _statfs (signal) { this.ops.statfs((err, statfs) => { + if (err) return signal(err) const arr = getStatfsArray(statfs) - return this._signal(signalFunc, [handle, err, arr]) + return signal(null, [arr]) }) } - on_fd_op (handle, op, path, fd, buf, len, offset) { + _fd_op (handle, op, path, fd, buf, len, offset) { const signalFunc = binding.fuse_native_signal_buffer.bind(binding) if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) @@ -306,6 +393,48 @@ class Fuse { return this._signal(signalFunc, [handle, -1]) } } + + on_symlink (path, target) { + + } + + // Public API + + mount (cb) { + const opts = this._fuseOptions() + + fs.stat(this.mnt, (err, stat) => { + if (err) return cb(new Error('Mountpoint does not exist')) + if (!stat.isDirectory()) return cb(new Error('Mountpoint is not a directory')) + fs.stat(path.join(this.mnt, '..'), (_, parent) => { + if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) + try { + // TODO: asyncify + binding.fuse_native_mount(this.mnt, opts, this._thread, this, this._handlers) + } catch (err) { + return cb(err) + } + this._timer = setInterval(() => {}, 10000) + return cb(null) + }) + }) + } + + unmount (cb) { + // TODO: asyncify + try { + binding.fuse_native_unmount(this.mnt, this._thread) + } catch (err) { + clearInterval(this._timer) + return process.nextTick(cb, err) + } + clearInterval(this._timer) + return process.nextTick(cb, null) + } + + errno (code) { + return (code && Fuse[code.toUpperCase()]) || -1 + } } Fuse.EPERM = -1