2015-03-12 02:11:29 +00:00
|
|
|
#include <nan.h>
|
|
|
|
|
2015-03-17 14:35:42 +00:00
|
|
|
#define FUSE_USE_VERSION 29
|
2015-03-12 02:11:29 +00:00
|
|
|
|
|
|
|
#include <fuse.h>
|
2015-03-20 03:11:42 +00:00
|
|
|
#include <fuse_opt.h>
|
2015-08-06 17:24:38 +00:00
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
2015-03-17 14:37:30 +00:00
|
|
|
#include <sys/types.h>
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-08-06 16:33:20 +00:00
|
|
|
#include "abstractions.h"
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
using namespace v8;
|
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
#define LOCAL_STRING(s) Nan::New<String>(s).ToLocalChecked()
|
|
|
|
#define LOOKUP_CALLBACK(map, name) map->Has(LOCAL_STRING(name)) ? new Nan::Callback(map->Get(LOCAL_STRING(name)).As<Function>()) : NULL
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
enum bindings_ops_t {
|
|
|
|
OP_INIT = 0,
|
2015-03-17 12:32:09 +00:00
|
|
|
OP_ERROR,
|
2015-03-12 02:11:29 +00:00
|
|
|
OP_ACCESS,
|
|
|
|
OP_STATFS,
|
|
|
|
OP_FGETATTR,
|
|
|
|
OP_GETATTR,
|
|
|
|
OP_FLUSH,
|
|
|
|
OP_FSYNC,
|
|
|
|
OP_FSYNCDIR,
|
|
|
|
OP_READDIR,
|
|
|
|
OP_TRUNCATE,
|
|
|
|
OP_FTRUNCATE,
|
|
|
|
OP_UTIMENS,
|
|
|
|
OP_READLINK,
|
|
|
|
OP_CHOWN,
|
|
|
|
OP_CHMOD,
|
2015-05-16 18:32:57 +00:00
|
|
|
OP_MKNOD,
|
2015-03-12 02:11:29 +00:00
|
|
|
OP_SETXATTR,
|
|
|
|
OP_GETXATTR,
|
|
|
|
OP_OPEN,
|
|
|
|
OP_OPENDIR,
|
|
|
|
OP_READ,
|
|
|
|
OP_WRITE,
|
|
|
|
OP_RELEASE,
|
|
|
|
OP_RELEASEDIR,
|
|
|
|
OP_CREATE,
|
|
|
|
OP_UNLINK,
|
|
|
|
OP_RENAME,
|
|
|
|
OP_LINK,
|
|
|
|
OP_SYMLINK,
|
|
|
|
OP_MKDIR,
|
|
|
|
OP_RMDIR,
|
|
|
|
OP_DESTROY
|
|
|
|
};
|
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
static Nan::Persistent<Function> buffer_constructor;
|
|
|
|
static Nan::Callback *callback_constructor;
|
2015-03-12 02:11:29 +00:00
|
|
|
static struct stat empty_stat;
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
struct bindings_t {
|
|
|
|
int index;
|
2015-03-22 01:00:26 +00:00
|
|
|
int gc;
|
2015-03-20 11:52:47 +00:00
|
|
|
|
2015-05-05 00:22:05 +00:00
|
|
|
// fuse context
|
|
|
|
int context_uid;
|
|
|
|
int context_gid;
|
|
|
|
int context_pid;
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
// fuse data
|
|
|
|
char mnt[1024];
|
|
|
|
char mntopts[1024];
|
2015-08-07 01:51:38 +00:00
|
|
|
abstr_thread_t thread;
|
2015-08-06 16:33:20 +00:00
|
|
|
bindings_sem_t semaphore;
|
2015-03-12 02:11:29 +00:00
|
|
|
uv_async_t async;
|
|
|
|
|
|
|
|
// methods
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::Callback *ops_init;
|
|
|
|
Nan::Callback *ops_error;
|
|
|
|
Nan::Callback *ops_access;
|
|
|
|
Nan::Callback *ops_statfs;
|
|
|
|
Nan::Callback *ops_getattr;
|
|
|
|
Nan::Callback *ops_fgetattr;
|
|
|
|
Nan::Callback *ops_flush;
|
|
|
|
Nan::Callback *ops_fsync;
|
|
|
|
Nan::Callback *ops_fsyncdir;
|
|
|
|
Nan::Callback *ops_readdir;
|
|
|
|
Nan::Callback *ops_truncate;
|
|
|
|
Nan::Callback *ops_ftruncate;
|
|
|
|
Nan::Callback *ops_readlink;
|
|
|
|
Nan::Callback *ops_chown;
|
|
|
|
Nan::Callback *ops_chmod;
|
|
|
|
Nan::Callback *ops_mknod;
|
|
|
|
Nan::Callback *ops_setxattr;
|
|
|
|
Nan::Callback *ops_getxattr;
|
|
|
|
Nan::Callback *ops_open;
|
|
|
|
Nan::Callback *ops_opendir;
|
|
|
|
Nan::Callback *ops_read;
|
|
|
|
Nan::Callback *ops_write;
|
|
|
|
Nan::Callback *ops_release;
|
|
|
|
Nan::Callback *ops_releasedir;
|
|
|
|
Nan::Callback *ops_create;
|
|
|
|
Nan::Callback *ops_utimens;
|
|
|
|
Nan::Callback *ops_unlink;
|
|
|
|
Nan::Callback *ops_rename;
|
|
|
|
Nan::Callback *ops_link;
|
|
|
|
Nan::Callback *ops_symlink;
|
|
|
|
Nan::Callback *ops_mkdir;
|
|
|
|
Nan::Callback *ops_rmdir;
|
|
|
|
Nan::Callback *ops_destroy;
|
|
|
|
|
|
|
|
Nan::Callback *callback;
|
2015-03-21 15:05:35 +00:00
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
// method data
|
|
|
|
bindings_ops_t op;
|
|
|
|
fuse_fill_dir_t filler; // used in readdir
|
|
|
|
struct fuse_file_info *info;
|
|
|
|
char *path;
|
|
|
|
char *name;
|
2015-08-06 19:33:27 +00:00
|
|
|
FUSE_OFF_T offset;
|
|
|
|
FUSE_OFF_T length;
|
2015-03-12 02:11:29 +00:00
|
|
|
void *data; // various structs
|
|
|
|
int mode;
|
2015-05-16 18:32:57 +00:00
|
|
|
int dev;
|
2015-03-12 02:11:29 +00:00
|
|
|
int uid;
|
|
|
|
int gid;
|
|
|
|
int result;
|
2015-03-21 15:05:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bindings_t *bindings_mounted[1024];
|
|
|
|
static int bindings_mounted_count = 0;
|
2015-05-05 00:22:05 +00:00
|
|
|
static bindings_t *bindings_current = NULL;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
static bindings_t *bindings_find_mounted (char *path) {
|
2015-03-21 15:05:35 +00:00
|
|
|
for (int i = 0; i < bindings_mounted_count; i++) {
|
|
|
|
bindings_t *b = bindings_mounted[i];
|
2015-03-22 01:00:26 +00:00
|
|
|
if (b != NULL && !b->gc && !strcmp(b->mnt, path)) {
|
|
|
|
return b;
|
2015-03-21 15:05:35 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-22 01:00:26 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2015-03-20 03:11:42 +00:00
|
|
|
|
2015-03-22 11:34:05 +00:00
|
|
|
static void bindings_fusermount (char *path) {
|
2015-08-06 17:24:38 +00:00
|
|
|
fusermount(path);
|
2015-03-22 11:34:05 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
static void bindings_unmount (char *path) {
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_lock(&mutex);
|
2015-03-22 01:00:26 +00:00
|
|
|
bindings_t *b = bindings_find_mounted(path);
|
|
|
|
if (b != NULL) b->gc = 1;
|
2015-03-20 03:42:28 +00:00
|
|
|
bindings_fusermount(path);
|
2015-08-06 17:24:38 +00:00
|
|
|
if (b != NULL) thread_join(b->thread);
|
|
|
|
mutex_unlock(&mutex);
|
2015-03-20 03:11:42 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION && NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION)
|
2015-03-16 21:28:33 +00:00
|
|
|
NAN_INLINE v8::Local<v8::Object> bindings_buffer (char *data, size_t length) {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Object> buf = Nan::New(buffer_constructor)->NewInstance(0, NULL);
|
|
|
|
Local<String> k = LOCAL_STRING("length");
|
|
|
|
Local<Number> v = Nan::New<Number>(length);
|
|
|
|
buf->Set(k, v);
|
2015-03-16 21:28:33 +00:00
|
|
|
buf->SetIndexedPropertiesToExternalArrayData((char *) data, kExternalUnsignedByteArray, length);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void noop (char *data, void *hint) {}
|
|
|
|
NAN_INLINE v8::Local<v8::Object> bindings_buffer (char *data, size_t length) {
|
2015-09-22 13:58:58 +00:00
|
|
|
return Nan::NewBuffer(data, length, noop, NULL).ToLocalChecked();
|
2015-03-16 21:28:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_INLINE static int bindings_call (bindings_t *b) {
|
|
|
|
uv_async_send(&(b->async));
|
|
|
|
semaphore_wait(&(b->semaphore));
|
|
|
|
return b->result;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-05-05 00:22:05 +00:00
|
|
|
static bindings_t *bindings_get_context () {
|
|
|
|
fuse_context *ctx = fuse_get_context();
|
|
|
|
bindings_t *b = (bindings_t *) ctx->private_data;
|
|
|
|
b->context_pid = ctx->pid;
|
|
|
|
b->context_uid = ctx->uid;
|
|
|
|
b->context_gid = ctx->gid;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2015-05-16 18:32:57 +00:00
|
|
|
static int bindings_mknod (const char *path, mode_t mode, dev_t dev) {
|
|
|
|
bindings_t *b = bindings_get_context();
|
|
|
|
|
|
|
|
b->op = OP_MKNOD;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = mode;
|
|
|
|
b->dev = dev;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static int bindings_truncate (const char *path, FUSE_OFF_T size) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_TRUNCATE;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->length = size;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static int bindings_ftruncate (const char *path, FUSE_OFF_T size, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_FTRUNCATE;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->length = size;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_getattr (const char *path, struct stat *stat) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_GETATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = stat;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_fgetattr (const char *path, struct stat *stat, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_FGETATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = stat;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_flush (const char *path, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_FLUSH;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_fsync (const char *path, int datasync, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_FSYNC;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = datasync;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_fsyncdir (const char *path, int datasync, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_FSYNCDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = datasync;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static int bindings_readdir (const char *path, void *buf, fuse_fill_dir_t filler, FUSE_OFF_T offset, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_READDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = buf;
|
|
|
|
b->filler = filler;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_readlink (const char *path, char *buf, size_t len) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_READLINK;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) buf;
|
|
|
|
b->length = len;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_chown (const char *path, uid_t uid, gid_t gid) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_CHOWN;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->uid = uid;
|
|
|
|
b->gid = gid;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_chmod (const char *path, mode_t mode) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_CHMOD;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = mode;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
static int bindings_setxattr (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_SETXATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->name = (char *) name;
|
|
|
|
b->data = (void *) value;
|
|
|
|
b->length = size;
|
|
|
|
b->offset = position;
|
|
|
|
b->mode = flags;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_getxattr (const char *path, const char *name, char *value, size_t size, uint32_t position) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_GETXATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->name = (char *) name;
|
|
|
|
b->data = (void *) value;
|
|
|
|
b->length = size;
|
|
|
|
b->offset = position;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int bindings_setxattr (const char *path, const char *name, const char *value, size_t size, int flags) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_SETXATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->name = (char *) name;
|
|
|
|
b->data = (void *) value;
|
|
|
|
b->length = size;
|
|
|
|
b->offset = 0;
|
|
|
|
b->mode = flags;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
static int bindings_getxattr (const char *path, const char *name, char *value, size_t size) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_GETXATTR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->name = (char *) name;
|
|
|
|
b->data = (void *) value;
|
|
|
|
b->length = size;
|
|
|
|
b->offset = 0;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int bindings_statfs (const char *path, struct statvfs *statfs) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_STATFS;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = statfs;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_open (const char *path, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_OPEN;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = info->flags;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_opendir (const char *path, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_OPENDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = info->flags;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static int bindings_read (const char *path, char *buf, size_t len, FUSE_OFF_T offset, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_READ;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) buf;
|
|
|
|
b->offset = offset;
|
|
|
|
b->length = len;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static int bindings_write (const char *path, const char *buf, size_t len, FUSE_OFF_T offset, struct fuse_file_info * info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_WRITE;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) buf;
|
|
|
|
b->offset = offset;
|
|
|
|
b->length = len;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_release (const char *path, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_RELEASE;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_releasedir (const char *path, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_RELEASEDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_access (const char *path, int mode) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_ACCESS;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = mode;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_create (const char *path, mode_t mode, struct fuse_file_info *info) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_CREATE;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = mode;
|
|
|
|
b->info = info;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_utimens (const char *path, const struct timespec tv[2]) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_UTIMENS;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) tv;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_unlink (const char *path) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_UNLINK;
|
|
|
|
b->path = (char *) path;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_rename (const char *src, const char *dest) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_RENAME;
|
|
|
|
b->path = (char *) src;
|
|
|
|
b->data = (void *) dest;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_link (const char *path, const char *dest) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_LINK;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) dest;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_symlink (const char *path, const char *dest) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_SYMLINK;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->data = (void *) dest;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_mkdir (const char *path, mode_t mode) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_MKDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
b->mode = mode;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bindings_rmdir (const char *path) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_RMDIR;
|
|
|
|
b->path = (char *) path;
|
|
|
|
|
|
|
|
return bindings_call(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void* bindings_init (struct fuse_conn_info *conn) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_INIT;
|
|
|
|
|
|
|
|
bindings_call(b);
|
|
|
|
return b;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void bindings_destroy (void *data) {
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_get_context();
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
b->op = OP_DESTROY;
|
|
|
|
|
|
|
|
bindings_call(b);
|
|
|
|
}
|
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
static void bindings_free (bindings_t *b) {
|
2015-03-21 15:05:35 +00:00
|
|
|
if (b->ops_access != NULL) delete b->ops_access;
|
|
|
|
if (b->ops_truncate != NULL) delete b->ops_truncate;
|
|
|
|
if (b->ops_ftruncate != NULL) delete b->ops_ftruncate;
|
|
|
|
if (b->ops_getattr != NULL) delete b->ops_getattr;
|
|
|
|
if (b->ops_fgetattr != NULL) delete b->ops_fgetattr;
|
|
|
|
if (b->ops_flush != NULL) delete b->ops_flush;
|
|
|
|
if (b->ops_fsync != NULL) delete b->ops_fsync;
|
|
|
|
if (b->ops_fsyncdir != NULL) delete b->ops_fsyncdir;
|
|
|
|
if (b->ops_readdir != NULL) delete b->ops_readdir;
|
|
|
|
if (b->ops_readlink != NULL) delete b->ops_readlink;
|
|
|
|
if (b->ops_chown != NULL) delete b->ops_chown;
|
|
|
|
if (b->ops_chmod != NULL) delete b->ops_chmod;
|
2015-05-16 18:32:57 +00:00
|
|
|
if (b->ops_mknod != NULL) delete b->ops_mknod;
|
2015-03-21 15:05:35 +00:00
|
|
|
if (b->ops_setxattr != NULL) delete b->ops_setxattr;
|
|
|
|
if (b->ops_getxattr != NULL) delete b->ops_getxattr;
|
|
|
|
if (b->ops_statfs != NULL) delete b->ops_statfs;
|
|
|
|
if (b->ops_open != NULL) delete b->ops_open;
|
|
|
|
if (b->ops_opendir != NULL) delete b->ops_opendir;
|
|
|
|
if (b->ops_read != NULL) delete b->ops_read;
|
|
|
|
if (b->ops_write != NULL) delete b->ops_write;
|
|
|
|
if (b->ops_release != NULL) delete b->ops_release;
|
|
|
|
if (b->ops_releasedir != NULL) delete b->ops_releasedir;
|
|
|
|
if (b->ops_create != NULL) delete b->ops_create;
|
|
|
|
if (b->ops_utimens != NULL) delete b->ops_utimens;
|
|
|
|
if (b->ops_unlink != NULL) delete b->ops_unlink;
|
|
|
|
if (b->ops_rename != NULL) delete b->ops_rename;
|
|
|
|
if (b->ops_link != NULL) delete b->ops_link;
|
|
|
|
if (b->ops_symlink != NULL) delete b->ops_symlink;
|
|
|
|
if (b->ops_mkdir != NULL) delete b->ops_mkdir;
|
|
|
|
if (b->ops_rmdir != NULL) delete b->ops_rmdir;
|
|
|
|
if (b->ops_init != NULL) delete b->ops_init;
|
|
|
|
if (b->ops_destroy != NULL) delete b->ops_destroy;
|
|
|
|
if (b->callback != NULL) delete b->callback;
|
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
bindings_mounted[b->index] = NULL;
|
|
|
|
while (bindings_mounted_count > 0 && bindings_mounted[bindings_mounted_count - 1] == NULL) {
|
|
|
|
bindings_mounted_count--;
|
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
free(b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
static void bindings_on_close (uv_handle_t *handle) {
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_lock(&mutex);
|
2015-03-22 01:00:26 +00:00
|
|
|
bindings_free((bindings_t *) handle->data);
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_unlock(&mutex);
|
2015-03-22 01:00:26 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
static thread_fn_rtn_t bindings_thread (void *data) {
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_t *b = (bindings_t *) data;
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
struct fuse_operations ops = { };
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
if (b->ops_access != NULL) ops.access = bindings_access;
|
|
|
|
if (b->ops_truncate != NULL) ops.truncate = bindings_truncate;
|
|
|
|
if (b->ops_ftruncate != NULL) ops.ftruncate = bindings_ftruncate;
|
|
|
|
if (b->ops_getattr != NULL) ops.getattr = bindings_getattr;
|
|
|
|
if (b->ops_fgetattr != NULL) ops.fgetattr = bindings_fgetattr;
|
|
|
|
if (b->ops_flush != NULL) ops.flush = bindings_flush;
|
|
|
|
if (b->ops_fsync != NULL) ops.fsync = bindings_fsync;
|
|
|
|
if (b->ops_fsyncdir != NULL) ops.fsyncdir = bindings_fsyncdir;
|
|
|
|
if (b->ops_readdir != NULL) ops.readdir = bindings_readdir;
|
|
|
|
if (b->ops_readlink != NULL) ops.readlink = bindings_readlink;
|
|
|
|
if (b->ops_chown != NULL) ops.chown = bindings_chown;
|
|
|
|
if (b->ops_chmod != NULL) ops.chmod = bindings_chmod;
|
2015-05-16 18:32:57 +00:00
|
|
|
if (b->ops_mknod != NULL) ops.mknod = bindings_mknod;
|
2015-03-21 15:05:35 +00:00
|
|
|
if (b->ops_setxattr != NULL) ops.setxattr = bindings_setxattr;
|
|
|
|
if (b->ops_getxattr != NULL) ops.getxattr = bindings_getxattr;
|
|
|
|
if (b->ops_statfs != NULL) ops.statfs = bindings_statfs;
|
|
|
|
if (b->ops_open != NULL) ops.open = bindings_open;
|
|
|
|
if (b->ops_opendir != NULL) ops.opendir = bindings_opendir;
|
|
|
|
if (b->ops_read != NULL) ops.read = bindings_read;
|
|
|
|
if (b->ops_write != NULL) ops.write = bindings_write;
|
|
|
|
if (b->ops_release != NULL) ops.release = bindings_release;
|
|
|
|
if (b->ops_releasedir != NULL) ops.releasedir = bindings_releasedir;
|
|
|
|
if (b->ops_create != NULL) ops.create = bindings_create;
|
|
|
|
if (b->ops_utimens != NULL) ops.utimens = bindings_utimens;
|
|
|
|
if (b->ops_unlink != NULL) ops.unlink = bindings_unlink;
|
|
|
|
if (b->ops_rename != NULL) ops.rename = bindings_rename;
|
|
|
|
if (b->ops_link != NULL) ops.link = bindings_link;
|
|
|
|
if (b->ops_symlink != NULL) ops.symlink = bindings_symlink;
|
|
|
|
if (b->ops_mkdir != NULL) ops.mkdir = bindings_mkdir;
|
|
|
|
if (b->ops_rmdir != NULL) ops.rmdir = bindings_rmdir;
|
|
|
|
if (b->ops_init != NULL) ops.init = bindings_init;
|
|
|
|
if (b->ops_destroy != NULL) ops.destroy = bindings_destroy;
|
|
|
|
|
|
|
|
int argc = !strcmp(b->mntopts, "-o") ? 1 : 2;
|
2015-03-12 02:11:29 +00:00
|
|
|
char *argv[] = {
|
2015-03-17 14:41:31 +00:00
|
|
|
(char *) "fuse_bindings_dummy",
|
2015-03-21 15:05:35 +00:00
|
|
|
(char *) b->mntopts
|
2015-03-12 02:11:29 +00:00
|
|
|
};
|
|
|
|
|
2015-03-20 03:11:42 +00:00
|
|
|
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
2015-03-21 15:05:35 +00:00
|
|
|
struct fuse_chan *ch = fuse_mount(b->mnt, &args);
|
|
|
|
|
|
|
|
if (ch == NULL) {
|
|
|
|
b->op = OP_ERROR;
|
|
|
|
bindings_call(b);
|
|
|
|
uv_close((uv_handle_t*) &(b->async), &bindings_on_close);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-03-20 03:11:42 +00:00
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
struct fuse *fuse = fuse_new(ch, &args, &ops, sizeof(struct fuse_operations), b);
|
2015-03-20 03:11:42 +00:00
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
if (fuse == NULL) {
|
|
|
|
b->op = OP_ERROR;
|
|
|
|
bindings_call(b);
|
|
|
|
uv_close((uv_handle_t*) &(b->async), &bindings_on_close);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-03-20 03:11:42 +00:00
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
fuse_loop(fuse);
|
2015-03-20 03:11:42 +00:00
|
|
|
|
2015-03-22 01:00:26 +00:00
|
|
|
fuse_unmount(b->mnt, ch);
|
2015-03-21 15:05:35 +00:00
|
|
|
fuse_session_remove_chan(ch);
|
|
|
|
fuse_destroy(fuse);
|
|
|
|
|
|
|
|
uv_close((uv_handle_t*) &(b->async), &bindings_on_close);
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
return 0;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-08 20:56:37 +00:00
|
|
|
#ifndef _WIN32
|
2015-03-23 16:17:13 +00:00
|
|
|
NAN_INLINE static Local<Date> bindings_get_date (struct timespec *out) {
|
|
|
|
int ms = (out->tv_nsec / 1000);
|
2015-09-22 13:58:58 +00:00
|
|
|
return Nan::New<Date>(out->tv_sec * 1000 + ms).ToLocalChecked();
|
2015-03-23 16:17:13 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_INLINE static void bindings_set_date (struct timespec *out, Local<Date> date) {
|
2015-03-12 02:11:29 +00:00
|
|
|
double ms = date->NumberValue();
|
|
|
|
time_t secs = (time_t)(ms / 1000.0);
|
|
|
|
time_t rem = ms - (1000.0 * secs);
|
|
|
|
time_t ns = rem * 1000000.0;
|
|
|
|
out->tv_sec = secs;
|
|
|
|
out->tv_nsec = ns;
|
|
|
|
}
|
2015-08-08 20:56:37 +00:00
|
|
|
#else
|
2015-08-06 21:59:38 +00:00
|
|
|
NAN_INLINE static Local<Date> bindings_get_date (time_t *out) {
|
2015-09-22 13:58:58 +00:00
|
|
|
return Nan::New<Date>(*out * 1000.0);
|
2015-08-06 21:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NAN_INLINE static void bindings_set_date (time_t *out, Local<Date> date) {
|
|
|
|
double ms = date->NumberValue();
|
|
|
|
time_t secs = (time_t)(ms / 1000.0);
|
|
|
|
*out = secs;
|
|
|
|
}
|
2015-08-08 20:56:37 +00:00
|
|
|
#endif
|
2015-08-06 21:59:38 +00:00
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_INLINE static void bindings_set_stat (struct stat *stat, Local<Object> obj) {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("dev"))) stat->st_dev = obj->Get(LOCAL_STRING("dev"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("ino"))) stat->st_ino = obj->Get(LOCAL_STRING("ino"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("mode"))) stat->st_mode = obj->Get(LOCAL_STRING("mode"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("nlink"))) stat->st_nlink = obj->Get(LOCAL_STRING("nlink"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("uid"))) stat->st_uid = obj->Get(LOCAL_STRING("uid"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("gid"))) stat->st_gid = obj->Get(LOCAL_STRING("gid"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("rdev"))) stat->st_rdev = obj->Get(LOCAL_STRING("rdev"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("size"))) stat->st_size = obj->Get(LOCAL_STRING("size"))->NumberValue();
|
2015-08-06 19:33:27 +00:00
|
|
|
#ifndef _WIN32
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("blocks"))) stat->st_blocks = obj->Get(LOCAL_STRING("blocks"))->NumberValue();
|
|
|
|
if (obj->Has(LOCAL_STRING("blksize"))) stat->st_blksize = obj->Get(LOCAL_STRING("blksize"))->NumberValue();
|
2015-08-06 21:59:38 +00:00
|
|
|
#endif
|
2015-03-12 02:11:29 +00:00
|
|
|
#ifdef __APPLE__
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("mtime"))) bindings_set_date(&stat->st_mtimespec, obj->Get(LOCAL_STRING("mtime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("ctime"))) bindings_set_date(&stat->st_ctimespec, obj->Get(LOCAL_STRING("ctime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("atime"))) bindings_set_date(&stat->st_atimespec, obj->Get(LOCAL_STRING("atime")).As<Date>());
|
2015-08-06 21:59:38 +00:00
|
|
|
#elif defined(_WIN32)
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("mtime"))) bindings_set_date(&stat->st_mtime, obj->Get(LOCAL_STRING("mtime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("ctime"))) bindings_set_date(&stat->st_ctime, obj->Get(LOCAL_STRING("ctime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("atime"))) bindings_set_date(&stat->st_atime, obj->Get(LOCAL_STRING("atime")).As<Date>());
|
2015-03-12 02:11:29 +00:00
|
|
|
#else
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("mtime"))) bindings_set_date(&stat->st_mtim, obj->Get(LOCAL_STRING("mtime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("ctime"))) bindings_set_date(&stat->st_ctim, obj->Get(LOCAL_STRING("ctime")).As<Date>());
|
|
|
|
if (obj->Has(LOCAL_STRING("atime"))) bindings_set_date(&stat->st_atim, obj->Get(LOCAL_STRING("atime")).As<Date>());
|
2015-03-12 02:11:29 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_INLINE static void bindings_set_statfs (struct statvfs *statfs, Local<Object> obj) { // from http://linux.die.net/man/2/stat
|
2015-09-22 13:58:58 +00:00
|
|
|
if (obj->Has(LOCAL_STRING("bsize"))) statfs->f_bsize = obj->Get(LOCAL_STRING("bsize"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("frsize"))) statfs->f_frsize = obj->Get(LOCAL_STRING("frsize"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("blocks"))) statfs->f_blocks = obj->Get(LOCAL_STRING("blocks"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("bfree"))) statfs->f_bfree = obj->Get(LOCAL_STRING("bfree"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("bavail"))) statfs->f_bavail = obj->Get(LOCAL_STRING("bavail"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("files"))) statfs->f_files = obj->Get(LOCAL_STRING("files"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("ffree"))) statfs->f_ffree = obj->Get(LOCAL_STRING("ffree"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("favail"))) statfs->f_favail = obj->Get(LOCAL_STRING("favail"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("fsid"))) statfs->f_fsid = obj->Get(LOCAL_STRING("fsid"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("flag"))) statfs->f_flag = obj->Get(LOCAL_STRING("flag"))->Uint32Value();
|
|
|
|
if (obj->Has(LOCAL_STRING("namemax"))) statfs->f_namemax = obj->Get(LOCAL_STRING("namemax"))->Uint32Value();
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_INLINE static void bindings_set_dirs (bindings_t *b, Local<Array> dirs) {
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::HandleScope scope;
|
2015-03-12 02:11:29 +00:00
|
|
|
for (uint32_t i = 0; i < dirs->Length(); i++) {
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::Utf8String dir(dirs->Get(i));
|
2015-03-21 15:05:35 +00:00
|
|
|
if (b->filler(b->data, *dir, &empty_stat, 0)) break;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NAN_METHOD(OpCallback) {
|
2015-09-22 13:58:58 +00:00
|
|
|
bindings_t *b = bindings_mounted[info[0]->Uint32Value()];
|
|
|
|
b->result = (info.Length() > 1 && info[1]->IsNumber()) ? info[1]->Uint32Value() : 0;
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_current = NULL;
|
2015-03-21 15:05:35 +00:00
|
|
|
|
|
|
|
if (!b->result) {
|
|
|
|
switch (b->op) {
|
2015-03-15 10:56:54 +00:00
|
|
|
case OP_STATFS: {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (info.Length() > 2 && info[2]->IsObject()) bindings_set_statfs((struct statvfs *) b->data, info[2].As<Object>());
|
2015-03-15 10:56:54 +00:00
|
|
|
}
|
2015-03-12 02:11:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_GETATTR:
|
2015-03-15 10:56:54 +00:00
|
|
|
case OP_FGETATTR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (info.Length() > 2 && info[2]->IsObject()) bindings_set_stat((struct stat *) b->data, info[2].As<Object>());
|
2015-03-15 10:56:54 +00:00
|
|
|
}
|
2015-03-12 02:11:29 +00:00
|
|
|
break;
|
|
|
|
|
2015-03-15 10:56:54 +00:00
|
|
|
case OP_READDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (info.Length() > 2 && info[2]->IsArray()) bindings_set_dirs(b, info[2].As<Array>());
|
2015-03-15 10:56:54 +00:00
|
|
|
}
|
2015-03-12 02:11:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CREATE:
|
|
|
|
case OP_OPEN:
|
2015-03-15 10:56:54 +00:00
|
|
|
case OP_OPENDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (info.Length() > 2 && info[2]->IsNumber()) {
|
|
|
|
b->info->fh = info[2].As<Number>()->Uint32Value();
|
2015-03-23 14:21:11 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
}
|
2015-03-12 02:11:29 +00:00
|
|
|
break;
|
|
|
|
|
2015-03-23 14:21:11 +00:00
|
|
|
case OP_READLINK: {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (info.Length() > 2 && info[2]->IsString()) {
|
|
|
|
Nan::Utf8String path(info[2]);
|
2015-08-06 19:33:27 +00:00
|
|
|
strcpy((char *) b->data, *path);
|
2015-03-23 14:21:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
case OP_INIT:
|
2015-03-17 14:36:29 +00:00
|
|
|
case OP_ERROR:
|
2015-03-12 02:11:29 +00:00
|
|
|
case OP_ACCESS:
|
|
|
|
case OP_FLUSH:
|
|
|
|
case OP_FSYNC:
|
|
|
|
case OP_FSYNCDIR:
|
|
|
|
case OP_TRUNCATE:
|
|
|
|
case OP_FTRUNCATE:
|
|
|
|
case OP_CHOWN:
|
|
|
|
case OP_CHMOD:
|
2015-05-16 18:32:57 +00:00
|
|
|
case OP_MKNOD:
|
2015-03-12 02:11:29 +00:00
|
|
|
case OP_SETXATTR:
|
|
|
|
case OP_GETXATTR:
|
|
|
|
case OP_READ:
|
2015-03-23 16:17:13 +00:00
|
|
|
case OP_UTIMENS:
|
2015-03-12 02:11:29 +00:00
|
|
|
case OP_WRITE:
|
|
|
|
case OP_RELEASE:
|
|
|
|
case OP_RELEASEDIR:
|
|
|
|
case OP_UNLINK:
|
|
|
|
case OP_RENAME:
|
|
|
|
case OP_LINK:
|
|
|
|
case OP_SYMLINK:
|
|
|
|
case OP_MKDIR:
|
|
|
|
case OP_RMDIR:
|
|
|
|
case OP_DESTROY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
semaphore_signal(&(b->semaphore));
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
NAN_INLINE static void bindings_call_op (bindings_t *b, Nan::Callback *fn, int argc, Local<Value> *argv) {
|
2015-03-21 15:05:35 +00:00
|
|
|
if (fn == NULL) semaphore_signal(&(b->semaphore));
|
2015-03-15 10:56:54 +00:00
|
|
|
else fn->Call(argc, argv);
|
|
|
|
}
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
static void bindings_dispatch (uv_async_t* handle, int status) {
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::HandleScope scope;
|
2015-05-04 23:52:56 +00:00
|
|
|
|
2015-05-05 00:22:05 +00:00
|
|
|
bindings_t *b = bindings_current = (bindings_t *) handle->data;
|
2015-03-21 15:05:35 +00:00
|
|
|
Local<Function> callback = b->callback->GetFunction();
|
|
|
|
b->result = -1;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
switch (b->op) {
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_INIT: {
|
|
|
|
Local<Value> tmp[] = {callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_init, 1, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-17 12:32:09 +00:00
|
|
|
case OP_ERROR: {
|
|
|
|
Local<Value> tmp[] = {callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_error, 1, tmp);
|
2015-03-17 12:32:09 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_STATFS: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_statfs, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_FGETATTR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_fgetattr, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_GETATTR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_getattr, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_READDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_readdir, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_CREATE: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_create, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_TRUNCATE: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->length), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_truncate, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_FTRUNCATE: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), Nan::New<Number>(b->length), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_ftruncate, 4, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_ACCESS: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_access, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_OPEN: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_open, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_OPENDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_opendir, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_WRITE: {
|
|
|
|
Local<Value> tmp[] = {
|
2015-09-22 13:58:58 +00:00
|
|
|
LOCAL_STRING(b->path),
|
|
|
|
Nan::New<Number>(b->info->fh),
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_buffer((char *) b->data, b->length),
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::New<Number>(b->length), // TODO: remove me
|
|
|
|
Nan::New<Number>(b->offset),
|
2015-03-12 03:13:34 +00:00
|
|
|
callback
|
|
|
|
};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_write, 6, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_READ: {
|
|
|
|
Local<Value> tmp[] = {
|
2015-09-22 13:58:58 +00:00
|
|
|
LOCAL_STRING(b->path),
|
|
|
|
Nan::New<Number>(b->info->fh),
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_buffer((char *) b->data, b->length),
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::New<Number>(b->length), // TODO: remove me
|
|
|
|
Nan::New<Number>(b->offset),
|
2015-03-12 03:13:34 +00:00
|
|
|
callback
|
|
|
|
};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_read, 6, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_RELEASE: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_release, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_RELEASEDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_releasedir, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_UNLINK: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_unlink, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_RENAME: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), LOCAL_STRING((char *) b->data), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_rename, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_LINK: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), LOCAL_STRING((char *) b->data), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_link, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_SYMLINK: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), LOCAL_STRING((char *) b->data), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_symlink, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_CHMOD: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_chmod, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-05-16 18:32:57 +00:00
|
|
|
case OP_MKNOD: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), Nan::New<Number>(b->dev), callback};
|
2015-05-16 18:32:57 +00:00
|
|
|
bindings_call_op(b, b->ops_mknod, 4, tmp);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_CHOWN: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->uid), Nan::New<Number>(b->gid), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_chown, 4, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_READLINK: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-23 14:21:11 +00:00
|
|
|
bindings_call_op(b, b->ops_readlink, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_SETXATTR: {
|
|
|
|
Local<Value> tmp[] = {
|
2015-09-22 13:58:58 +00:00
|
|
|
LOCAL_STRING(b->path),
|
|
|
|
LOCAL_STRING(b->name),
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_buffer((char *) b->data, b->length),
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::New<Number>(b->length),
|
|
|
|
Nan::New<Number>(b->offset),
|
|
|
|
Nan::New<Number>(b->mode),
|
2015-03-12 03:13:34 +00:00
|
|
|
callback
|
|
|
|
};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_setxattr, 7, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_GETXATTR: {
|
|
|
|
Local<Value> tmp[] = {
|
2015-09-22 13:58:58 +00:00
|
|
|
LOCAL_STRING(b->path),
|
|
|
|
LOCAL_STRING(b->name),
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_buffer((char *) b->data, b->length),
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::New<Number>(b->length),
|
|
|
|
Nan::New<Number>(b->offset),
|
2015-03-12 03:13:34 +00:00
|
|
|
callback
|
|
|
|
};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_getxattr, 6, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_MKDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_mkdir, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_RMDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_rmdir, 2, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_DESTROY: {
|
|
|
|
Local<Value> tmp[] = {callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_destroy, 1, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_UTIMENS: {
|
2015-08-06 21:59:38 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
time_t *tv = (time_t *) b->data;
|
|
|
|
#else
|
2015-03-23 16:17:13 +00:00
|
|
|
struct timespec *tv = (struct timespec *) b->data;
|
2015-08-06 21:59:38 +00:00
|
|
|
#endif
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), bindings_get_date(tv), bindings_get_date(tv + 1), callback};
|
2015-03-23 16:17:13 +00:00
|
|
|
bindings_call_op(b, b->ops_utimens, 4, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_FLUSH: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_flush, 3, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_FSYNC: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_fsync, 4, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-03-12 03:13:34 +00:00
|
|
|
case OP_FSYNCDIR: {
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Value> tmp[] = {LOCAL_STRING(b->path), Nan::New<Number>(b->info->fh), Nan::New<Number>(b->mode), callback};
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_call_op(b, b->ops_fsyncdir, 4, tmp);
|
2015-03-12 03:13:34 +00:00
|
|
|
}
|
2015-03-15 10:56:54 +00:00
|
|
|
return;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
semaphore_signal(&(b->semaphore));
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
static int bindings_alloc () {
|
|
|
|
int free_index = -1;
|
|
|
|
size_t size = sizeof(bindings_t);
|
|
|
|
|
|
|
|
for (int i = 0; i < bindings_mounted_count; i++) {
|
|
|
|
if (bindings_mounted[i] == NULL) {
|
|
|
|
free_index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (free_index == -1 && bindings_mounted_count < 1024) free_index = bindings_mounted_count++;
|
|
|
|
if (free_index != -1) {
|
|
|
|
bindings_t *b = bindings_mounted[free_index] = (bindings_t *) malloc(size);
|
|
|
|
memset(b, 0, size);
|
|
|
|
b->index = free_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return free_index;
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NAN_METHOD(Mount) {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (!info[0]->IsString()) return Nan::ThrowError("mnt must be a string");
|
2015-03-21 15:05:35 +00:00
|
|
|
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_lock(&mutex);
|
2015-03-21 15:05:35 +00:00
|
|
|
int index = bindings_alloc();
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_unlock(&mutex);
|
2015-03-21 15:05:35 +00:00
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
if (index == -1) return Nan::ThrowError("You cannot mount more than 1024 filesystem in one process");
|
2015-03-21 15:05:35 +00:00
|
|
|
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_lock(&mutex);
|
2015-03-21 15:05:35 +00:00
|
|
|
bindings_t *b = bindings_mounted[index];
|
2015-08-06 17:24:38 +00:00
|
|
|
mutex_unlock(&mutex);
|
2015-03-20 11:52:47 +00:00
|
|
|
|
2015-03-20 03:11:42 +00:00
|
|
|
memset(&empty_stat, 0, sizeof(empty_stat));
|
2015-03-21 15:05:35 +00:00
|
|
|
memset(b, 0, sizeof(bindings_t));
|
2015-03-13 18:05:41 +00:00
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::Utf8String path(info[0]);
|
|
|
|
Local<Object> ops = info[1].As<Object>();
|
|
|
|
|
|
|
|
b->ops_init = LOOKUP_CALLBACK(ops, "init");
|
|
|
|
b->ops_error = LOOKUP_CALLBACK(ops, "error");
|
|
|
|
b->ops_access = LOOKUP_CALLBACK(ops, "access");
|
|
|
|
b->ops_statfs = LOOKUP_CALLBACK(ops, "statfs");
|
|
|
|
b->ops_getattr = LOOKUP_CALLBACK(ops, "getattr");
|
|
|
|
b->ops_fgetattr = LOOKUP_CALLBACK(ops, "fgetattr");
|
|
|
|
b->ops_flush = LOOKUP_CALLBACK(ops, "flush");
|
|
|
|
b->ops_fsync = LOOKUP_CALLBACK(ops, "fsync");
|
|
|
|
b->ops_fsyncdir = LOOKUP_CALLBACK(ops, "fsyncdir");
|
|
|
|
b->ops_readdir = LOOKUP_CALLBACK(ops, "readdir");
|
|
|
|
b->ops_truncate = LOOKUP_CALLBACK(ops, "truncate");
|
|
|
|
b->ops_ftruncate = LOOKUP_CALLBACK(ops, "ftruncate");
|
|
|
|
b->ops_readlink = LOOKUP_CALLBACK(ops, "readlink");
|
|
|
|
b->ops_chown = LOOKUP_CALLBACK(ops, "chown");
|
|
|
|
b->ops_chmod = LOOKUP_CALLBACK(ops, "chmod");
|
|
|
|
b->ops_mknod = LOOKUP_CALLBACK(ops, "mknod");
|
|
|
|
b->ops_setxattr = LOOKUP_CALLBACK(ops, "setxattr");
|
|
|
|
b->ops_getxattr = LOOKUP_CALLBACK(ops, "getxattr");
|
|
|
|
b->ops_open = LOOKUP_CALLBACK(ops, "open");
|
|
|
|
b->ops_opendir = LOOKUP_CALLBACK(ops, "opendir");
|
|
|
|
b->ops_read = LOOKUP_CALLBACK(ops, "read");
|
|
|
|
b->ops_write = LOOKUP_CALLBACK(ops, "write");
|
|
|
|
b->ops_release = LOOKUP_CALLBACK(ops, "release");
|
|
|
|
b->ops_releasedir = LOOKUP_CALLBACK(ops, "releasedir");
|
|
|
|
b->ops_create = LOOKUP_CALLBACK(ops, "create");
|
|
|
|
b->ops_utimens = LOOKUP_CALLBACK(ops, "utimens");
|
|
|
|
b->ops_unlink = LOOKUP_CALLBACK(ops, "unlink");
|
|
|
|
b->ops_rename = LOOKUP_CALLBACK(ops, "rename");
|
|
|
|
b->ops_link = LOOKUP_CALLBACK(ops, "link");
|
|
|
|
b->ops_symlink = LOOKUP_CALLBACK(ops, "symlink");
|
|
|
|
b->ops_mkdir = LOOKUP_CALLBACK(ops, "mkdir");
|
|
|
|
b->ops_rmdir = LOOKUP_CALLBACK(ops, "rmdir");
|
|
|
|
b->ops_destroy = LOOKUP_CALLBACK(ops, "destroy");
|
|
|
|
|
|
|
|
Local<Value> tmp[] = {Nan::New<Number>(index), Nan::New<FunctionTemplate>(OpCallback)->GetFunction()};
|
|
|
|
b->callback = new Nan::Callback(callback_constructor->Call(2, tmp).As<Function>());
|
2015-03-21 15:05:35 +00:00
|
|
|
|
2015-08-06 19:33:27 +00:00
|
|
|
strcpy(b->mnt, *path);
|
|
|
|
strcpy(b->mntopts, "-o");
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Array> options = ops->Get(LOCAL_STRING("options")).As<Array>();
|
2015-03-12 02:11:29 +00:00
|
|
|
if (options->IsArray()) {
|
2015-03-13 18:05:41 +00:00
|
|
|
for (uint32_t i = 0; i < options->Length(); i++) {
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::Utf8String option(options->Get(i));
|
2015-03-21 15:05:35 +00:00
|
|
|
if (strcmp(b->mntopts, "-o")) strcat(b->mntopts, ",");
|
|
|
|
strcat(b->mntopts, *option);
|
2015-03-13 18:05:41 +00:00
|
|
|
}
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
semaphore_init(&(b->semaphore));
|
|
|
|
uv_async_init(uv_default_loop(), &(b->async), (uv_async_cb) bindings_dispatch);
|
|
|
|
b->async.data = b;
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-08-06 17:24:38 +00:00
|
|
|
thread_create(&(b->thread), bindings_thread, b);
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
class UnmountWorker : public Nan::AsyncWorker {
|
2015-03-12 02:11:29 +00:00
|
|
|
public:
|
2015-09-22 13:58:58 +00:00
|
|
|
UnmountWorker(Nan::Callback *callback, char *path)
|
|
|
|
: Nan::AsyncWorker(callback), path(path) {}
|
2015-03-12 02:11:29 +00:00
|
|
|
~UnmountWorker() {}
|
|
|
|
|
|
|
|
void Execute () {
|
|
|
|
bindings_unmount(path);
|
|
|
|
free(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HandleOKCallback () {
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::HandleScope scope;
|
2015-03-12 02:11:29 +00:00
|
|
|
callback->Call(0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
char *path;
|
|
|
|
};
|
|
|
|
|
2015-03-21 15:05:35 +00:00
|
|
|
NAN_METHOD(SetCallback) {
|
2015-09-22 13:58:58 +00:00
|
|
|
callback_constructor = new Nan::Callback(info[0].As<Function>());
|
2015-03-21 15:05:35 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 21:28:33 +00:00
|
|
|
NAN_METHOD(SetBuffer) {
|
2015-09-22 13:58:58 +00:00
|
|
|
buffer_constructor.Reset(info[0].As<Function>());
|
2015-03-16 21:28:33 +00:00
|
|
|
}
|
|
|
|
|
2015-05-05 00:22:05 +00:00
|
|
|
NAN_METHOD(PopulateContext) {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (bindings_current == NULL) return Nan::ThrowError("You have to call this inside a fuse operation");
|
2015-05-05 00:22:05 +00:00
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
Local<Object> ctx = info[0].As<Object>();
|
|
|
|
ctx->Set(LOCAL_STRING("uid"), Nan::New(bindings_current->context_uid));
|
|
|
|
ctx->Set(LOCAL_STRING("gid"), Nan::New(bindings_current->context_gid));
|
|
|
|
ctx->Set(LOCAL_STRING("pid"), Nan::New(bindings_current->context_pid));
|
2015-05-05 00:22:05 +00:00
|
|
|
}
|
|
|
|
|
2015-03-12 02:11:29 +00:00
|
|
|
NAN_METHOD(Unmount) {
|
2015-09-22 13:58:58 +00:00
|
|
|
if (!info[0]->IsString()) return Nan::ThrowError("mnt must be a string");
|
|
|
|
Nan::Utf8String path(info[0]);
|
|
|
|
Local<Function> callback = info[1].As<Function>();
|
2015-03-12 02:11:29 +00:00
|
|
|
|
|
|
|
char *path_alloc = (char *) malloc(1024);
|
2015-08-06 19:33:27 +00:00
|
|
|
strcpy(path_alloc, *path);
|
2015-03-12 02:11:29 +00:00
|
|
|
|
2015-09-22 13:58:58 +00:00
|
|
|
Nan::AsyncQueueWorker(new UnmountWorker(new Nan::Callback(callback), path_alloc));
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Init(Handle<Object> exports) {
|
2015-09-22 13:58:58 +00:00
|
|
|
exports->Set(LOCAL_STRING("setCallback"), Nan::New<FunctionTemplate>(SetCallback)->GetFunction());
|
|
|
|
exports->Set(LOCAL_STRING("setBuffer"), Nan::New<FunctionTemplate>(SetBuffer)->GetFunction());
|
|
|
|
exports->Set(LOCAL_STRING("mount"), Nan::New<FunctionTemplate>(Mount)->GetFunction());
|
|
|
|
exports->Set(LOCAL_STRING("unmount"), Nan::New<FunctionTemplate>(Unmount)->GetFunction());
|
|
|
|
exports->Set(LOCAL_STRING("populateContext"), Nan::New<FunctionTemplate>(PopulateContext)->GetFunction());
|
2015-03-12 02:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 16:33:20 +00:00
|
|
|
NODE_MODULE(fuse_bindings, Init)
|