commit b249f974cd205529e5f57767b54879004d7e12b8 Author: Mathias Buus Date: Thu Mar 12 03:11:29 2015 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4739ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +.nadconfig.mk +build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..66a4d2a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..32aaea3 --- /dev/null +++ b/README.md @@ -0,0 +1,265 @@ +# fuse-bindings + +Fully maintained fuse bindings for Node that aims to cover the entire FUSE api + +``` +npm install fuse-bindings +``` + +Created because [fuse4js](https://github.com/bcle/fuse4js) isn't maintained anymore and doesn't compile on iojs + +## Usage + +Try creating an empty folder called `mnt` and run the below example + +``` js +var fuse = require('fuse-bindings') + +fuse.mount('./mnt', { + readdir: function (path, cb) { + if (path === '/') return cb(0, ['test']) + cb(0) + }, + getattr: function (path, cb) { + console.log('getattr(%s)', path) + if (path === '/') { + cb(0, { + mtime: new Date(), + atime: new Date(), + ctime: new Date(), + size: 100, + mode: 16877, + uid: process.getuid(), + gid: process.getgid() + }) + return + } + + if (path === '/test') { + cb(0, { + mtime: new Date(), + atime: new Date(), + ctime: new Date(), + size: 12, + mode: 33188, + uid: process.getuid(), + gid: process.getgid() + }) + return + } + + cb(fuse.ENOENT) + }, + open: function (path, flags, cb) { + console.log('open(%s, %d)', path, flags) + cb(0, 42) // 42 is an fd + }, + read: function (path, fd, buf, len, pos, cb) { + console.log('read(%s, %d, %d, %d)', path, fd, len, pos) + var str = 'hello world\n'.slice(pos) + if (!str) return cb(0) + buf.write(str) + return cb(str.length) + } +}) + +process.on('SIGINT', function () { + fuse.unmount('./mnt', function () { + process.exit() + }) +}) +``` + +## API + +#### `fuse.mount(mnt, ops)` + +Mount a new filesystem on `mnt`. +Pass the FUSE operations you want to support as the `ops` argument. + +#### `fuse.unmount(mnt, [cb])` + +Unmount a filesystem + +#### `fuse.unmountSync(mnt)` + +Unmount a filesystem synchroniously + +## FUSE operations + +Most of the [FUSE api](http://fuse.sourceforge.net/doxygen/structfuse__operations.html) is supported. + +* `ops.init(cb)` +* `ops.access(path, cb)` +* `ops.statfs(path, cb)` +* `ops.getattr(path, cb)` +* `ops.fgetattr(path, fd, cb)` +* `ops.flush(path, fd, cb)` +* `ops.fsync(path, fd, cb)` +* `ops.fsyncdir(path, fd, cb)` +* `ops.readdir(path, cb)` +* `ops.truncate(path, size, cb)` +* `ops.ftruncate(path, fd, size, cb)` +* `ops.readlink(path, result, cb)` +* `ops.chown(path, uid, gid, cb)` +* `ops.chmod(path, mode, cb)` +* `ops.setxattr(path, name, buf, length, offset, flags, cb)` +* `ops.getxattr(path, name, buf, length, offset, cb)` +* `ops.open(path, flags, cb)` +* `ops.opendir(path, flags, cb)` +* `ops.read(path, fd, buf, length, position, cb)` +* `ops.write(path, fd, buf, length, position, cb)` +* `ops.release(path, fd, cb)` +* `ops.releasedir(path, fd, cb)` +* `ops.create(path, mode, cb)` +* `ops.utimens(path, cb)` +* `ops.unlink(path, cb)` +* `ops.rename(src, dest, cb)` +* `ops.link(src, dest, cb)` +* `ops.symlink(src, dest, cb)` +* `ops.mkdir(path, cb)` +* `ops.rmdir(path, cb)` +* `ops.destroy(cb)` + +The goal is to support 100% of the API. + +When using `getattr` you should return a stat object after the status code, +`readdir` expects an array of directory names, `open` an optional fd and +`utimens` an object with `mtime` and `atime` dates. + +Both `read` and `write` passes the underlying fuse buffer without copying them to be as fast as possible. + +You can pass [mount options](http://blog.woralelandia.com/2012/07/16/fuse-mount-options/) (i.e. `direct_io` etc) as `ops.options = ['direct_io']` + +## Error codes + +The available error codes are exposes as well as properties. These include + +* `fuse.EPERM === -1` +* `fuse.ENOENT === -2` +* `fuse.ESRCH === -3` +* `fuse.EINTR === -4` +* `fuse.EIO === -5` +* `fuse.ENXIO === -6` +* `fuse.E2BIG === -7` +* `fuse.ENOEXEC === -8` +* `fuse.EBADF === -9` +* `fuse.ECHILD === -10` +* `fuse.EAGAIN === -11` +* `fuse.ENOMEM === -12` +* `fuse.EACCES === -13` +* `fuse.EFAULT === -14` +* `fuse.ENOTBLK === -15` +* `fuse.EBUSY === -16` +* `fuse.EEXIST === -17` +* `fuse.EXDEV === -18` +* `fuse.ENODEV === -19` +* `fuse.ENOTDIR === -20` +* `fuse.EISDIR === -21` +* `fuse.EINVAL === -22` +* `fuse.ENFILE === -23` +* `fuse.EMFILE === -24` +* `fuse.ENOTTY === -25` +* `fuse.ETXTBSY === -26` +* `fuse.EFBIG === -27` +* `fuse.ENOSPC === -28` +* `fuse.ESPIPE === -29` +* `fuse.EROFS === -30` +* `fuse.EMLINK === -31` +* `fuse.EPIPE === -32` +* `fuse.EDOM === -33` +* `fuse.ERANGE === -34` +* `fuse.EDEADLK === -35` +* `fuse.ENAMETOOLONG === -36` +* `fuse.ENOLCK === -37` +* `fuse.ENOSYS === -38` +* `fuse.ENOTEMPTY === -39` +* `fuse.ELOOP === -40` +* `fuse.EWOULDBLOCK === -11` +* `fuse.ENOMSG === -42` +* `fuse.EIDRM === -43` +* `fuse.ECHRNG === -44` +* `fuse.EL2NSYNC === -45` +* `fuse.EL3HLT === -46` +* `fuse.EL3RST === -47` +* `fuse.ELNRNG === -48` +* `fuse.EUNATCH === -49` +* `fuse.ENOCSI === -50` +* `fuse.EL2HLT === -51` +* `fuse.EBADE === -52` +* `fuse.EBADR === -53` +* `fuse.EXFULL === -54` +* `fuse.ENOANO === -55` +* `fuse.EBADRQC === -56` +* `fuse.EBADSLT === -57` +* `fuse.EDEADLOCK === -35` +* `fuse.EBFONT === -59` +* `fuse.ENOSTR === -60` +* `fuse.ENODATA === -61` +* `fuse.ETIME === -62` +* `fuse.ENOSR === -63` +* `fuse.ENONET === -64` +* `fuse.ENOPKG === -65` +* `fuse.EREMOTE === -66` +* `fuse.ENOLINK === -67` +* `fuse.EADV === -68` +* `fuse.ESRMNT === -69` +* `fuse.ECOMM === -70` +* `fuse.EPROTO === -71` +* `fuse.EMULTIHOP === -72` +* `fuse.EDOTDOT === -73` +* `fuse.EBADMSG === -74` +* `fuse.EOVERFLOW === -75` +* `fuse.ENOTUNIQ === -76` +* `fuse.EBADFD === -77` +* `fuse.EREMCHG === -78` +* `fuse.ELIBACC === -79` +* `fuse.ELIBBAD === -80` +* `fuse.ELIBSCN === -81` +* `fuse.ELIBMAX === -82` +* `fuse.ELIBEXEC === -83` +* `fuse.EILSEQ === -84` +* `fuse.ERESTART === -85` +* `fuse.ESTRPIPE === -86` +* `fuse.EUSERS === -87` +* `fuse.ENOTSOCK === -88` +* `fuse.EDESTADDRREQ === -89` +* `fuse.EMSGSIZE === -90` +* `fuse.EPROTOTYPE === -91` +* `fuse.ENOPROTOOPT === -92` +* `fuse.EPROTONOSUPPORT === -93` +* `fuse.ESOCKTNOSUPPORT === -94` +* `fuse.EOPNOTSUPP === -95` +* `fuse.EPFNOSUPPORT === -96` +* `fuse.EAFNOSUPPORT === -97` +* `fuse.EADDRINUSE === -98` +* `fuse.EADDRNOTAVAIL === -99` +* `fuse.ENETDOWN === -100` +* `fuse.ENETUNREACH === -101` +* `fuse.ENETRESET === -102` +* `fuse.ECONNABORTED === -103` +* `fuse.ECONNRESET === -104` +* `fuse.ENOBUFS === -105` +* `fuse.EISCONN === -106` +* `fuse.ENOTCONN === -107` +* `fuse.ESHUTDOWN === -108` +* `fuse.ETOOMANYREFS === -109` +* `fuse.ETIMEDOUT === -110` +* `fuse.ECONNREFUSED === -111` +* `fuse.EHOSTDOWN === -112` +* `fuse.EHOSTUNREACH === -113` +* `fuse.EALREADY === -114` +* `fuse.EINPROGRESS === -115` +* `fuse.ESTALE === -116` +* `fuse.EUCLEAN === -117` +* `fuse.ENOTNAM === -118` +* `fuse.ENAVAIL === -119` +* `fuse.EISNAM === -120` +* `fuse.EREMOTEIO === -121` +* `fuse.EDQUOT === -122` +* `fuse.ENOMEDIUM === -123` +* `fuse.EMEDIUMTYPE === -124` + +## License + +MIT diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..f9b5861 --- /dev/null +++ b/binding.gyp @@ -0,0 +1,17 @@ +{ + "targets": [ + { + "target_name": "fuse_bindings", + "sources": [ "fuse-bindings.cc" ], + "include_dirs": [ + " + +#define FUSE_USE_VERSION 26 + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#endif + +using namespace v8; + +enum bindings_ops_t { + OP_INIT = 0, + 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, + 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 +}; + +static struct stat empty_stat; + +// TODO support more than a single mount +static struct { + // fuse data + char mnt[1024]; + char mntopts[1024]; + pthread_t thread; +#ifdef __APPLE__ + dispatch_semaphore_t semaphore; +#else + sem_t semaphore; +#endif + uv_async_t async; + + // buffer + Persistent buffer_persistent; + + // methods + NanCallback *ops_init; + NanCallback *ops_access; + NanCallback *ops_statfs; + NanCallback *ops_getattr; + NanCallback *ops_fgetattr; + NanCallback *ops_flush; + NanCallback *ops_fsync; + NanCallback *ops_fsyncdir; + NanCallback *ops_readdir; + NanCallback *ops_truncate; + NanCallback *ops_ftruncate; + NanCallback *ops_readlink; + NanCallback *ops_chown; + NanCallback *ops_chmod; + NanCallback *ops_setxattr; + NanCallback *ops_getxattr; + NanCallback *ops_open; + NanCallback *ops_opendir; + NanCallback *ops_read; + NanCallback *ops_write; + NanCallback *ops_release; + NanCallback *ops_releasedir; + NanCallback *ops_create; + NanCallback *ops_utimens; + NanCallback *ops_unlink; + NanCallback *ops_rename; + NanCallback *ops_link; + NanCallback *ops_symlink; + NanCallback *ops_mkdir; + NanCallback *ops_rmdir; + NanCallback *ops_destroy; + + // method data + bindings_ops_t op; + NanCallback *callback; + fuse_fill_dir_t filler; // used in readdir + struct fuse_file_info *info; + char *path; + char *name; + off_t offset; + off_t length; + void *data; // various structs + int mode; + int uid; + int gid; + int result; +} bindings; + +#ifdef __APPLE__ +static void bindings_unmount (char *path) { + unmount(path, 0); +} + +static int semaphore_init (dispatch_semaphore_t *sem) { + *sem = dispatch_semaphore_create(0); + return *sem == NULL ? -1 : 0; +} + +static void semaphore_wait (dispatch_semaphore_t *sem) { + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); +} + +static void semaphore_signal (dispatch_semaphore_t *sem) { + dispatch_semaphore_signal(*sem); +} +#else +static void bindings_unmount (char *path) { + umount(path); +} + +static int semaphore_init (sem_t *sem) { + return sem_init(sem, 0, 1); +} + +static void semaphore_wait (sem_t *sem) { + sem_wait(sem); +} + +static void semaphore_signal (sem_t *sem) { + sem_post(sem); +} +#endif + +static int bindings_call () { + uv_async_send(&bindings.async); + semaphore_wait(&bindings.semaphore); + return bindings.result; +} + +static int bindings_truncate (const char *path, off_t size) { + bindings.op = OP_TRUNCATE; + bindings.path = (char *) path; + bindings.length = size; + return bindings_call(); +} + +static int bindings_ftruncate (const char *path, off_t size, struct fuse_file_info *info) { + bindings.op = OP_FTRUNCATE; + bindings.path = (char *) path; + bindings.length = size; + bindings.info = info; + return bindings_call(); +} + +static int bindings_getattr (const char *path, struct stat *stat) { + bindings.op = OP_GETATTR; + bindings.path = (char *) path; + bindings.data = stat; + return bindings_call(); +} + +static int bindings_fgetattr (const char *path, struct stat *stat, struct fuse_file_info *info) { + bindings.op = OP_FGETATTR; + bindings.path = (char *) path; + bindings.data = stat; + bindings.info = info; + return bindings_call(); +} + +static int bindings_flush (const char *path, struct fuse_file_info *info) { + bindings.op = OP_FLUSH; + bindings.path = (char *) path; + bindings.info = info; + return bindings_call(); +} + +static int bindings_fsync (const char *path, int datasync, struct fuse_file_info *info) { + bindings.op = OP_FSYNC; + bindings.path = (char *) path; + bindings.mode = datasync; + bindings.info = info; + return bindings_call(); +} + +static int bindings_fsyncdir (const char *path, int datasync, struct fuse_file_info *info) { + bindings.op = OP_FSYNCDIR; + bindings.path = (char *) path; + bindings.mode = datasync; + bindings.info = info; + return bindings_call(); +} + +static int bindings_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { + bindings.op = OP_READDIR; + bindings.path = (char *) path; + bindings.data = buf; + bindings.filler = filler; + return bindings_call(); +} + +static int bindings_readlink (const char *path, char *buf, size_t len) { + bindings.op = OP_READLINK; + bindings.path = (char *) path; + bindings.data = (void *) buf; + bindings.length = len; + return bindings_call(); +} + +static int bindings_chown (const char *path, uid_t uid, gid_t gid) { + bindings.op = OP_CHOWN; + bindings.path = (char *) path; + bindings.uid = uid; + bindings.gid = gid; + return bindings_call(); +} + +static int bindings_chmod (const char *path, mode_t mode) { + bindings.op = OP_CHMOD; + bindings.path = (char *) path; + bindings.mode = mode; + return bindings_call(); +} + +#ifdef __APPLE__ +static int bindings_setxattr (const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) { + bindings.op = OP_SETXATTR; + bindings.path = (char *) path; + bindings.name = (char *) name; + bindings.data = (void *) value; + bindings.length = size; + bindings.offset = position; + bindings.mode = flags; + return bindings_call(); +} + +static int bindings_getxattr (const char *path, const char *name, char *value, size_t size, uint32_t position) { + bindings.op = OP_GETXATTR; + bindings.path = (char *) path; + bindings.name = (char *) name; + bindings.data = (void *) value; + bindings.length = size; + bindings.offset = position; + return bindings_call(); +} +#else +static int bindings_setxattr (const char *path, const char *name, const char *value, size_t size, int flags) { + bindings.op = OP_SETXATTR; + bindings.path = (char *) path; + bindings.name = (char *) name; + bindings.data = (void *) value; + bindings.length = size; + bindings.offset = 0; + bindings.mode = flags; + return bindings_call(); +} + +static int bindings_getxattr (const char *path, const char *name, const char *value, size_t size) { + bindings.op = OP_GETXATTR; + bindings.path = (char *) path; + bindings.name = (char *) name; + bindings.data = (void *) value; + bindings.length = size; + bindings.offset = 0; + return bindings_call(); +} +#endif + +static int bindings_statfs (const char *path, struct statvfs *statfs) { + bindings.op = OP_STATFS; + bindings.path = (char *) path; + bindings.data = statfs; + return bindings_call(); +} + +static int bindings_open (const char *path, struct fuse_file_info *info) { + bindings.op = OP_OPEN; + bindings.path = (char *) path; + bindings.mode = info->flags; + bindings.info = info; + return bindings_call(); +} + +static int bindings_opendir (const char *path, struct fuse_file_info *info) { + bindings.op = OP_OPENDIR; + bindings.path = (char *) path; + bindings.mode = info->flags; + bindings.info = info; + return bindings_call(); +} + +static int bindings_read (const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info) { + bindings.op = OP_READ; + bindings.path = (char *) path; + bindings.data = (void *) buf; + bindings.offset = offset; + bindings.length = len; + bindings.info = info; + return bindings_call(); +} + +static int bindings_write (const char *path, const char *buf, size_t len, off_t offset, struct fuse_file_info * info) { + bindings.op = OP_WRITE; + bindings.path = (char *) path; + bindings.data = (void *) buf; + bindings.offset = offset; + bindings.length = len; + bindings.info = info; + return bindings_call(); +} + +static int bindings_release (const char *path, struct fuse_file_info *info) { + bindings.op = OP_RELEASE; + bindings.path = (char *) path; + bindings.info = info; + return bindings_call(); +} + +static int bindings_releasedir (const char *path, struct fuse_file_info *info) { + bindings.op = OP_RELEASEDIR; + bindings.path = (char *) path; + bindings.info = info; + return bindings_call(); +} + +static int bindings_access (const char *path, int mode) { + bindings.op = OP_ACCESS; + bindings.path = (char *) path; + bindings.mode = mode; + return bindings_call(); +} + +static int bindings_create (const char *path, mode_t mode, struct fuse_file_info *info) { + bindings.op = OP_CREATE; + bindings.path = (char *) path; + bindings.mode = mode; + bindings.info = info; + return bindings_call(); +} + +static int bindings_utimens (const char *path, const struct timespec tv[2]) { + bindings.op = OP_UTIMENS; + bindings.path = (char *) path; + bindings.data = (void *) tv; + return bindings_call(); +} + +static int bindings_unlink (const char *path) { + bindings.op = OP_UNLINK; + bindings.path = (char *) path; + return bindings_call(); +} + +static int bindings_rename (const char *src, const char *dest) { + bindings.op = OP_RENAME; + bindings.path = (char *) src; + bindings.data = (void *) dest; + return bindings_call(); +} + +static int bindings_link (const char *path, const char *dest) { + bindings.op = OP_LINK; + bindings.path = (char *) path; + bindings.data = (void *) dest; + return bindings_call(); +} + +static int bindings_symlink (const char *path, const char *dest) { + bindings.op = OP_SYMLINK; + bindings.path = (char *) path; + bindings.data = (void *) dest; + return bindings_call(); +} + +static int bindings_mkdir (const char *path, mode_t mode) { + bindings.op = OP_MKDIR; + bindings.path = (char *) path; + bindings.mode = mode; + return bindings_call(); +} + +static int bindings_rmdir (const char *path) { + bindings.op = OP_RMDIR; + bindings.path = (char *) path; + return bindings_call(); +} + +static void* bindings_init (struct fuse_conn_info *conn) { + bindings.op = OP_INIT; + bindings_call(); + return NULL; +} + +static void bindings_destroy (void *data) { + bindings.op = OP_DESTROY; + bindings_call(); +} + +static void *bindings_thread (void *) { + struct fuse_operations ops = { }; + + if (bindings.ops_access != NULL) ops.access = bindings_access; + if (bindings.ops_truncate != NULL) ops.truncate = bindings_truncate; + if (bindings.ops_ftruncate != NULL) ops.ftruncate = bindings_ftruncate; + if (bindings.ops_getattr != NULL) ops.getattr = bindings_getattr; + if (bindings.ops_fgetattr != NULL) ops.fgetattr = bindings_fgetattr; + if (bindings.ops_flush != NULL) ops.flush = bindings_flush; + if (bindings.ops_fsync != NULL) ops.fsync = bindings_fsync; + if (bindings.ops_fsyncdir != NULL) ops.fsyncdir = bindings_fsyncdir; + if (bindings.ops_readdir != NULL) ops.readdir = bindings_readdir; + if (bindings.ops_readlink != NULL) ops.readlink = bindings_readlink; + if (bindings.ops_chown != NULL) ops.chown = bindings_chown; + if (bindings.ops_chmod != NULL) ops.chmod = bindings_chmod; + if (bindings.ops_setxattr != NULL) ops.setxattr = bindings_setxattr; + if (bindings.ops_getxattr != NULL) ops.getxattr = bindings_getxattr; + if (bindings.ops_statfs != NULL) ops.statfs = bindings_statfs; + if (bindings.ops_open != NULL) ops.open = bindings_open; + if (bindings.ops_opendir != NULL) ops.opendir = bindings_opendir; + if (bindings.ops_read != NULL) ops.read = bindings_read; + if (bindings.ops_write != NULL) ops.write = bindings_write; + if (bindings.ops_release != NULL) ops.release = bindings_release; + if (bindings.ops_releasedir != NULL) ops.releasedir = bindings_releasedir; + if (bindings.ops_create != NULL) ops.create = bindings_create; + if (bindings.ops_utimens != NULL) ops.utimens = bindings_utimens; + if (bindings.ops_unlink != NULL) ops.unlink = bindings_unlink; + if (bindings.ops_rename != NULL) ops.rename = bindings_rename; + if (bindings.ops_link != NULL) ops.link = bindings_link; + if (bindings.ops_symlink != NULL) ops.symlink = bindings_symlink; + if (bindings.ops_mkdir != NULL) ops.mkdir = bindings_mkdir; + if (bindings.ops_rmdir != NULL) ops.rmdir = bindings_rmdir; + if (bindings.ops_init != NULL) ops.init = bindings_init; + if (bindings.ops_destroy != NULL) ops.destroy = bindings_destroy; + + char *argv[] = { + (char *) "dummy", + (char *) "-s", + (char *) "-f", + (char *) bindings.mnt, + (char *) bindings.mntopts + }; + + bindings_unmount(bindings.mnt); // should probably throw instead if mounted + + if (fuse_main(!strcmp(bindings.mntopts, "-o") ? 4 : 5, argv, &ops, NULL)) { + // TODO: error handle somehow + printf("fuse-binding: mount failed\n"); + } + + return NULL; +} + +static void bindings_set_date (Local date, struct timespec *out) { + 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; +} + +static void bindings_set_stat (Local obj, struct stat *stat) { + if (obj->Has(NanNew("dev"))) stat->st_dev = obj->Get(NanNew("dev"))->NumberValue(); + if (obj->Has(NanNew("ino"))) stat->st_ino = obj->Get(NanNew("ino"))->NumberValue(); + if (obj->Has(NanNew("mode"))) stat->st_mode = obj->Get(NanNew("mode"))->Uint32Value(); + if (obj->Has(NanNew("nlink"))) stat->st_nlink = obj->Get(NanNew("nlink"))->NumberValue(); + if (obj->Has(NanNew("uid"))) stat->st_uid = obj->Get(NanNew("uid"))->NumberValue(); + if (obj->Has(NanNew("gid"))) stat->st_gid = obj->Get(NanNew("gid"))->NumberValue(); + if (obj->Has(NanNew("rdev"))) stat->st_rdev = obj->Get(NanNew("rdev"))->NumberValue(); + if (obj->Has(NanNew("size"))) stat->st_size = obj->Get(NanNew("size"))->NumberValue(); + if (obj->Has(NanNew("blksize"))) stat->st_blksize = obj->Get(NanNew("blksize"))->NumberValue(); + if (obj->Has(NanNew("blocks"))) stat->st_blocks = obj->Get(NanNew("blocks"))->NumberValue(); +#ifdef __APPLE__ + if (obj->Has(NanNew("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As(), &stat->st_mtimespec); + if (obj->Has(NanNew("ctime"))) bindings_set_date(obj->Get(NanNew("ctime")).As(), &stat->st_ctimespec); + if (obj->Has(NanNew("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As(), &stat->st_atimespec); +#else + if (obj->Has(NanNew("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As(), &stat->st_mtim); + if (obj->Has(NanNew("ctime"))) bindings_set_date(obj->Get(NanNew("ctime")).As(), &stat->st_ctim); + if (obj->Has(NanNew("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As(), &stat->st_atim); +#endif +} + +static void bindings_set_utimens (Local obj, struct timespec tv[2]) { + if (obj->Has(NanNew("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As(), &tv[0]); + if (obj->Has(NanNew("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As(), &tv[1]); +} + +static void bindings_set_statfs (Local obj, struct statvfs *statfs) { // from http://linux.die.net/man/2/stat + if (obj->Has(NanNew("bsize"))) statfs->f_bsize = obj->Get(NanNew("bsize"))->Uint32Value(); + if (obj->Has(NanNew("frsize"))) statfs->f_frsize = obj->Get(NanNew("frsize"))->Uint32Value(); + if (obj->Has(NanNew("blocks"))) statfs->f_blocks = obj->Get(NanNew("blocks"))->Uint32Value(); + if (obj->Has(NanNew("bfree"))) statfs->f_bfree = obj->Get(NanNew("bfree"))->Uint32Value(); + if (obj->Has(NanNew("bavail"))) statfs->f_bavail = obj->Get(NanNew("bavail"))->Uint32Value(); + if (obj->Has(NanNew("files"))) statfs->f_files = obj->Get(NanNew("files"))->Uint32Value(); + if (obj->Has(NanNew("ffree"))) statfs->f_ffree = obj->Get(NanNew("ffree"))->Uint32Value(); + if (obj->Has(NanNew("favail"))) statfs->f_favail = obj->Get(NanNew("favail"))->Uint32Value(); + if (obj->Has(NanNew("fsid"))) statfs->f_fsid = obj->Get(NanNew("fsid"))->Uint32Value(); + if (obj->Has(NanNew("flag"))) statfs->f_flag = obj->Get(NanNew("flag"))->Uint32Value(); + if (obj->Has(NanNew("namemax"))) statfs->f_namemax = obj->Get(NanNew("namemax"))->Uint32Value(); +} + +static void bindings_set_dirs (Local dirs) { + for (uint32_t i = 0; i < dirs->Length(); i++) { + if (bindings.filler(bindings.data, (char *) *NanUtf8String(dirs->Get(i).As()), &empty_stat, 0)) break; + } +} + +static void bindings_set_fd (Local fd) { + bindings.info->fh = fd->Uint32Value(); +} + +NAN_METHOD(OpCallback) { + NanScope(); + bindings.result = args[0]->Uint32Value(); + + if (!bindings.result) { + switch (bindings.op) { + case OP_STATFS: + if (args.Length() > 1 && args[1]->IsObject()) bindings_set_statfs(args[1].As(), (struct statvfs *) bindings.data); + break; + + case OP_GETATTR: + case OP_FGETATTR: + if (args.Length() > 1 && args[1]->IsObject()) bindings_set_stat(args[1].As(), (struct stat *) bindings.data); + break; + + case OP_READDIR: + if (args.Length() > 1 && args[1]->IsArray()) bindings_set_dirs(args[1].As()); + break; + + case OP_CREATE: + case OP_OPEN: + case OP_OPENDIR: + if (args.Length() > 1 && args[1]->IsNumber()) bindings_set_fd(args[1].As()); + break; + + case OP_UTIMENS: + if (args.Length() > 1 && args[1]->IsObject()) bindings_set_utimens(args[1].As(), (struct timespec *) bindings.data); + break; + + case OP_INIT: + case OP_ACCESS: + case OP_FLUSH: + case OP_FSYNC: + case OP_FSYNCDIR: + case OP_TRUNCATE: + case OP_FTRUNCATE: + case OP_READLINK: + case OP_CHOWN: + case OP_CHMOD: + case OP_SETXATTR: + case OP_GETXATTR: + case OP_READ: + 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; + } + } + + semaphore_signal(&bindings.semaphore); + NanReturnUndefined(); +} + +static void bindings_dispatch (uv_async_t* handle, int status) { + NanCallback *fn = NULL; + int argc; + Local *argv; + Local callback = bindings.callback->GetFunction(); + Local buf; + bindings.result = -1; + + switch (bindings.op) { + case OP_INIT: + argv = (Local[]) {callback}; + argc = 1; + fn = bindings.ops_init; + break; + + case OP_STATFS: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_statfs; + break; + + case OP_FGETATTR: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), callback}; + argc = 3; + fn = bindings.ops_fgetattr; + break; + + case OP_GETATTR: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_getattr; + break; + + case OP_READDIR: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_readdir; + break; + + case OP_CREATE: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_create; + break; + + case OP_TRUNCATE: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.offset), callback}; + argc = 3; + fn = bindings.ops_truncate; + break; + + case OP_FTRUNCATE: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), NanNew(bindings.offset), callback}; + argc = 4; + fn = bindings.ops_ftruncate; + break; + + case OP_ACCESS: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_access; + break; + + case OP_OPEN: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_open; + break; + + case OP_OPENDIR: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_opendir; + break; + + case OP_WRITE: + buf = NanNew(bindings.buffer_persistent); + buf->Set(NanNew("length"), NanNew(bindings.length)); + buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length); + + argv = (Local[]) { + NanNew(bindings.path), + NanNew(bindings.info->fh), + buf, + NanNew(bindings.length), + NanNew(bindings.offset), + callback + }; + argc = 6; + fn = bindings.ops_write; + break; + + case OP_READ: + buf = NanNew(bindings.buffer_persistent); + buf->Set(NanNew("length"), NanNew(bindings.length)); + buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length); + + argv = (Local[]) { + NanNew(bindings.path), + NanNew(bindings.info->fh), + buf, + NanNew(bindings.length), + NanNew(bindings.offset), + callback + }; + argc = 6; + fn = bindings.ops_read; + break; + + case OP_RELEASE: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), callback}; + argc = 3; + fn = bindings.ops_release; + break; + + case OP_RELEASEDIR: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), callback}; + argc = 3; + fn = bindings.ops_releasedir; + break; + + case OP_UNLINK: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_unlink; + break; + + case OP_RENAME: + argv = (Local[]) {NanNew(bindings.path), NanNew((char *) bindings.data), callback}; + argc = 3; + fn = bindings.ops_rename; + break; + + case OP_LINK: + argv = (Local[]) {NanNew(bindings.path), NanNew((char *) bindings.data), callback}; + argc = 3; + fn = bindings.ops_link; + break; + + case OP_SYMLINK: + argv = (Local[]) {NanNew(bindings.path), NanNew((char *) bindings.data), callback}; + argc = 3; + fn = bindings.ops_symlink; + break; + + case OP_CHMOD: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_chmod; + break; + + case OP_CHOWN: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.uid), NanNew(bindings.gid), callback}; + argc = 4; + fn = bindings.ops_chown; + break; + + case OP_READLINK: + buf = NanNew(bindings.buffer_persistent); + buf->Set(NanNew("length"), NanNew(bindings.length)); + buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length); + + argv = (Local[]) {NanNew(bindings.path), buf, NanNew(bindings.length), callback}; + argc = 4; + fn = bindings.ops_readlink; + break; + + case OP_SETXATTR: + buf = NanNew(bindings.buffer_persistent); + buf->Set(NanNew("length"), NanNew(bindings.length)); + buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length); + + argv = (Local[]) { + NanNew(bindings.path), + NanNew(bindings.name), + buf, + NanNew(bindings.length), + NanNew(bindings.offset), + NanNew(bindings.mode), + callback + }; + argc = 7; + fn = bindings.ops_setxattr; + break; + + case OP_GETXATTR: + buf = NanNew(bindings.buffer_persistent); + buf->Set(NanNew("length"), NanNew(bindings.length)); + buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length); + + argv = (Local[]) { + NanNew(bindings.path), + NanNew(bindings.name), + buf, + NanNew(bindings.length), + NanNew(bindings.offset), + callback + }; + argc = 6; + fn = bindings.ops_getxattr; + break; + + case OP_MKDIR: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.mode), callback}; + argc = 3; + fn = bindings.ops_mkdir; + break; + + case OP_RMDIR: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_rmdir; + break; + + case OP_DESTROY: + argv = (Local[]) {callback}; + argc = 1; + fn = bindings.ops_destroy; + break; + + case OP_UTIMENS: + argv = (Local[]) {NanNew(bindings.path), callback}; + argc = 2; + fn = bindings.ops_utimens; + break; + + case OP_FLUSH: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), callback}; + argc = 3; + fn = bindings.ops_flush; + break; + + case OP_FSYNC: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), NanNew(bindings.mode), callback}; + argc = 4; + fn = bindings.ops_fsync; + break; + + case OP_FSYNCDIR: + argv = (Local[]) {NanNew(bindings.path), NanNew(bindings.info->fh), NanNew(bindings.mode), callback}; + argc = 4; + fn = bindings.ops_fsyncdir; + break; + } + + if (fn == NULL) semaphore_signal(&bindings.semaphore); + else fn->Call(argc, argv); +} + +static void bindings_append_opt (char *name) { + if (strcmp(bindings.mntopts, "-o")) strcat(bindings.mntopts, ","); + strcat(bindings.mntopts, name); +} + +NAN_METHOD(Mount) { + NanScope(); + + memset(&empty_stat, 0, sizeof(empty_stat)); // zero empty stat + char *path = (char *) *NanUtf8String(args[0].As()); + Local ops = args[1].As(); + + bindings.ops_init = ops->Has(NanNew("init")) ? new NanCallback(ops->Get(NanNew("init")).As()) : NULL; + bindings.ops_access = ops->Has(NanNew("access")) ? new NanCallback(ops->Get(NanNew("access")).As()) : NULL; + bindings.ops_statfs = ops->Has(NanNew("statfs")) ? new NanCallback(ops->Get(NanNew("statfs")).As()) : NULL; + bindings.ops_getattr = ops->Has(NanNew("getattr")) ? new NanCallback(ops->Get(NanNew("getattr")).As()) : NULL; + bindings.ops_fgetattr = ops->Has(NanNew("fgetattr")) ? new NanCallback(ops->Get(NanNew("fgetattr")).As()) : NULL; + bindings.ops_flush = ops->Has(NanNew("flush")) ? new NanCallback(ops->Get(NanNew("flush")).As()) : NULL; + bindings.ops_fsync = ops->Has(NanNew("fsync")) ? new NanCallback(ops->Get(NanNew("fsync")).As()) : NULL; + bindings.ops_fsyncdir = ops->Has(NanNew("fsyncdir")) ? new NanCallback(ops->Get(NanNew("fsyncdir")).As()) : NULL; + bindings.ops_readdir = ops->Has(NanNew("readdir")) ? new NanCallback(ops->Get(NanNew("readdir")).As()) : NULL; + bindings.ops_truncate = ops->Has(NanNew("truncate")) ? new NanCallback(ops->Get(NanNew("truncate")).As()) : NULL; + bindings.ops_ftruncate = ops->Has(NanNew("ftruncate")) ? new NanCallback(ops->Get(NanNew("ftruncate")).As()) : NULL; + bindings.ops_readlink = ops->Has(NanNew("readlink")) ? new NanCallback(ops->Get(NanNew("readlink")).As()) : NULL; + bindings.ops_chown = ops->Has(NanNew("chown")) ? new NanCallback(ops->Get(NanNew("chown")).As()) : NULL; + bindings.ops_chmod = ops->Has(NanNew("chmod")) ? new NanCallback(ops->Get(NanNew("chmod")).As()) : NULL; + bindings.ops_setxattr = ops->Has(NanNew("setxattr")) ? new NanCallback(ops->Get(NanNew("setxattr")).As()) : NULL; + bindings.ops_getxattr = ops->Has(NanNew("getxattr")) ? new NanCallback(ops->Get(NanNew("getxattr")).As()) : NULL; + bindings.ops_open = ops->Has(NanNew("open")) ? new NanCallback(ops->Get(NanNew("open")).As()) : NULL; + bindings.ops_opendir = ops->Has(NanNew("opendir")) ? new NanCallback(ops->Get(NanNew("opendir")).As()) : NULL; + bindings.ops_read = ops->Has(NanNew("read")) ? new NanCallback(ops->Get(NanNew("read")).As()) : NULL; + bindings.ops_write = ops->Has(NanNew("write")) ? new NanCallback(ops->Get(NanNew("write")).As()) : NULL; + bindings.ops_release = ops->Has(NanNew("release")) ? new NanCallback(ops->Get(NanNew("release")).As()) : NULL; + bindings.ops_releasedir = ops->Has(NanNew("releasedir")) ? new NanCallback(ops->Get(NanNew("releasedir")).As()) : NULL; + bindings.ops_create = ops->Has(NanNew("create")) ? new NanCallback(ops->Get(NanNew("create")).As()) : NULL; + bindings.ops_utimens = ops->Has(NanNew("utimens")) ? new NanCallback(ops->Get(NanNew("utimens")).As()) : NULL; + bindings.ops_unlink = ops->Has(NanNew("unlink")) ? new NanCallback(ops->Get(NanNew("unlink")).As()) : NULL; + bindings.ops_rename = ops->Has(NanNew("rename")) ? new NanCallback(ops->Get(NanNew("rename")).As()) : NULL; + bindings.ops_link = ops->Has(NanNew("link")) ? new NanCallback(ops->Get(NanNew("link")).As()) : NULL; + bindings.ops_symlink = ops->Has(NanNew("symlink")) ? new NanCallback(ops->Get(NanNew("symlink")).As()) : NULL; + bindings.ops_mkdir = ops->Has(NanNew("mkdir")) ? new NanCallback(ops->Get(NanNew("mkdir")).As()) : NULL; + bindings.ops_rmdir = ops->Has(NanNew("rmdir")) ? new NanCallback(ops->Get(NanNew("rmdir")).As()) : NULL; + bindings.ops_destroy = ops->Has(NanNew("destroy")) ? new NanCallback(ops->Get(NanNew("destroy")).As()) : NULL; + + NanAssignPersistent(bindings.buffer_persistent, args[2].As()); + + bindings.callback = new NanCallback(NanNew(OpCallback)->GetFunction()); + stpcpy(bindings.mnt, path); + stpcpy(bindings.mntopts, "-o"); + + Local options = ops->Get(NanNew("options")).As(); + if (options->IsArray()) { + for (uint32_t i = 0; i < options->Length(); i++) bindings_append_opt((char *) *NanUtf8String(options->Get(i).As())); + } + + // yolo + semaphore_init(&bindings.semaphore); + uv_async_init(uv_default_loop(), &bindings.async, (uv_async_cb) bindings_dispatch); + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_create(&bindings.thread, &attr, bindings_thread, NULL); + + NanReturnUndefined(); +} + +NAN_METHOD(UnmountSync) { + NanScope(); + char *path = (char *) *NanUtf8String(args[0].As()); + bindings_unmount(path); + NanReturnUndefined(); +} + +class UnmountWorker : public NanAsyncWorker { + public: + UnmountWorker(NanCallback *callback, char *path) + : NanAsyncWorker(callback), path(path) {} + ~UnmountWorker() {} + + void Execute () { + bindings_unmount(path); + free(path); + } + + void HandleOKCallback () { + NanScope(); + callback->Call(0, NULL); + } + + private: + char *path; +}; + + +NAN_METHOD(Unmount) { + NanScope(); + char *path = (char *) *NanUtf8String(args[0].As()); + Local callback = args[1].As(); + + char *path_alloc = (char *) malloc(1024); + stpcpy(path_alloc, path); + + NanAsyncQueueWorker(new UnmountWorker(new NanCallback(callback), path_alloc)); + NanReturnUndefined(); +} + +void Init(Handle exports) { + exports->Set(NanNew("mount"), NanNew(Mount)->GetFunction()); + exports->Set(NanNew("unmount"), NanNew(Unmount)->GetFunction()); + exports->Set(NanNew("unmountSync"), NanNew(UnmountSync)->GetFunction()); +} + +NODE_MODULE(fuse_bindings, Init) \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..654382c --- /dev/null +++ b/index.js @@ -0,0 +1,150 @@ +var bindings = require('bindings') +var fuse = bindings('fuse_bindings') +var path = require('path') + +var noop = function () {} + +var FuseBuffer = function () { + this.length = 0 +} + +FuseBuffer.prototype = Buffer.prototype + +exports.mount = function (mnt, ops) { + if (!ops) ops = {} + if (/\*|(^,)fuse-bindings(,$)/.test(process.env.DEBUG)) ops.options = ['debug'].concat(ops.options || []) + return fuse.mount(path.resolve(mnt), ops, new FuseBuffer()) +} + +exports.unmount = function (mnt, cb) { + fuse.unmount(path.resolve(mnt), cb || noop) +} + +exports.unmountSync = function (mnt) { + return fuse.unmountSync(path.resolve(mnt)) +} + +exports.EPERM = -1 +exports.ENOENT = -2 +exports.ESRCH = -3 +exports.EINTR = -4 +exports.EIO = -5 +exports.ENXIO = -6 +exports.E2BIG = -7 +exports.ENOEXEC = -8 +exports.EBADF = -9 +exports.ECHILD = -10 +exports.EAGAIN = -11 +exports.ENOMEM = -12 +exports.EACCES = -13 +exports.EFAULT = -14 +exports.ENOTBLK = -15 +exports.EBUSY = -16 +exports.EEXIST = -17 +exports.EXDEV = -18 +exports.ENODEV = -19 +exports.ENOTDIR = -20 +exports.EISDIR = -21 +exports.EINVAL = -22 +exports.ENFILE = -23 +exports.EMFILE = -24 +exports.ENOTTY = -25 +exports.ETXTBSY = -26 +exports.EFBIG = -27 +exports.ENOSPC = -28 +exports.ESPIPE = -29 +exports.EROFS = -30 +exports.EMLINK = -31 +exports.EPIPE = -32 +exports.EDOM = -33 +exports.ERANGE = -34 +exports.EDEADLK = -35 +exports.ENAMETOOLONG = -36 +exports.ENOLCK = -37 +exports.ENOSYS = -38 +exports.ENOTEMPTY = -39 +exports.ELOOP = -40 +exports.EWOULDBLOCK = -11 +exports.ENOMSG = -42 +exports.EIDRM = -43 +exports.ECHRNG = -44 +exports.EL2NSYNC = -45 +exports.EL3HLT = -46 +exports.EL3RST = -47 +exports.ELNRNG = -48 +exports.EUNATCH = -49 +exports.ENOCSI = -50 +exports.EL2HLT = -51 +exports.EBADE = -52 +exports.EBADR = -53 +exports.EXFULL = -54 +exports.ENOANO = -55 +exports.EBADRQC = -56 +exports.EBADSLT = -57 +exports.EDEADLOCK = -35 +exports.EBFONT = -59 +exports.ENOSTR = -60 +exports.ENODATA = -61 +exports.ETIME = -62 +exports.ENOSR = -63 +exports.ENONET = -64 +exports.ENOPKG = -65 +exports.EREMOTE = -66 +exports.ENOLINK = -67 +exports.EADV = -68 +exports.ESRMNT = -69 +exports.ECOMM = -70 +exports.EPROTO = -71 +exports.EMULTIHOP = -72 +exports.EDOTDOT = -73 +exports.EBADMSG = -74 +exports.EOVERFLOW = -75 +exports.ENOTUNIQ = -76 +exports.EBADFD = -77 +exports.EREMCHG = -78 +exports.ELIBACC = -79 +exports.ELIBBAD = -80 +exports.ELIBSCN = -81 +exports.ELIBMAX = -82 +exports.ELIBEXEC = -83 +exports.EILSEQ = -84 +exports.ERESTART = -85 +exports.ESTRPIPE = -86 +exports.EUSERS = -87 +exports.ENOTSOCK = -88 +exports.EDESTADDRREQ = -89 +exports.EMSGSIZE = -90 +exports.EPROTOTYPE = -91 +exports.ENOPROTOOPT = -92 +exports.EPROTONOSUPPORT = -93 +exports.ESOCKTNOSUPPORT = -94 +exports.EOPNOTSUPP = -95 +exports.EPFNOSUPPORT = -96 +exports.EAFNOSUPPORT = -97 +exports.EADDRINUSE = -98 +exports.EADDRNOTAVAIL = -99 +exports.ENETDOWN = -100 +exports.ENETUNREACH = -101 +exports.ENETRESET = -102 +exports.ECONNABORTED = -103 +exports.ECONNRESET = -104 +exports.ENOBUFS = -105 +exports.EISCONN = -106 +exports.ENOTCONN = -107 +exports.ESHUTDOWN = -108 +exports.ETOOMANYREFS = -109 +exports.ETIMEDOUT = -110 +exports.ECONNREFUSED = -111 +exports.EHOSTDOWN = -112 +exports.EHOSTUNREACH = -113 +exports.EALREADY = -114 +exports.EINPROGRESS = -115 +exports.ESTALE = -116 +exports.EUCLEAN = -117 +exports.ENOTNAM = -118 +exports.ENAVAIL = -119 +exports.EISNAM = -120 +exports.EREMOTEIO = -121 +exports.EDQUOT = -122 +exports.ENOMEDIUM = -123 +exports.EMEDIUMTYPE = -124 diff --git a/package.json b/package.json new file mode 100644 index 0000000..6c8cc36 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "fuse-bindings", + "version": "0.0.0", + "description": "Fully maintained fuse bindings for Node that aims to cover the entire FUSE api", + "main": "index.js", + "scripts": { + "install": "node-gyp rebuild" + }, + "gypfile": true, + "dependencies": { + "bindings": "^1.2.1", + "nan": "^1.7.0" + }, + "devDependencies": {}, + "repository": { + "type": "git", + "url": "https://github.com/mafintosh/fuse-bindings.git" + }, + "author": "Mathias Buus (@mafintosh)", + "license": "MIT", + "bugs": { + "url": "https://github.com/mafintosh/fuse-bindings/issues" + }, + "homepage": "https://github.com/mafintosh/fuse-bindings" +}