mirror of
				https://github.com/fuse-friends/fuse-native
				synced 2025-06-13 12:53:54 +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