mirror of
https://github.com/fuse-friends/fuse-native
synced 2024-10-27 18:34:01 +00:00
first commit
This commit is contained in:
commit
b249f974cd
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.nadconfig.mk
|
||||
build
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -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.
|
265
README.md
Normal file
265
README.md
Normal file
@ -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
|
17
binding.gyp
Normal file
17
binding.gyp
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "fuse_bindings",
|
||||
"sources": [ "fuse-bindings.cc" ],
|
||||
"include_dirs": [
|
||||
"<!(node -e \"require('nan')\")",
|
||||
"<!@(pkg-config fuse --cflags-only-I | sed s/-I//g)"
|
||||
],
|
||||
"link_settings": {
|
||||
"libraries": [
|
||||
"<!@(pkg-config --libs-only-l fuse)"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
49
example.js
Normal file
49
example.js
Normal file
@ -0,0 +1,49 @@
|
||||
var fuse = require('./')
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
953
fuse-bindings.cc
Normal file
953
fuse-bindings.cc
Normal file
@ -0,0 +1,953 @@
|
||||
#include <nan.h>
|
||||
|
||||
#define FUSE_USE_VERSION 26
|
||||
|
||||
#include <fuse.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mount.h>
|
||||
#ifdef __APPLE__
|
||||
#include <dispatch/dispatch.h>
|
||||
#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<Object> 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> 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<Object> obj, struct stat *stat) {
|
||||
if (obj->Has(NanNew<String>("dev"))) stat->st_dev = obj->Get(NanNew<String>("dev"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("ino"))) stat->st_ino = obj->Get(NanNew<String>("ino"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("mode"))) stat->st_mode = obj->Get(NanNew<String>("mode"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("nlink"))) stat->st_nlink = obj->Get(NanNew<String>("nlink"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("uid"))) stat->st_uid = obj->Get(NanNew<String>("uid"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("gid"))) stat->st_gid = obj->Get(NanNew<String>("gid"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("rdev"))) stat->st_rdev = obj->Get(NanNew<String>("rdev"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("size"))) stat->st_size = obj->Get(NanNew<String>("size"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("blksize"))) stat->st_blksize = obj->Get(NanNew<String>("blksize"))->NumberValue();
|
||||
if (obj->Has(NanNew<String>("blocks"))) stat->st_blocks = obj->Get(NanNew<String>("blocks"))->NumberValue();
|
||||
#ifdef __APPLE__
|
||||
if (obj->Has(NanNew<String>("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As<Date>(), &stat->st_mtimespec);
|
||||
if (obj->Has(NanNew<String>("ctime"))) bindings_set_date(obj->Get(NanNew("ctime")).As<Date>(), &stat->st_ctimespec);
|
||||
if (obj->Has(NanNew<String>("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As<Date>(), &stat->st_atimespec);
|
||||
#else
|
||||
if (obj->Has(NanNew<String>("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As<Date>(), &stat->st_mtim);
|
||||
if (obj->Has(NanNew<String>("ctime"))) bindings_set_date(obj->Get(NanNew("ctime")).As<Date>(), &stat->st_ctim);
|
||||
if (obj->Has(NanNew<String>("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As<Date>(), &stat->st_atim);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bindings_set_utimens (Local<Object> obj, struct timespec tv[2]) {
|
||||
if (obj->Has(NanNew<String>("atime"))) bindings_set_date(obj->Get(NanNew("atime")).As<Date>(), &tv[0]);
|
||||
if (obj->Has(NanNew<String>("mtime"))) bindings_set_date(obj->Get(NanNew("mtime")).As<Date>(), &tv[1]);
|
||||
}
|
||||
|
||||
static void bindings_set_statfs (Local<Object> obj, struct statvfs *statfs) { // from http://linux.die.net/man/2/stat
|
||||
if (obj->Has(NanNew<String>("bsize"))) statfs->f_bsize = obj->Get(NanNew<String>("bsize"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("frsize"))) statfs->f_frsize = obj->Get(NanNew<String>("frsize"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("blocks"))) statfs->f_blocks = obj->Get(NanNew<String>("blocks"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("bfree"))) statfs->f_bfree = obj->Get(NanNew<String>("bfree"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("bavail"))) statfs->f_bavail = obj->Get(NanNew<String>("bavail"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("files"))) statfs->f_files = obj->Get(NanNew<String>("files"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("ffree"))) statfs->f_ffree = obj->Get(NanNew<String>("ffree"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("favail"))) statfs->f_favail = obj->Get(NanNew<String>("favail"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("fsid"))) statfs->f_fsid = obj->Get(NanNew<String>("fsid"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("flag"))) statfs->f_flag = obj->Get(NanNew<String>("flag"))->Uint32Value();
|
||||
if (obj->Has(NanNew<String>("namemax"))) statfs->f_namemax = obj->Get(NanNew<String>("namemax"))->Uint32Value();
|
||||
}
|
||||
|
||||
static void bindings_set_dirs (Local<Array> dirs) {
|
||||
for (uint32_t i = 0; i < dirs->Length(); i++) {
|
||||
if (bindings.filler(bindings.data, (char *) *NanUtf8String(dirs->Get(i).As<String>()), &empty_stat, 0)) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bindings_set_fd (Local<Number> 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<Object>(), (struct statvfs *) bindings.data);
|
||||
break;
|
||||
|
||||
case OP_GETATTR:
|
||||
case OP_FGETATTR:
|
||||
if (args.Length() > 1 && args[1]->IsObject()) bindings_set_stat(args[1].As<Object>(), (struct stat *) bindings.data);
|
||||
break;
|
||||
|
||||
case OP_READDIR:
|
||||
if (args.Length() > 1 && args[1]->IsArray()) bindings_set_dirs(args[1].As<Array>());
|
||||
break;
|
||||
|
||||
case OP_CREATE:
|
||||
case OP_OPEN:
|
||||
case OP_OPENDIR:
|
||||
if (args.Length() > 1 && args[1]->IsNumber()) bindings_set_fd(args[1].As<Number>());
|
||||
break;
|
||||
|
||||
case OP_UTIMENS:
|
||||
if (args.Length() > 1 && args[1]->IsObject()) bindings_set_utimens(args[1].As<Object>(), (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<Value> *argv;
|
||||
Local<Function> callback = bindings.callback->GetFunction();
|
||||
Local<Object> buf;
|
||||
bindings.result = -1;
|
||||
|
||||
switch (bindings.op) {
|
||||
case OP_INIT:
|
||||
argv = (Local<Value>[]) {callback};
|
||||
argc = 1;
|
||||
fn = bindings.ops_init;
|
||||
break;
|
||||
|
||||
case OP_STATFS:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_statfs;
|
||||
break;
|
||||
|
||||
case OP_FGETATTR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_fgetattr;
|
||||
break;
|
||||
|
||||
case OP_GETATTR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_getattr;
|
||||
break;
|
||||
|
||||
case OP_READDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_readdir;
|
||||
break;
|
||||
|
||||
case OP_CREATE:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_create;
|
||||
break;
|
||||
|
||||
case OP_TRUNCATE:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.offset), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_truncate;
|
||||
break;
|
||||
|
||||
case OP_FTRUNCATE:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), NanNew<Number>(bindings.offset), callback};
|
||||
argc = 4;
|
||||
fn = bindings.ops_ftruncate;
|
||||
break;
|
||||
|
||||
case OP_ACCESS:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_access;
|
||||
break;
|
||||
|
||||
case OP_OPEN:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_open;
|
||||
break;
|
||||
|
||||
case OP_OPENDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_opendir;
|
||||
break;
|
||||
|
||||
case OP_WRITE:
|
||||
buf = NanNew(bindings.buffer_persistent);
|
||||
buf->Set(NanNew<String>("length"), NanNew<Number>(bindings.length));
|
||||
buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length);
|
||||
|
||||
argv = (Local<Value>[]) {
|
||||
NanNew<String>(bindings.path),
|
||||
NanNew<Number>(bindings.info->fh),
|
||||
buf,
|
||||
NanNew<Number>(bindings.length),
|
||||
NanNew<Number>(bindings.offset),
|
||||
callback
|
||||
};
|
||||
argc = 6;
|
||||
fn = bindings.ops_write;
|
||||
break;
|
||||
|
||||
case OP_READ:
|
||||
buf = NanNew(bindings.buffer_persistent);
|
||||
buf->Set(NanNew<String>("length"), NanNew<Number>(bindings.length));
|
||||
buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length);
|
||||
|
||||
argv = (Local<Value>[]) {
|
||||
NanNew<String>(bindings.path),
|
||||
NanNew<Number>(bindings.info->fh),
|
||||
buf,
|
||||
NanNew<Number>(bindings.length),
|
||||
NanNew<Number>(bindings.offset),
|
||||
callback
|
||||
};
|
||||
argc = 6;
|
||||
fn = bindings.ops_read;
|
||||
break;
|
||||
|
||||
case OP_RELEASE:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_release;
|
||||
break;
|
||||
|
||||
case OP_RELEASEDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_releasedir;
|
||||
break;
|
||||
|
||||
case OP_UNLINK:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_unlink;
|
||||
break;
|
||||
|
||||
case OP_RENAME:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<String>((char *) bindings.data), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_rename;
|
||||
break;
|
||||
|
||||
case OP_LINK:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<String>((char *) bindings.data), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_link;
|
||||
break;
|
||||
|
||||
case OP_SYMLINK:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<String>((char *) bindings.data), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_symlink;
|
||||
break;
|
||||
|
||||
case OP_CHMOD:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_chmod;
|
||||
break;
|
||||
|
||||
case OP_CHOWN:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.uid), NanNew<Number>(bindings.gid), callback};
|
||||
argc = 4;
|
||||
fn = bindings.ops_chown;
|
||||
break;
|
||||
|
||||
case OP_READLINK:
|
||||
buf = NanNew(bindings.buffer_persistent);
|
||||
buf->Set(NanNew<String>("length"), NanNew<Number>(bindings.length));
|
||||
buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length);
|
||||
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), buf, NanNew<Number>(bindings.length), callback};
|
||||
argc = 4;
|
||||
fn = bindings.ops_readlink;
|
||||
break;
|
||||
|
||||
case OP_SETXATTR:
|
||||
buf = NanNew(bindings.buffer_persistent);
|
||||
buf->Set(NanNew<String>("length"), NanNew<Number>(bindings.length));
|
||||
buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length);
|
||||
|
||||
argv = (Local<Value>[]) {
|
||||
NanNew<String>(bindings.path),
|
||||
NanNew<String>(bindings.name),
|
||||
buf,
|
||||
NanNew<Number>(bindings.length),
|
||||
NanNew<Number>(bindings.offset),
|
||||
NanNew<Number>(bindings.mode),
|
||||
callback
|
||||
};
|
||||
argc = 7;
|
||||
fn = bindings.ops_setxattr;
|
||||
break;
|
||||
|
||||
case OP_GETXATTR:
|
||||
buf = NanNew(bindings.buffer_persistent);
|
||||
buf->Set(NanNew<String>("length"), NanNew<Number>(bindings.length));
|
||||
buf->SetIndexedPropertiesToExternalArrayData((char *) bindings.data, kExternalUnsignedByteArray, bindings.length);
|
||||
|
||||
argv = (Local<Value>[]) {
|
||||
NanNew<String>(bindings.path),
|
||||
NanNew<String>(bindings.name),
|
||||
buf,
|
||||
NanNew<Number>(bindings.length),
|
||||
NanNew<Number>(bindings.offset),
|
||||
callback
|
||||
};
|
||||
argc = 6;
|
||||
fn = bindings.ops_getxattr;
|
||||
break;
|
||||
|
||||
case OP_MKDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_mkdir;
|
||||
break;
|
||||
|
||||
case OP_RMDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_rmdir;
|
||||
break;
|
||||
|
||||
case OP_DESTROY:
|
||||
argv = (Local<Value>[]) {callback};
|
||||
argc = 1;
|
||||
fn = bindings.ops_destroy;
|
||||
break;
|
||||
|
||||
case OP_UTIMENS:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), callback};
|
||||
argc = 2;
|
||||
fn = bindings.ops_utimens;
|
||||
break;
|
||||
|
||||
case OP_FLUSH:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), callback};
|
||||
argc = 3;
|
||||
fn = bindings.ops_flush;
|
||||
break;
|
||||
|
||||
case OP_FSYNC:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), NanNew<Number>(bindings.mode), callback};
|
||||
argc = 4;
|
||||
fn = bindings.ops_fsync;
|
||||
break;
|
||||
|
||||
case OP_FSYNCDIR:
|
||||
argv = (Local<Value>[]) {NanNew<String>(bindings.path), NanNew<Number>(bindings.info->fh), NanNew<Number>(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<String>());
|
||||
Local<Object> ops = args[1].As<Object>();
|
||||
|
||||
bindings.ops_init = ops->Has(NanNew<String>("init")) ? new NanCallback(ops->Get(NanNew<String>("init")).As<Function>()) : NULL;
|
||||
bindings.ops_access = ops->Has(NanNew<String>("access")) ? new NanCallback(ops->Get(NanNew<String>("access")).As<Function>()) : NULL;
|
||||
bindings.ops_statfs = ops->Has(NanNew<String>("statfs")) ? new NanCallback(ops->Get(NanNew<String>("statfs")).As<Function>()) : NULL;
|
||||
bindings.ops_getattr = ops->Has(NanNew<String>("getattr")) ? new NanCallback(ops->Get(NanNew<String>("getattr")).As<Function>()) : NULL;
|
||||
bindings.ops_fgetattr = ops->Has(NanNew<String>("fgetattr")) ? new NanCallback(ops->Get(NanNew<String>("fgetattr")).As<Function>()) : NULL;
|
||||
bindings.ops_flush = ops->Has(NanNew<String>("flush")) ? new NanCallback(ops->Get(NanNew<String>("flush")).As<Function>()) : NULL;
|
||||
bindings.ops_fsync = ops->Has(NanNew<String>("fsync")) ? new NanCallback(ops->Get(NanNew<String>("fsync")).As<Function>()) : NULL;
|
||||
bindings.ops_fsyncdir = ops->Has(NanNew<String>("fsyncdir")) ? new NanCallback(ops->Get(NanNew<String>("fsyncdir")).As<Function>()) : NULL;
|
||||
bindings.ops_readdir = ops->Has(NanNew<String>("readdir")) ? new NanCallback(ops->Get(NanNew<String>("readdir")).As<Function>()) : NULL;
|
||||
bindings.ops_truncate = ops->Has(NanNew<String>("truncate")) ? new NanCallback(ops->Get(NanNew<String>("truncate")).As<Function>()) : NULL;
|
||||
bindings.ops_ftruncate = ops->Has(NanNew<String>("ftruncate")) ? new NanCallback(ops->Get(NanNew<String>("ftruncate")).As<Function>()) : NULL;
|
||||
bindings.ops_readlink = ops->Has(NanNew<String>("readlink")) ? new NanCallback(ops->Get(NanNew<String>("readlink")).As<Function>()) : NULL;
|
||||
bindings.ops_chown = ops->Has(NanNew<String>("chown")) ? new NanCallback(ops->Get(NanNew<String>("chown")).As<Function>()) : NULL;
|
||||
bindings.ops_chmod = ops->Has(NanNew<String>("chmod")) ? new NanCallback(ops->Get(NanNew<String>("chmod")).As<Function>()) : NULL;
|
||||
bindings.ops_setxattr = ops->Has(NanNew<String>("setxattr")) ? new NanCallback(ops->Get(NanNew<String>("setxattr")).As<Function>()) : NULL;
|
||||
bindings.ops_getxattr = ops->Has(NanNew<String>("getxattr")) ? new NanCallback(ops->Get(NanNew<String>("getxattr")).As<Function>()) : NULL;
|
||||
bindings.ops_open = ops->Has(NanNew<String>("open")) ? new NanCallback(ops->Get(NanNew<String>("open")).As<Function>()) : NULL;
|
||||
bindings.ops_opendir = ops->Has(NanNew<String>("opendir")) ? new NanCallback(ops->Get(NanNew<String>("opendir")).As<Function>()) : NULL;
|
||||
bindings.ops_read = ops->Has(NanNew<String>("read")) ? new NanCallback(ops->Get(NanNew<String>("read")).As<Function>()) : NULL;
|
||||
bindings.ops_write = ops->Has(NanNew<String>("write")) ? new NanCallback(ops->Get(NanNew<String>("write")).As<Function>()) : NULL;
|
||||
bindings.ops_release = ops->Has(NanNew<String>("release")) ? new NanCallback(ops->Get(NanNew<String>("release")).As<Function>()) : NULL;
|
||||
bindings.ops_releasedir = ops->Has(NanNew<String>("releasedir")) ? new NanCallback(ops->Get(NanNew<String>("releasedir")).As<Function>()) : NULL;
|
||||
bindings.ops_create = ops->Has(NanNew<String>("create")) ? new NanCallback(ops->Get(NanNew<String>("create")).As<Function>()) : NULL;
|
||||
bindings.ops_utimens = ops->Has(NanNew<String>("utimens")) ? new NanCallback(ops->Get(NanNew<String>("utimens")).As<Function>()) : NULL;
|
||||
bindings.ops_unlink = ops->Has(NanNew<String>("unlink")) ? new NanCallback(ops->Get(NanNew<String>("unlink")).As<Function>()) : NULL;
|
||||
bindings.ops_rename = ops->Has(NanNew<String>("rename")) ? new NanCallback(ops->Get(NanNew<String>("rename")).As<Function>()) : NULL;
|
||||
bindings.ops_link = ops->Has(NanNew<String>("link")) ? new NanCallback(ops->Get(NanNew<String>("link")).As<Function>()) : NULL;
|
||||
bindings.ops_symlink = ops->Has(NanNew<String>("symlink")) ? new NanCallback(ops->Get(NanNew<String>("symlink")).As<Function>()) : NULL;
|
||||
bindings.ops_mkdir = ops->Has(NanNew<String>("mkdir")) ? new NanCallback(ops->Get(NanNew<String>("mkdir")).As<Function>()) : NULL;
|
||||
bindings.ops_rmdir = ops->Has(NanNew<String>("rmdir")) ? new NanCallback(ops->Get(NanNew<String>("rmdir")).As<Function>()) : NULL;
|
||||
bindings.ops_destroy = ops->Has(NanNew<String>("destroy")) ? new NanCallback(ops->Get(NanNew<String>("destroy")).As<Function>()) : NULL;
|
||||
|
||||
NanAssignPersistent(bindings.buffer_persistent, args[2].As<Object>());
|
||||
|
||||
bindings.callback = new NanCallback(NanNew<FunctionTemplate>(OpCallback)->GetFunction());
|
||||
stpcpy(bindings.mnt, path);
|
||||
stpcpy(bindings.mntopts, "-o");
|
||||
|
||||
Local<Array> options = ops->Get(NanNew<String>("options")).As<Array>();
|
||||
if (options->IsArray()) {
|
||||
for (uint32_t i = 0; i < options->Length(); i++) bindings_append_opt((char *) *NanUtf8String(options->Get(i).As<String>()));
|
||||
}
|
||||
|
||||
// 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<String>());
|
||||
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<String>());
|
||||
Local<Function> callback = args[1].As<Function>();
|
||||
|
||||
char *path_alloc = (char *) malloc(1024);
|
||||
stpcpy(path_alloc, path);
|
||||
|
||||
NanAsyncQueueWorker(new UnmountWorker(new NanCallback(callback), path_alloc));
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
||||
void Init(Handle<Object> exports) {
|
||||
exports->Set(NanNew("mount"), NanNew<FunctionTemplate>(Mount)->GetFunction());
|
||||
exports->Set(NanNew("unmount"), NanNew<FunctionTemplate>(Unmount)->GetFunction());
|
||||
exports->Set(NanNew("unmountSync"), NanNew<FunctionTemplate>(UnmountSync)->GetFunction());
|
||||
}
|
||||
|
||||
NODE_MODULE(fuse_bindings, Init)
|
150
index.js
Normal file
150
index.js
Normal file
@ -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
|
25
package.json
Normal file
25
package.json
Normal file
@ -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"
|
||||
}
|
Loading…
Reference in New Issue
Block a user