From 2e5dd4298d063df177f7fe3803f6c4885e802e92 Mon Sep 17 00:00:00 2001 From: Andrew Osheroff Date: Tue, 30 Jul 2019 18:58:39 +0200 Subject: [PATCH] added utimens + release --- fuse-native.c | 456 ++++++++++++++++++++++++++++++++++++++------------ index.js | 122 +++++++++++--- 2 files changed, 452 insertions(+), 126 deletions(-) diff --git a/fuse-native.c b/fuse-native.c index 8728b6a..84996cd 100644 --- a/fuse-native.c +++ b/fuse-native.c @@ -13,6 +13,7 @@ #include #include + #include #include #include @@ -28,6 +29,15 @@ blk \ napi_close_handle_scope(env, scope); +#define FUSE_NATIVE_HANDLER(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(); \ + blk \ + uv_async_send(&(l->async)); \ + fuse_native_semaphore_wait(&(l->sem)); \ + return l->res; + static const uint32_t op_init = 0; static const uint32_t op_error = 1; static const uint32_t op_access = 2; @@ -74,6 +84,7 @@ typedef struct { 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; @@ -88,8 +99,22 @@ typedef struct { // Payloads const char *path; + struct fuse_file_info *info; void *buf; + off_t offset; + size_t len; + mode_t mode; int32_t res; + uint32_t atim[2]; + uint32_t mtim[2]; + + // Extended attributes + const char *name; + const char *value; + char *list; + size_t size; + uint32_t position; + int flags; // Stat + Statfs struct stat *stat; @@ -97,8 +122,6 @@ typedef struct { // Readdir fuse_fill_dir_t readdir_filler; - off_t readdir_offset; - struct fuse_file_info *readdir_info; // Internal bookkeeping fuse_thread_t *fuse; @@ -109,33 +132,110 @@ typedef struct { static pthread_key_t thread_locals_key; +// Helpers +// TODO: Extract into a separate file. + static void fin (napi_env env, void *fin_data, void* fin_hint) { printf("finaliser is run\n"); // exit(0); } +static void to_timespec (struct timespec* ts, uint32_t* int_ptr) { + long unsigned int ms = *int_ptr + (*(int_ptr + 1) * 4294967296); + ts->tv_sec = ms / 1000; + ts->tv_nsec = (ms % 1000) * 1000000; +} + +static void from_timespec(const struct timespec* ts, uint32_t* int_ptr) { + long unsigned int ms = (ts->tv_sec * 1000) + (ts->tv_nsec / 1000000); + *int_ptr = ms % 4294967296; + *(int_ptr + 1) = (ms - *int_ptr) / 4294967296; +} + +static void populate_stat (uint32_t *ints, struct stat* stat) { + stat->st_mode = *ints++; + stat->st_uid = *ints++; + stat->st_gid = *ints++; + stat->st_size = *ints++; + stat->st_dev = *ints++; + stat->st_nlink = *ints++; + stat->st_ino = *ints++; + stat->st_rdev = *ints++; + stat->st_blksize = *ints++; + stat->st_blocks = *ints++; + to_timespec(&stat->st_atim, ints); + to_timespec(&stat->st_mtim, ints + 2); + to_timespec(&stat->st_ctim, ints + 4); +} + +static void populate_statvfs (uint32_t *ints, struct statvfs* statvfs) { + statvfs->f_bsize = *ints++; + statvfs->f_frsize = *ints++; + statvfs->f_blocks = *ints++; + statvfs->f_bfree = *ints++; + statvfs->f_bavail = *ints++; + statvfs->f_files = *ints++; + statvfs->f_ffree = *ints++; + statvfs->f_favail = *ints++; + statvfs->f_fsid = *ints++; + statvfs->f_flag = *ints++; + 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]; + + 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) + }) +} 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[3]; + napi_value argv[4]; 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])); + 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, 3, argv, NULL) + NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 4, argv, NULL) }) } 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[3]; + 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->mode, &(argv[3])); + + if (l->info != NULL) { + napi_create_uint32(env, l->info->fh, &(argv[4])); + } else { + napi_create_uint32(env, 0, &(argv[4])); + } + + 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_MAKE_CALLBACK(env, NULL, ctx, callback, 3, argv, NULL) + NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 7, argv, NULL) }) } @@ -153,25 +253,65 @@ static void fuse_native_dispatch_readdir(uv_async_t* handle, int status, fuse_th 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[3]; + 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); } } @@ -212,108 +352,206 @@ static void* start_fuse_thread (void *data) { return NULL; } -static int fuse_native_getattr (const char *path, struct stat *stat) { - struct fuse_context *ctx = fuse_get_context(); - fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; +// Handlers - fuse_thread_locals_t *l = get_thread_locals(); +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->mode = mode; + l->info = info; + l->op = op_create; + }) +} - l->fuse = ft; - l->stat = stat; - l->op = op_getattr; - l->path = path; +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; + }) +} - uv_async_send(&(l->async)); - fuse_native_semaphore_wait(&(l->sem)); +static int fuse_native_open(const char *path, struct fuse_file_info *info) { + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->path = path; + l->info = info; + l->op = op_open; + }) +} - return l->res; +static int fuse_native_release (const char *path, struct fuse_file_info *info) { + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->path = path; + l->info = info; + l->op = op_release; + }) } -static int fuse_native_statfs (struct statvfs *statvfs) { - struct fuse_context *ctx = fuse_get_context(); - fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; +static int fuse_native_releasedir (const char *path, struct fuse_file_info *info) { + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->path = path; + l->info = info; + l->op = op_releasedir; + }) +} - fuse_thread_locals_t *l = get_thread_locals(); +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; + l->path = path; + l->buf = buf; + l->len = len; + l->offset = offset; + l->info = info; + l->op = op_write; + }) +} - l->fuse = ft; - l->statvfs = statvfs; - l->op = op_statfs; +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; + l->path = path; + l->buf = buf; + l->len = len; + l->offset = offset; + l->info = info; + l->op = op_read; + }) +} - uv_async_send(&(l->async)); - fuse_native_semaphore_wait(&(l->sem)); +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; + }) +} - return l->res; +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) { - struct fuse_context *ctx = fuse_get_context(); - fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->buf = buf; + l->path = path; + l->offset = offset; + l->info = info; + l->readdir_filler = filler; + l->op = op_readdir; + }) +} - fuse_thread_locals_t *l = get_thread_locals(); +#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; + l->path = path; + l->name = name; + l->value = value; + l->size = size; + l->flags = flags; + l->position = position; + l->op = op_setxattr; + }) +} + +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; + l->path = path; + l->name = name; + l->value = value; + l->size = size; + l->position = position; + l->op = op_getxattr; + }) +} +#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; + l->path = path; + l->name = name; + l->value = value; + l->size = size; + l->flags = flags; + l->position = position; + l->op = op_setxattr; + }) +} - l->fuse = ft; - l->buf = buf; - l->path = path; - l->readdir_filler = filler; - l->readdir_offset = offset; - l->readdir_info = info; - l->op = op_readdir; +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; + l->path = path; + l->name = name; + l->value = value; + l->size = size; + l->position = position; + l->op = op_getxattr; + }) +} +#endif + +static int fuse_native_listxattr (const char *path, char *list, size_t size) { + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->path = path; + l->list = list; + l->size = size; + l->op = op_listxattr; + }) +} - uv_async_send(&(l->async)); - printf("before semaphore wait\n"); - fuse_native_semaphore_wait(&(l->sem)); - printf("after semaphore wait\n"); +static int fuse_native_removexattr (const char *path, const char *name) { + FUSE_NATIVE_HANDLER({ + l->fuse = ft; + l->path = path; + l->name = name; + l->op = op_removexattr; + }) +} - return l->res; +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_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) l->res = res; + if (fd != 0) { + l->info->fh = fd; + } fuse_native_semaphore_signal(&(l->sem)); return NULL; } -static void to_timespec (struct timespec* ts, uint32_t* int_ptr) { - long unsigned int ms = *int_ptr + (*(int_ptr + 1) * 4294967296); - ts->tv_sec = ms / 1000; - ts->tv_nsec = (ms % 1000) * 1000000; -} - -static void populate_stat (uint32_t *ints, struct stat* stat) { - stat->st_mode = *ints++; - stat->st_uid = *ints++; - stat->st_gid = *ints++; - stat->st_size = *ints++; - stat->st_dev = *ints++; - stat->st_nlink = *ints++; - stat->st_ino = *ints++; - stat->st_rdev = *ints++; - stat->st_blksize = *ints++; - stat->st_blocks = *ints++; - to_timespec(&stat->st_atim, ints); - to_timespec(&stat->st_mtim, ints + 2); - to_timespec(&stat->st_ctim, ints + 4); -} - -static void populate_statvfs (uint32_t *ints, struct statvfs* statvfs) { - statvfs->f_bsize = *ints++; - statvfs->f_frsize = *ints++; - statvfs->f_blocks = *ints++; - statvfs->f_bfree = *ints++; - statvfs->f_bavail = *ints++; - statvfs->f_files = *ints++; - statvfs->f_ffree = *ints++; - statvfs->f_favail = *ints++; - statvfs->f_fsid = *ints++; - statvfs->f_flag = *ints++; - statvfs->f_namemax = *ints++; -} - NAPI_METHOD(fuse_native_signal_stat) { NAPI_ARGV(4) NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); @@ -327,24 +565,27 @@ NAPI_METHOD(fuse_native_signal_stat) { return NULL; } -NAPI_METHOD(fuse_native_signal_statfs) { - NAPI_ARGV(3) +NAPI_METHOD(fuse_native_signal_buffer) { + NAPI_ARGV(2) NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); NAPI_ARGV_INT32(res, 1) - NAPI_ARGV_BUFFER_CAST(uint32_t*, ints, 2) - populate_statvfs(ints, l->statvfs); l->res = res; fuse_native_semaphore_signal(&(l->sem)); return NULL; } -NAPI_METHOD(fuse_native_signal_buffer) { - NAPI_ARGV(2) +NAPI_METHOD(fuse_native_signal_xattr) { +} + +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) + populate_statvfs(ints, l->statvfs); l->res = res; fuse_native_semaphore_signal(&(l->sem)); @@ -352,7 +593,6 @@ NAPI_METHOD(fuse_native_signal_buffer) { } NAPI_METHOD(fuse_native_signal_readdir) { - printf("In signal readdir\n"); NAPI_ARGV(4) NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); NAPI_ARGV_INT32(res, 1) @@ -405,45 +645,45 @@ NAPI_METHOD(fuse_native_mount) { 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_statfs)); - napi_create_reference(env, argv[6], 1, &(ft->on_stat_op)); - napi_create_reference(env, argv[7], 1, &(ft->on_buffer_op)); - napi_create_reference(env, argv[8], 1, &(ft->on_readdir)); - napi_create_reference(env, argv[9], 1, &(ft->on_symlink)); + 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)); ft->env = env; struct fuse_operations ops = { - .getattr = fuse_native_getattr, + .getattr = fuse_native_fgetattr, + .fgetattr = fuse_native_fgetattr, .statfs = fuse_native_statfs, - .readdir = fuse_native_readdir + .readdir = fuse_native_readdir, + .open = fuse_native_open, + .create = fuse_native_create, + .read = fuse_native_read, + .write = fuse_native_write, + .release = fuse_native_release, + .releasedir = fuse_native_releasedir, + .access = fuse_native_access, + .setxattr = fuse_native_setxattr, + .getxattr = fuse_native_getxattr, + .listxattr = fuse_native_listxattr, + .removexattr = fuse_native_removexattr, + .utimens = fuse_native_utimens, /* .init = fuse_native_init, .error = fuse_native_error, - .access = fuse_native_access, - .fgetattr = fuse_native_fgetattr, .flush = fuse_native_flush, .fsync = fuse_native_fsync, .fsyncdir = fuse_native_fsyncdir, - .readdir = fuse_native_readdir, .truncate = fuse_native_truncate, .ftruncate = fuse_native_ftruncate, - .utimens = fuse_native_utimens, .readlink = fuse_native_readlink, .chown = fuse_native_chown, .chmod = fuse_native_chmod, .mknod = fuse_native_mknod, - .setxattr = fuse_native_setxattr, - .getxattr = fuse_native_getxattr, - .listxattr = fuse_native_listxattr, - .removexattr = fuse_native_removexattr, - .open = fuse_native_open, .opendir = fuse_native_opendir, - .read = fuse_native_read, - .write = fuse_native_write, - .release = fuse_native_release, - .releasedir = fuse_native_releasedir, - .create = fuse_native_create, .unlink = fuse_native_unlink, .rename = fuse_native_rename, .link = fuse_native_link, @@ -530,3 +770,5 @@ NAPI_INIT() { NAPI_EXPORT_UINT32(op_rmdir) NAPI_EXPORT_UINT32(op_destroy) } + + diff --git a/index.js b/index.js index fe34d0b..72db5cf 100644 --- a/index.js +++ b/index.js @@ -68,8 +68,8 @@ class Fuse { mount () { binding.fuse_native_mount(this.mnt, '-odebug', this._thread, this, - this.on_path_op, this.on_statfs_op, this.on_stat_op, - this.on_buffer_op, this.on_readdir, this.on_symlink) + 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) } unmount () { @@ -82,24 +82,17 @@ class Fuse { } on_readdir (handle, op, path) { - console.log('IN ONREADDIR') const signalFunc = binding.fuse_native_signal_readdir.bind(binding) if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) this.ops.readdir(path, (err, names, stats) => { if (stats) stats = stats.map(getStatArray) - console.error('readdir err:', err, 'names:', names, 'stats:', stats) return this._signal(signalFunc, [handle, err, names, stats || []]) }) } - on_buffer_op (handle, op, path, buf) { - const signalFunc = binding.fuse_native_signal_buffer.bind(binding) - if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) - } - - on_statfs_op (handle, op, path) { + 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()]) @@ -109,27 +102,102 @@ class Fuse { }) } - on_stat_op (handle, op, path) { + on_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]) + + const cb = (bytesProcessed) => { + return this._signal(signalFunc, [handle, bytesProcessed || 0]) + } + + switch (op) { + case (binding.op_read): + this.ops.read(path, fd, buf, len, offset, cb) + break + case (binding.op_write): + this.ops.write(path, fd, buf, len, offset, cb) + break + case(binding.op_release): + this.ops.release(path, fd, cb) + break + case(binding.op_releasedir): + this.ops.releasedir(path, fd, cb) + break + default: + return this._signal(signalFunc, [handle, 0]) + } + } + + on_stat_op (handle, op, path, fd) { const signalFunc = binding.fuse_native_signal_stat.bind(binding) if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, getStatArray()]) + const cb = (err, stat) => { + const arr = getStatArray(stat) + return this._signal(signalFunc, [handle, err, arr]) + } + switch (op) { case (binding.op_getattr): - this.ops.getattr(path, (err, stat) => { - const arr = getStatArray(stat) - return this._signal(signalFunc, [handle, err, arr]) - }) + this.ops.getattr(path, cb) break - + case (binding.op_fgetattr): + this.ops.fgetattr(path, fd, cb) default: - return this._signal(signalFunc, [handle, -1, getStatArray()]) + return this._signal(signalFunc, [handle, -1, getStatArray()]) } } - on_path_op (handle, op, path) { + on_path_op (handle, op, path, mode, flags, atim, mtim) { const signalFunc = binding.fuse_native_signal_path.bind(binding) - if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1]) + if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, 0]) + + const cb = (err, fd) => { + return this._signal(signalFunc, [handle, err, fd || 0]) + } + switch (op) { + case (binding.op_open): + this.ops.open(path, flags, cb) + break + case (binding.op_create): + this.ops.create(path, mode, cb) + break + case (binding.op_access): + this.ops.access(path, mode, cb) + break + case (binding.op_utimens): + this.ops.utimens(path, getDoubleInt(atim, 0), getDoubleInt(mtim, 0), cb) + break + default: + return this._signal(signalFunc, [handle, -1, 0]) + } + } + + on_xattr_op (handle, op, path, name, value, list, size, flags, position) { + const signalFunc = binding.fuse_native_signal_xattr.bind(binding) + if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, 0]) + + const cb = err => { + return this._signal(signalFunc, [handle, -1]) + } + + switch (op) { + case (binding.op_setxattr): + this.ops.setxattr(path, name, value, size, position || 0, flags, cb) + break + case (binding.op_getxattr): + this.ops.getxattr(path, name, value, size, position || 0, cb) + break + case (binding.op_listxattr): + this.ops.listxattr(path, list, size, cb) + break + case (binding.op_removexattr): + this.ops.removexattr(path, name, cb) + break + default: + return this._signal(signalFunc, [handle, -1]) + } } } @@ -156,6 +224,13 @@ function setDoubleInt (arr, idx, num) { arr[idx + 1] = (num - arr[idx]) / 4294967296 } +function getDoubleInt(arr, idx) { + arr = new Uint32Array(arr) + var num = arr[idx + 1] * 4294967296 + num += arr[idx] + return num +} + function getStatArray (stat) { const ints = new Uint32Array(16) @@ -193,6 +268,15 @@ const f = new Fuse('mnt', { getattr: (path, cb) => { return cb(0, emptyStat()) }, + access: (path, mode, cb) => { + return cb(0, 0) + }, + setxattr: (path, name, buffer, length, offset, cb) => { + return cb(0) + }, + utimens: (path, atim, mtim, cb) => { + return cb(0) + }, readdir: (path, cb) => { if (path === '/') { return cb(0, ['a', 'b', 'c'], Array(3).fill('a').map(() => emptyStat()))