big macro refactor compiles

reimpl
Andrew Osheroff 5 years ago
parent 9121e8822c
commit bd8c036010

@ -13,7 +13,6 @@
#include <fuse_opt.h> #include <fuse_opt.h>
#include <fuse_lowlevel.h> #include <fuse_lowlevel.h>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <pthread.h> #include <pthread.h>
@ -29,15 +28,43 @@
blk \ blk \
napi_close_handle_scope(env, scope); napi_close_handle_scope(env, scope);
#define FUSE_NATIVE_HANDLER(blk) \ #define FUSE_NATIVE_HANDLER(name, blk) \
struct fuse_context *ctx = fuse_get_context(); \ struct fuse_context *ctx = fuse_get_context(); \
fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; \ fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; \
fuse_thread_locals_t *l = get_thread_locals(); \ fuse_thread_locals_t *l = get_thread_locals(); \
l->fuse = ft; \
l->op = op_##name; \
blk \ blk \
uv_async_send(&(l->async)); \ uv_async_send(&(l->async)); \
fuse_native_semaphore_wait(&(l->sem)); \ fuse_native_semaphore_wait(&(l->sem)); \
return l->res; 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_init = 0;
static const uint32_t op_error = 1; static const uint32_t op_error = 1;
static const uint32_t op_access = 2; 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_rmdir = 33;
static const uint32_t op_destroy = 34; static const uint32_t op_destroy = 34;
// Data structures
typedef struct { typedef struct {
napi_env env; napi_env env;
pthread_t thread; pthread_t thread;
@ -81,13 +110,7 @@ typedef struct {
napi_ref ctx; napi_ref ctx;
// Operation handlers // Operation handlers
napi_ref on_path_op; napi_ref handlers[34];
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;
struct fuse *fuse; struct fuse *fuse;
struct fuse_chan *ch; struct fuse_chan *ch;
@ -133,6 +156,7 @@ typedef struct {
} fuse_thread_locals_t; } fuse_thread_locals_t;
static pthread_key_t thread_locals_key; static pthread_key_t thread_locals_key;
static fuse_thread_locals_t* get_thread_locals ();
// Helpers // Helpers
// TODO: Extract into a separate file. // TODO: Extract into a separate file.
@ -184,456 +208,400 @@ static void populate_statvfs (uint32_t *ints, struct statvfs* statvfs) {
statvfs->f_namemax = *ints++; statvfs->f_namemax = *ints++;
} }
// Dispatchers // Methods
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];
napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); FUSE_METHOD(statfs, 0, 1, (struct statvfs *statvfs), {
napi_create_uint32(env, l->op, &(argv[1])); l->statvfs = statvfs;
},
NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 2, argv, NULL) {},
{
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_METHOD(getattr, 1, 1, (const char *path, struct stat *stat, struct fuse_file_info *info), {
FUSE_NATIVE_CALLBACK(ft->on_stat_op, { l->path = path;
napi_value argv[4]; 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])); FUSE_METHOD(fgetattr, 2, 1, (const char *path, struct stat *stat, struct fuse_file_info *info), {
napi_create_uint32(env, l->op, &(argv[1])); l->path = path;
l->stat = stat;
l->info = info;
},
{
napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2]));
if (l->info != NULL) { if (l->info != NULL) {
napi_create_uint32(env, l->info->fh, &(argv[3])); napi_create_uint32(env, l->info->fh, &(argv[3]));
} else { } else {
napi_create_uint32(env, 0, &(argv[3])); 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])); FUSE_METHOD(access, 2, 0, (const char *path, int mode), {
napi_create_uint32(env, l->op, &(argv[1])); l->path = path;
l->mode = mode;
},
{
napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2])); napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2]));
napi_create_uint32(env, l->mode, &(argv[3])); 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) { if (l->info != NULL) {
napi_create_uint32(env, l->info->fh, &(argv[4])); napi_create_uint32(env, l->info->fh, &(argv[2]));
} else { } 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_ARGV_INT32(fd, 2)
napi_create_external_arraybuffer(env, l->mtim, 2 * sizeof(uint32_t), &fin, NULL, &argv[6]); if (fd != 0) {
} else { l->info->fh = fd;
napi_create_external_arraybuffer(env, NULL, 0, &fin, NULL, &argv[5]);
napi_create_external_arraybuffer(env, NULL, 0, &fin, NULL, &argv[6]);
} }
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])); FUSE_METHOD(create, 2, 1, (const char *path, mode_t mode, struct fuse_file_info *info), {
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;
l->path = path; l->path = path;
l->mode = mode; l->mode = mode;
l->info = info; l->info = info;
l->op = op_create; },
}) {
} napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2]));
napi_create_uint32(env, l->mode, &(argv[3]));
static int fuse_native_access(const char *path, int mode) { },
FUSE_NATIVE_HANDLER({ {
l->fuse = ft; NAPI_ARGV_INT32(fd, 2)
l->path = path; if (fd != 0) {
l->mode = mode; l->info->fh = fd;
l->op = op_access; }
}) })
}
static int fuse_native_open(const char *path, struct fuse_file_info *info) { FUSE_METHOD(utimens, 2, 0, (const char *path, const struct timespec tv[2]), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->info = info; from_timespec(&tv[0], l->atim);
l->op = op_open; from_timespec(&tv[1], l->mtim);
}) },
} {
napi_create_external_arraybuffer(env, l->atim, 2 * sizeof(uint32_t), &fin, NULL, &argv[2]);
static int fuse_native_release (const char *path, struct fuse_file_info *info) { napi_create_external_arraybuffer(env, l->mtim, 2 * sizeof(uint32_t), &fin, NULL, &argv[3]);
FUSE_NATIVE_HANDLER({ },
l->fuse = ft; {})
FUSE_METHOD(release, 2, 0, (const char *path, struct fuse_file_info *info), {
l->path = path; l->path = path;
l->info = info; 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_METHOD(releasedir, 2, 0, (const char *path, struct fuse_file_info *info), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->info = info; 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_METHOD(read, 5, 1, (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->buf = buf; l->buf = buf;
l->len = len; l->len = len;
l->offset = offset; l->offset = offset;
l->info = info; 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_METHOD(write, 5, 1, (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->buf = buf; l->buf = buf;
l->len = len; l->len = len;
l->offset = offset; l->offset = offset;
l->info = info; l->info = info;
l->op = op_read; },
}) {
} napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2]));
napi_create_uint32(env, l->info->fh, &(argv[3]));
static int fuse_native_fgetattr (const char *path, struct stat *stat, struct fuse_file_info *info) { napi_create_external_buffer(env, l->len, l->buf, &fin, NULL, &(argv[4]));
FUSE_NATIVE_HANDLER({ napi_create_uint32(env, l->len, &(argv[5]));
l->fuse = ft; napi_create_uint32(env, l->offset, &(argv[6]));
l->path = path; },
l->stat = stat; {
l->info = info; // TODO: handle bytes processed?
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;
}) })
}
static int fuse_native_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { FUSE_METHOD(readdir, 1, 2, (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->buf = buf; l->buf = buf;
l->path = path; l->path = path;
l->offset = offset; l->offset = offset;
l->info = info; l->info = info;
l->readdir_filler = filler; 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__ #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({ FUSE_METHOD(setxattr, 6, 0, (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position), {
l->fuse = ft;
l->path = path; l->path = path;
l->name = name; l->name = name;
l->value = value; l->value = value;
l->size = size; l->size = size;
l->flags = flags; l->flags = flags;
l->position = position; 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_METHOD(getxattr, 5, 0, (const char *path, const char *name, const char *value, size_t size, uint32_t position), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->name = name; l->name = name;
l->value = value; l->value = value;
l->size = size; l->size = size;
l->position = position; 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 #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({ FUSE_METHOD(setxattr, 5, 0, (const char *path, const char *name, const char *value, size_t size, int flags), {
l->fuse = ft;
l->path = path; l->path = path;
l->name = name; l->name = name;
l->value = value; l->value = value;
l->size = size; l->size = size;
l->flags = flags; 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_METHOD(getxattr, 4, 0, (const char *path, const char *name, const char *value, size_t size), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->name = name; l->name = name;
l->value = value; l->value = value;
l->size = size; 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 #endif
static int fuse_native_listxattr (const char *path, char *list, size_t size) { FUSE_METHOD(listxattr, 3, 0, (const char *path, char *list, size_t size), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->list = list; l->list = list;
l->size = size; 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_METHOD(removexattr, 2, 0, (const char *path, const char *name), {
FUSE_NATIVE_HANDLER({
l->fuse = ft;
l->path = path; l->path = path;
l->name = name; l->name = name;
l->op = op_removexattr; },
}) {
} napi_create_string_utf8(env, l->path, NAPI_AUTO_LENGTH, &(argv[2]));
napi_create_string_utf8(env, l->name, NAPI_AUTO_LENGTH, &(argv[3]));
static int fuse_native_utimens (const char *path, const struct timespec tv[2]) { },
FUSE_NATIVE_HANDLER({ {})
l->fuse = ft;
l->path = path; FUSE_METHOD(init, 0, 0, (struct fuse_conn_info *conn, struct fuse_config *cfg), {}, {}, {})
from_timespec(&tv[0], l->atim);
from_timespec(&tv[1], l->mtim); FUSE_METHOD(error, 0, 0, (), {}, {}, {})
l->op = op_utimens; FUSE_METHOD(flush, 0, 0, (), {}, {}, {})
}) FUSE_METHOD(fsync, 0, 0, (), {}, {}, {})
} FUSE_METHOD(fsyncdir, 0, 0, (), {}, {}, {})
FUSE_METHOD(truncate, 0, 0, (), {}, {}, {})
// Signallers 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) { static void fuse_native_dispatch (uv_async_t* handle, int status) {
NAPI_ARGV(3) fuse_thread_locals_t *l = (fuse_thread_locals_t *) handle->data;
NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); fuse_thread_t *ft = l->fuse;
NAPI_ARGV_INT32(res, 1)
NAPI_ARGV_INT32(fd, 2)
l->res = res; // TODO: Either use a function pointer (like ft->handlers[op]) or generate with a macro.
if (fd != 0) { switch (l->op) {
l->info->fh = fd; 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) { static fuse_thread_locals_t* get_thread_locals () {
NAPI_ARGV(4) void *data = pthread_getspecific(thread_locals_key);
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;
}
NAPI_METHOD(fuse_native_signal_buffer) { if (data != NULL) {
NAPI_ARGV(2) return (fuse_thread_locals_t *) data;
NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); }
NAPI_ARGV_INT32(res, 1)
l->res = res; fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t));
fuse_native_semaphore_signal(&(l->sem));
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) { if (err < 0) {
NAPI_ARGV(3) printf("uv_async failed: %i\n", err);
NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); return NULL;
NAPI_ARGV_INT32(res, 1) }
NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2)
populate_statvfs(ints, l->statvfs); fuse_native_semaphore_init(&(l->sem));
l->res = res; pthread_setspecific(thread_locals_key, (void *) l);
fuse_native_semaphore_signal(&(l->sem));
return NULL; return l;
} }
NAPI_METHOD(fuse_native_signal_readdir) { static void* start_fuse_thread (void *data) {
NAPI_ARGV(4) fuse_thread_t *ft = (fuse_thread_t *) data;
NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); fuse_loop_mt(ft->fuse);
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;
}
}
}
l->res = res; // printf("her nu\n");
fuse_native_semaphore_signal(&(l->sem)); // fuse_unmount(mnt, ch);
// fuse_session_remove_chan(ch);
// fuse_destroy(fuse);
return NULL; return NULL;
} }
@ -646,18 +614,17 @@ NAPI_METHOD(fuse_native_mount) {
NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 2); NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 2);
napi_create_reference(env, argv[3], 1, &(ft->ctx)); napi_create_reference(env, argv[3], 1, &(ft->ctx));
napi_create_reference(env, argv[4], 1, &(ft->on_path_op)); napi_ref handlers;
napi_create_reference(env, argv[5], 1, &(ft->on_stat_op)); napi_create_reference(env, argv[4], 1, &handlers);
napi_create_reference(env, argv[6], 1, &(ft->on_buffer_op));
napi_create_reference(env, argv[7], 1, &(ft->on_xattr_op)); NAPI_FOR_EACH(handlers, handler) {
napi_create_reference(env, argv[8], 1, &(ft->on_statfs)); napi_create_reference(env, handler, 1, &ft->handlers[i]);
napi_create_reference(env, argv[9], 1, &(ft->on_readdir)); }
napi_create_reference(env, argv[10], 1, &(ft->on_symlink));
ft->env = env; ft->env = env;
struct fuse_operations ops = { struct fuse_operations ops = {
.getattr = fuse_native_fgetattr, .getattr = fuse_native_getattr,
.fgetattr = fuse_native_fgetattr, .fgetattr = fuse_native_fgetattr,
.statfs = fuse_native_statfs, .statfs = fuse_native_statfs,
.readdir = fuse_native_readdir, .readdir = fuse_native_readdir,
@ -673,9 +640,7 @@ NAPI_METHOD(fuse_native_mount) {
.listxattr = fuse_native_listxattr, .listxattr = fuse_native_listxattr,
.removexattr = fuse_native_removexattr, .removexattr = fuse_native_removexattr,
.utimens = fuse_native_utimens, .utimens = fuse_native_utimens,
/*
.init = fuse_native_init, .init = fuse_native_init,
.error = fuse_native_error,
.flush = fuse_native_flush, .flush = fuse_native_flush,
.fsync = fuse_native_fsync, .fsync = fuse_native_fsync,
.fsyncdir = fuse_native_fsyncdir, .fsyncdir = fuse_native_fsyncdir,
@ -692,8 +657,7 @@ NAPI_METHOD(fuse_native_mount) {
.symlink = fuse_native_symlink, .symlink = fuse_native_symlink,
.mkdir = fuse_native_mkdir, .mkdir = fuse_native_mkdir,
.rmdir = fuse_native_rmdir, .rmdir = fuse_native_rmdir,
.destroy = fuse_native_destroy, .destroy = fuse_native_destroy
*/
}; };
int _argc = 2; int _argc = 2;
@ -746,14 +710,48 @@ NAPI_METHOD(fuse_native_unmount) {
NAPI_INIT() { NAPI_INIT() {
pthread_key_create(&(thread_locals_key), NULL); // TODO: add destructor 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_mount)
NAPI_EXPORT_FUNCTION(fuse_native_unmount) 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_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_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_getattr)
NAPI_EXPORT_UINT32(op_init) NAPI_EXPORT_UINT32(op_init)
NAPI_EXPORT_UINT32(op_error) NAPI_EXPORT_UINT32(op_error)

@ -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 HAS_FOLDER_ICON = IS_OSX && fs.existsSync(OSX_FOLDER_ICON)
const binding = require('node-gyp-build')(__dirname) const binding = require('node-gyp-build')(__dirname)
const Opcodes = new Map([ const OpcodesAndDefaults = new Map([
[ 'init', 0 ], [ 'init', {
[ 'error', 1 ], op: 0
[ 'access', 2 ], } ],
[ 'statfs', 3 ], [ 'error', {
[ 'fgetattr', 4 ], op: 1
[ 'getattr', 5 ], } ],
[ 'flush', 6 ], [ 'access', {
[ 'fsync', 7 ], op: 2,
[ 'fsyncdir', 8 ], defaults: [ 0 ]
[ 'readdir', 9 ], } ],
[ 'truncate', 10 ], [ 'statfs', {
[ 'ftruncate', 11 ], op: 3,
[ 'utimens', 12 ], defaults: [ getStatfsArray() ]
[ 'readlink', 13 ], } ],
[ 'chown', 14 ], [ 'fgetattr', {
[ 'chmod', 15 ], op: 4,
[ 'mknod', 16 ], defaults: [ getStatArray() ]
[ 'setxattr', 17 ], } ],
[ 'getxattr', 18 ], [ 'getattr', {
[ 'listxattr', 19 ], op: 5,
[ 'removexattr', 20 ], defaults: [ getStatArray() ]
[ 'open', 21 ], } ],
[ 'opendir', 22 ], [ 'flush', {
[ 'read', 23 ], op: 6,
[ 'write', 24 ], } ],
[ 'release', 25 ], [ 'fsync', {
[ 'releasedir', 26 ], op: 7
[ 'create', 27 ], } ],
[ 'unlink', 28 ], [ 'fsyncdir', {
[ 'rename', 29 ], op: 8
[ 'link', 30 ], } ],
[ 'symlink', 31 ], [ 'readdir', {
[ 'mkdir', 32 ], op: 9
[ 'rmdir', 33 ], } ],
[ 'destroy', 34 ] [ '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 { class Fuse {
@ -53,10 +127,11 @@ class Fuse {
this.ops = ops this.ops = ops
this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t) this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t)
this._handlers = this._makeHandlerArray()
// Keep the process alive while fuse is mounted. // Keep the process alive while fuse is mounted.
this._timer = null this._timer = null
const implemented = ['init', 'error', 'getattr'] const implemented = [0, 1, 5]
if (ops) { if (ops) {
for (const [name, code] of Opcodes) { for (const [name, code] of Opcodes) {
if (ops[name]) implemented.push(code) if (ops[name]) implemented.push(code)
@ -68,39 +143,6 @@ class Fuse {
this._sync = true 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 () { _fuseOptions () {
const options = [] const options = []
@ -144,72 +186,117 @@ class Fuse {
process.nextTick(() => signalFunc.apply(null, args)) process.nextTick(() => signalFunc.apply(null, args))
} }
mount (cb) { // Handlers
this.ops = this._withDefaultOps(this.ops, cb)
const opts = this._fuseOptions()
fs.stat(this.mnt, (err, stat) => { _makeHandlerArray () {
if (err) return cb(new Error('Mountpoint does not exist')) const handlers = new Array(OpcodesAndDefaults.size)
if (!stat.isDirectory()) return cb(new Error('Mountpoint is not a directory')) for (const [name, { op, defaults }] of OpcodesAndDefaults) {
fs.stat(path.join(this.mnt, '..'), (_, parent) => { const nativeSignal = binding[`fuse_native_signal_${name}`]
if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) if (!nativeSignal) continue
try {
// TODO: asyncify handlers[op] = makeHandler(name, op, defaults, nativeSignal)
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) return handlers
} catch (err) {
return cb(err) function makeHandler (name, op, defaults, nativeSignal) {
} return () => {
this._timer = setInterval(() => {}, 10000) const boundSignal = signal.bind(arguments[0])
return cb(null) 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) { _error (signal) {
// TODO: asyncify if (!this.ops.error) return signal(0)
try { this.ops.error(err => {
binding.fuse_native_unmount(this.mnt, this._thread) return signal(err)
} catch (err) { })
clearInterval(this._timer) }
return process.nextTick(cb, 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) this.ops.getattr(path, (err, stat) => {
return process.nextTick(cb, null) if (err) return signal(err)
return signal(0, getStatArray(stat))
})
} }
errno (code) { _fgetattr (signal, path, fd) {
return (code && Fuse[code.toUpperCase()]) || -1
} }
on_symlink (handle, op, path, target) { _setxattr (signal, path, name, value, size, position, flags) {
const signalFunc = binding.fuse_native_signal_path.bind(binding)
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) }
_getxattr (signal, path, name, value, size, position) {
}
_listxattr (signal, path, list, size) {
} }
on_readdir (handle, op, path) { _open (signal, path) {
const signalFunc = binding.fuse_native_signal_readdir.bind(binding)
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) => { this.ops.readdir(path, (err, names, stats) => {
if (err) return signal(err)
if (stats) stats = stats.map(getStatArray) if (stats) stats = stats.map(getStatArray)
return this._signal(signalFunc, [handle, err, names, stats || []]) return signal(null, [names, stats || []])
}) })
} }
on_statfs (handle, op) { _statfs (signal) {
const signalFunc = binding.fuse_native_signal_statfs.bind(binding)
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, ...getStatfsArray()])
this.ops.statfs((err, statfs) => { this.ops.statfs((err, statfs) => {
if (err) return signal(err)
const arr = getStatfsArray(statfs) 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) const signalFunc = binding.fuse_native_signal_buffer.bind(binding)
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
@ -306,6 +393,48 @@ class Fuse {
return this._signal(signalFunc, [handle, -1]) 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 Fuse.EPERM = -1

Loading…
Cancel
Save