diff --git a/binding.gyp b/binding.gyp index 0d91380..2ff2ef7 100644 --- a/binding.gyp +++ b/binding.gyp @@ -10,7 +10,8 @@ ], "sources": [ "fuse-native.c" - ] + ], + "cflags": ["-rdynamic"] }, { "target_name": "postinstall", "type": "none", diff --git a/example.js b/example.js index a8592ca..ff4b6a0 100644 --- a/example.js +++ b/example.js @@ -60,7 +60,7 @@ fuse.mount(err => { console.log('filesystem mounted on ' + fuse.mnt) }) -process.on('SIGINT', function () { +process.once('SIGINT', function () { fuse.unmount(err => { if (err) { console.log('filesystem at ' + fuse.mnt + ' not unmounted', err) diff --git a/fuse-native.c b/fuse-native.c index 9af91dc..91354d4 100644 --- a/fuse-native.c +++ b/fuse-native.c @@ -1,16 +1,17 @@ #define FUSE_USE_VERSION 29 -#include "semaphore.h" - #include #include #include +#include #include + #include #include #include +#include #include #include @@ -29,14 +30,11 @@ napi_close_handle_scope(env, scope); #define FUSE_NATIVE_HANDLER(name, blk)\ - struct fuse_context *ctx = fuse_get_context();\ - fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data;\ fuse_thread_locals_t *l = get_thread_locals();\ - l->fuse = ft;\ l->op = op_##name;\ blk\ uv_async_send(&(l->async));\ - fuse_native_semaphore_wait(&(l->sem));\ + uv_sem_wait(&(l->sem));\ return l->res; #define FUSE_METHOD(name, callbackArgs, signalArgs, signature, callBlk, callbackBlk, signalBlk)\ @@ -57,7 +55,7 @@ int ret = NULL;\ signalBlk\ l->res = ret ? ret : res;\ - fuse_native_semaphore_signal(&(l->sem));\ + uv_sem_post(&(l->sem));\ return ret;\ }\ static int fuse_native_##name signature {\ @@ -115,8 +113,13 @@ typedef struct { struct fuse *fuse; struct fuse_chan *ch; - bool mounted; + char* mnt; + char* mntopts; + int mounted; + uv_async_t async; + uv_mutex_t mut; + uv_sem_t sem; } fuse_thread_t; typedef struct { @@ -156,7 +159,7 @@ typedef struct { // Internal bookkeeping fuse_thread_t *fuse; - fuse_native_semaphore_t sem; + uv_sem_t sem; uv_async_t async; } fuse_thread_locals_t; @@ -764,27 +767,49 @@ static void fuse_native_dispatch (uv_async_t* handle, int status) { } } +static void fuse_native_async_init (uv_async_t* handle, int status) { + fuse_thread_locals_t *l = (fuse_thread_locals_t *) handle->data; + fuse_thread_t *ft = l->fuse; + + int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch); + uv_unref(&(l->async)); + + uv_sem_init(&(l->sem), 0); + l->async.data = l; + + uv_sem_post(&(ft->sem)); + + if (err < 0) { + printf("uv_async_init failed: %i\n", err); + return NULL; + } +} + static fuse_thread_locals_t* get_thread_locals () { + struct fuse_context *ctx = fuse_get_context(); + fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; + void *data = pthread_getspecific(thread_locals_key); if (data != NULL) { - return (fuse_thread_locals_t *) data; + return (fuse_thread_locals_t *)data; } fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t)); + l->fuse = ft; - // TODO: mutex me?? - int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch); + // Need to lock the mutation of l->async. + uv_mutex_lock(&(ft->mut)); + ft->async.data = l; - l->async.data = l; + // Notify the main thread to uv_async_init l->async. + uv_async_send(&(ft->async)); + uv_sem_wait(&(ft->sem)); - if (err < 0) { - printf("uv_async failed: %i\n", err); - return NULL; - } + l->async.data = l; - fuse_native_semaphore_init(&(l->sem)); pthread_setspecific(thread_locals_key, (void *) l); + uv_mutex_unlock(&(ft->mut)); return l; } @@ -793,10 +818,9 @@ static void* start_fuse_thread (void *data) { fuse_thread_t *ft = (fuse_thread_t *) data; fuse_loop_mt(ft->fuse); - // printf("her nu\n"); - // fuse_unmount(mnt, ch); - // fuse_session_remove_chan(ch); - // fuse_destroy(fuse); + fuse_unmount(ft->mnt, ft->ch); + fuse_session_remove_chan(ft->ch); + fuse_destroy(ft->fuse); return NULL; } @@ -816,14 +840,12 @@ NAPI_METHOD(fuse_native_mount) { } NAPI_FOR_EACH(handlers, handler) { - printf("creating reference for handler: %d\n", i); napi_create_reference(env, handler, 1, &ft->handlers[i]); } ft->env = env; struct fuse_operations ops = { }; - if (implemented[op_access]) ops.access = fuse_native_access; if (implemented[op_truncate]) ops.truncate = fuse_native_truncate; if (implemented[op_ftruncate]) ops.ftruncate = fuse_native_ftruncate; @@ -875,11 +897,18 @@ NAPI_METHOD(fuse_native_mount) { struct fuse *fuse = fuse_new(ch, &args, &ops, sizeof(struct fuse_operations), ft); + uv_mutex_init(&(ft->mut)); + uv_sem_init(&(ft->sem), 0); + + ft->mnt = mnt; + ft->mntopts = mntopts; ft->fuse = fuse; ft->ch = ch; - ft->mounted = true; + ft->mounted++; + + int err = uv_async_init(uv_default_loop(), &(ft->async), (uv_async_cb) fuse_native_async_init); - if (fuse == NULL) { + if (fuse == NULL || err < 0) { napi_throw_error(env, "fuse failed", "fuse failed"); return NULL; } @@ -896,12 +925,11 @@ NAPI_METHOD(fuse_native_unmount) { NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 1); if (ft != NULL && ft->mounted) { - fuse_unmount(mnt, ft->ch); - printf("joining\n"); pthread_join(ft->thread, NULL); - printf("joined\n"); } - ft->mounted = false; + + uv_unref(&(ft->async)); + ft->mounted--; return NULL; } diff --git a/index.js b/index.js index e2d7356..06171c1 100644 --- a/index.js +++ b/index.js @@ -1,142 +1,143 @@ const os = require('os') const fs = require('fs') const path = require('path') +const { exec } = require('child_process') + +const Nanoresource = require('nanoresource') +const binding = require('node-gyp-build')(__dirname) const IS_OSX = os.platform() === 'darwin' const OSX_FOLDER_ICON = '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericFolderIcon.icns' - const HAS_FOLDER_ICON = IS_OSX && fs.existsSync(OSX_FOLDER_ICON) -const binding = require('node-gyp-build')(__dirname) const OpcodesAndDefaults = new Map([ ['init', { - op: 0 + op: binding.op_init }], ['error', { - op: 1 + op: binding.op_error }], ['access', { - op: 2, + op: binding.op_access, defaults: [0] }], ['statfs', { - op: 3, + op: binding.op_statfs, defaults: [getStatfsArray()] }], ['fgetattr', { - op: 4, + op: binding.op_fgetattr, defaults: [getStatArray()] }], ['getattr', { - op: 5, + op: binding.op_getattr, defaults: [getStatArray()] }], ['flush', { - op: 6 + op: binding.op_flush }], ['fsync', { - op: 7 + op: binding.op_fsync }], ['fsyncdir', { - op: 8 + op: binding.op_fsyncdir }], ['readdir', { - op: 9 + op: binding.op_readdir }], ['truncate', { - op: 10 + op: binding.op_truncate }], ['ftruncate', { - op: 11 + op: binding.op_ftruncate }], ['utimens', { - op: 12 + op: binding.op_utimens }], ['readlink', { - op: 13, + op: binding.op_readlink, defaults: [''] }], ['chown', { - op: 14 + op: binding.op_chown }], ['chmod', { - op: 15 + op: binding.op_chmod }], ['mknod', { - op: 16 + op: binding.op_mknod }], ['setxattr', { - op: 17 + op: binding.op_setxattr }], ['getxattr', { - op: 18 + op: binding.op_getxattr }], ['listxattr', { - op: 19 + op: binding.op_listxattr }], ['removexattr', { - op: 20 + op: binding.op_removexattr }], ['open', { - op: 21, + op: binding.op_open, defaults: [0] }], ['opendir', { - op: 22, + op: binding.op_opendir, defaults: [0] }], ['read', { - op: 23, + op: binding.op_read, defaults: [0] }], ['write', { - op: 24, + op: binding.op_write, defaults: [0] }], ['release', { - op: 25 + op: binding.op_release }], ['releasedir', { - op: 26 + op: binding.op_releasedir }], ['create', { - op: 27 + op: binding.op_create }], ['unlink', { - op: 28 + op: binding.op_unlink }], ['rename', { - op: 29 + op: binding.op_rename }], ['link', { - op: 30 + op: binding.op_link }], ['symlink', { - op: 31 + op: binding.op_symlink }], ['mkdir', { - op: 32 + op: binding.op_mkdir }], ['rmdir', { - op: 33 + op: binding.op_rmdir }], ['destroy', { - op: 34 + op: binding.op_destroy }] ]) -class Fuse { +class Fuse extends Nanoresource { constructor (mnt, ops, opts = {}) { + super() this.opts = opts this.mnt = path.resolve(mnt) this.ops = ops - this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t) + this._thread = null this._handlers = this._makeHandlerArray() - // Keep the process alive while fuse is mounted. - this._timer = null - const implemented = [0, 1, 5] + const implemented = [binding.op_init, binding.op_error, binding.op_getattr] if (ops) { for (const [name, { op }] of OpcodesAndDefaults) { if (ops[name]) implemented.push(op) @@ -150,7 +151,7 @@ class Fuse { _getImplementedArray () { const implemented = new Uint32Array(35) - for (const impl of [...this._implemented]) { + for (const impl of this._implemented) { implemented[impl] = 1 } return implemented @@ -191,16 +192,6 @@ class Fuse { return options.map(o => '-o' + o).join(' ') } - _signal (signalFunc, args) { - /* - if (this._sync) process.nextTick(() => signalFunc.apply(null, args)) - else signalFunc.apply(null, args) - */ - process.nextTick(() => signalFunc.apply(null, args)) - } - - // Handlers - _makeHandlerArray () { const self = this const handlers = new Array(OpcodesAndDefaults.size) @@ -217,7 +208,7 @@ class Fuse { function makeHandler (name, op, defaults, nativeSignal) { return function () { const boundSignal = signal.bind(null, arguments[0]) - const funcName = `_${name}` + const funcName = `_op_${name}` if (!self[funcName] || !self._implemented.has(op)) return boundSignal(-1, ...defaults) return self[funcName].apply(self, [boundSignal, ...[...arguments].slice(2)]) } @@ -230,7 +221,57 @@ class Fuse { } } - _init (signal) { + // Lifecycle methods + + _open (cb) { + this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t) + this._openCallback = cb + + const opts = this._fuseOptions() + const implemented = this._getImplementedArray() + + return fs.stat(this.mnt, (err, stat) => { + if (err) return cb(new Error('Mountpoint does not exist')) + if (!stat.isDirectory()) return cb(new Error('Mountpoint is not a directory')) + return fs.stat(path.join(this.mnt, '..'), (_, parent) => { + if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) + try { + // TODO: asyncify + binding.fuse_native_mount(this.mnt, opts, this._thread, this, this._handlers, implemented) + } catch (err) { + return cb(err) + } + }) + }) + } + + _close (cb) { + const self = this + const mnt = JSON.stringify(this.mnt) + const cmd = os.platform() === 'darwin' ? `umount ${mnt}` : `fusermount -q -u ${mnt}` + + exec(cmd, err => { + if (err) return cb(err) + return nativeUnmount() + }) + + function nativeUnmount () { + try { + binding.fuse_native_unmount(self.mnt, self._thread) + } catch (err) { + return cb(err) + } + return cb(null) + } + } + + // Handlers + + _op_init (signal) { + if (this._openCallback) { + process.nextTick(this._openCallback, null) + this._openCallback = null + } if (!this.ops.init) { signal(0) return @@ -240,7 +281,7 @@ class Fuse { }) } - _error (signal) { + _op_error (signal) { if (!this.ops.error) { signal(0) return @@ -250,7 +291,7 @@ class Fuse { }) } - _statfs (signal) { + _op_statfs (signal) { this.ops.statfs((err, statfs) => { if (err) return signal(err) const arr = getStatfsArray(statfs) @@ -258,7 +299,7 @@ class Fuse { }) } - _getattr (signal, path) { + _op_getattr (signal, path) { if (!this.ops.getattr) { if (path !== '/') { signal(Fuse.EPERM) @@ -273,7 +314,7 @@ class Fuse { }) } - _fgetattr (signal, path, fd) { + _op_fgetattr (signal, path, fd) { if (!this.ops.fgetattr) { if (path !== '/') { signal(Fuse.EPERM) @@ -288,31 +329,31 @@ class Fuse { }) } - _access (signal, path, mode) { + _op_access (signal, path, mode) { this.ops.access(path, mode, err => { return signal(err) }) } - _open (signal, path, flags) { + _op_open (signal, path, flags) { this.ops.open(path, flags, (err, fd) => { return signal(err, fd) }) } - _opendir (signal, path, flags) { + _op_opendir (signal, path, flags) { this.ops.opendir(path, flags, (err, fd) => { return signal(err, fd) }) } - _create (signal, path, mode) { + _op_create (signal, path, mode) { this.ops.create(path, mode, (err, fd) => { return signal(err, fd) }) } - _utimens (signal, path, atim, mtim) { + _op_utimens (signal, path, atim, mtim) { atim = getDoubleInt(atim, 0) mtim = getDoubleInt(mtim, 0) this.ops.utimens(path, atim, mtim, err => { @@ -320,31 +361,31 @@ class Fuse { }) } - _release (signal, path, fd) { + _op_release (signal, path, fd) { this.ops.release(path, fd, err => { return signal(err) }) } - _releasedir (signal, path, fd) { + _op_releasedir (signal, path, fd) { this.ops.releasedir(path, fd, err => { return signal(err) }) } - _read (signal, path, fd, buf, len, offset) { + _op_read (signal, path, fd, buf, len, offset) { this.ops.read(path, fd, buf, len, offset, (err, bytesRead) => { return signal(err, bytesRead) }) } - _write (signal, path, fd, buf, len, offset) { + _op_write (signal, path, fd, buf, len, offset) { this.ops.write(path, fd, buf, len, offset, (err, bytesWritten) => { return signal(err, bytesWritten) }) } - _readdir (signal, path) { + _op_readdir (signal, path) { this.ops.readdir(path, (err, names, stats) => { if (err) return signal(err) if (stats) stats = stats.map(getStatArray) @@ -352,121 +393,121 @@ class Fuse { }) } - _setxattr (signal, path, name, value, size, position, flags) { + _op_setxattr (signal, path, name, value, size, position, flags) { this.ops.setxattr(path, name, value, size, position, flags, err => { return signal(err) }) } - _getxattr (signal, path, name, value, size, position) { + _op_getxattr (signal, path, name, value, size, position) { this.ops.getxattr(path, name, value, size, position, err => { return signal(err) }) } - _listxattr (signal, path, list, size) { + _op_listxattr (signal, path, list, size) { this.ops.listxattr(path, list, size, err => { return signal(err) }) } - _removexattr (signal, path, name) { + _op_removexattr (signal, path, name) { this.ops.removexattr(path, name, err => { return signal(err) }) } - _flush (signal, path, datasync, fd) { + _op_flush (signal, path, datasync, fd) { this.ops.flush(path, datasync, fd, err => { return signal(err) }) } - _fsync (signal, path, datasync, fd) { + _op_fsync (signal, path, datasync, fd) { this.ops.fsync(path, datasync, fd, err => { return signal(err) }) } - _fsyncdir (signal, path, datasync, fd) { + _op_fsyncdir (signal, path, datasync, fd) { this.ops.fsyncdir(path, datasync, fd, err => { return signal(err) }) } - _truncate (signal, path, size) { + _op_truncate (signal, path, size) { this.ops.truncate(path, size, err => { return signal(err) }) } - _ftruncate (signal, path, size, fd) { + _op_ftruncate (signal, path, size, fd) { this.ops.ftruncate(path, size, fd, err => { return signal(err) }) } - _readlink (signal, path) { + _op_readlink (signal, path) { this.ops.readlink(path, (err, linkname) => { return signal(err, linkname) }) } - _chown (signal, path, uid, gid) { + _op_chown (signal, path, uid, gid) { this.ops.chown(path, uid, gid, err => { return signal(err) }) } - _chmod (signal, path, mode) { + _op_chmod (signal, path, mode) { this.ops.chmod(path, mode, err => { return signal(err) }) } - _mknod (signal, path, mode, dev) { + _op_mknod (signal, path, mode, dev) { this.ops.mknod(path, mode, dev, err => { return signal(err) }) } - _unlink (signal, path) { + _op_unlink (signal, path) { this.ops.unlink(path, err => { return signal(err) }) } - _rename (signal, src, dest, flags) { + _op_rename (signal, src, dest, flags) { this.ops.rename(src, dest, flags, err => { return signal(err) }) } - _link (signal, src, dest) { + _op_link (signal, src, dest) { this.ops.link(src, dest, err => { return signal(err) }) } - _symlink (signal, src, dest) { + _op_symlink (signal, src, dest) { this.ops.symlink(src, dest, err => { return signal(err) }) } - _mkdir (signal, path, mode) { + _op_mkdir (signal, path, mode) { this.ops.mkdir(path, mode, err => { return signal(err) }) } - _rmdir (signal, path) { + _op_rmdir (signal, path) { this.ops.rmdir(path, err => { return signal(err) }) } - _destroy (signal) { + _op_destroy (signal) { this.ops.destroy(err => { return signal(err) }) @@ -475,35 +516,11 @@ class Fuse { // Public API mount (cb) { - const opts = this._fuseOptions() - const implemented = this._getImplementedArray() - fs.stat(this.mnt, (err, stat) => { - if (err) return cb(new Error('Mountpoint does not exist')) - if (!stat.isDirectory()) return cb(new Error('Mountpoint is not a directory')) - fs.stat(path.join(this.mnt, '..'), (_, parent) => { - if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) - try { - // TODO: asyncify - binding.fuse_native_mount(this.mnt, opts, this._thread, this, this._handlers, implemented) - } catch (err) { - return cb(err) - } - this._timer = setInterval(() => {}, 10000) - return cb(null) - }) - }) + return this._open(cb) } unmount (cb) { - // TODO: asyncify - try { - binding.fuse_native_unmount(this.mnt, this._thread) - } catch (err) { - clearInterval(this._timer) - return process.nextTick(cb, err) - } - clearInterval(this._timer) - return process.nextTick(cb, null) + return this._close(cb) } errno (code) { diff --git a/package.json b/package.json index df0dad3..7b5b620 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,17 @@ "main": "index.js", "scripts": { "install": "node-gyp-build", - "test": "standard && test/*.js", + "test": "tape test/*.js", "prebuild": "prebuildify -a --strip", "prebuild-ia32": "prebuildify -a --strip --arch=ia32" }, "gypfile": true, "dependencies": { "fuse-shared-library": "^1.0.1", + "nanoresource": "^1.2.0", "napi-macros": "^2.0.0", - "node-gyp-build": "^3.2.2" + "node-gyp-build": "^3.2.2", + "why-is-node-running": "^2.1.0" }, "devDependencies": { "concat-stream": "^2.0.0", diff --git a/test/links.js b/test/links.js index 411bcb4..ac4b35d 100644 --- a/test/links.js +++ b/test/links.js @@ -10,26 +10,26 @@ tape('readlink', function (t) { var ops = { force: true, readdir: function (path, cb) { - if (path === '/') return cb(null, ['hello', 'link']) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, ['hello', 'link']) + return process.nextTick(cb, Fuse.ENOENT) }, readlink: function (path, cb) { - cb(0, 'hello') + process.nextTick(cb, 0, 'hello') }, getattr: function (path, cb) { - if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 })) - if (path === '/hello') return cb(null, stat({ mode: 'file', size: 11 })) - if (path === '/link') return cb(null, stat({ mode: 'link', size: 5 })) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 })) + if (path === '/hello') return process.nextTick(cb, null, stat({ mode: 'file', size: 11 })) + if (path === '/link') return process.nextTick(cb, null, stat({ mode: 'link', size: 5 })) + return process.nextTick(cb, Fuse.ENOENT) }, open: function (path, flags, cb) { - cb(0, 42) + process.nextTick(cb, 0, 42) }, read: function (path, fd, buf, len, pos, cb) { var str = 'hello world'.slice(pos, pos + len) - if (!str) return cb(0) + if (!str) return process.nextTick(cb, 0) buf.write(str) - return cb(str.length) + return process.nextTick(cb, str.length) } } @@ -51,9 +51,9 @@ tape('readlink', function (t) { fs.readFile(path.join(mnt, 'link'), function (err, buf) { t.error(err, 'no error') - t.same(buf, new Buffer('hello world'), 'can read link content') + t.same(buf, Buffer.from('hello world'), 'can read link content') - fuse.unmount( function () { + fuse.unmount(function () { t.end() }) }) diff --git a/test/misc.js b/test/misc.js index 49ad64a..f7fda39 100644 --- a/test/misc.js +++ b/test/misc.js @@ -1,26 +1,31 @@ var mnt = require('./fixtures/mnt') -var fuse = require('../') var tape = require('tape') +var Fuse = require('../') + tape('mount', function (t) { - fuse.mount(mnt, { force: true }, function (err) { + const fuse = new Fuse(mnt, {}, { force: true }) + fuse.mount(function (err) { t.error(err, 'no error') t.ok(true, 'works') - fuse.unmount(mnt, function () { + fuse.unmount(function () { t.end() }) }) }) tape('mount + unmount + mount', function (t) { - fuse.mount(mnt, { force: true }, function (err) { + const fuse1 = new Fuse(mnt, {}, { force: true, debug: false }) + const fuse2 = new Fuse(mnt, {}, { force: true, debug: false }) + + fuse1.mount(function (err) { t.error(err, 'no error') t.ok(true, 'works') - fuse.unmount(mnt, function () { - fuse.mount(mnt, { force: true }, function (err) { + fuse1.unmount(function () { + fuse2.mount(function (err) { t.error(err, 'no error') t.ok(true, 'works') - fuse.unmount(mnt, function () { + fuse2.unmount(function () { t.end() }) }) @@ -29,14 +34,16 @@ tape('mount + unmount + mount', function (t) { }) tape('mnt point must exist', function (t) { - fuse.mount(mnt + '.does-not-exist', {}, function (err) { + const fuse = new Fuse('.does-not-exist', {}, { debug: false }) + fuse.mount(function (err) { t.ok(err, 'had error') t.end() }) }) tape('mnt point must be directory', function (t) { - fuse.mount(__filename, {}, function (err) { + const fuse = new Fuse(__filename, {}, { debug: false }) + fuse.mount(function (err) { t.ok(err, 'had error') t.end() }) diff --git a/test/read.js b/test/read.js index efcb980..96be7f5 100644 --- a/test/read.js +++ b/test/read.js @@ -11,27 +11,27 @@ tape('read', function (t) { var ops = { force: true, readdir: function (path, cb) { - if (path === '/') return cb(null, ['test']) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, ['test']) + return process.nextTick(cb, Fuse.ENOENT) }, getattr: function (path, cb) { - if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 })) - if (path === '/test') return cb(null, stat({ mode: 'file', size: 11 })) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 })) + if (path === '/test') return process.nextTick(cb, null, stat({ mode: 'file', size: 11 })) + return process.nextTick(cb, Fuse.ENOENT) }, open: function (path, flags, cb) { - cb(0, 42) + return process.nextTick(cb, 0, 42) }, release: function (path, fd, cb) { - + console.log('IN JS RELEASE') t.same(fd, 42, 'fd was passed to release') - cb(0) + return process.nextTick(cb, 0) }, read: function (path, fd, buf, len, pos, cb) { var str = 'hello world'.slice(pos, pos + len) - if (!str) return cb(0) + if (!str) return process.nextTick(cb, 0) buf.write(str) - return cb(str.length) + return process.nextTick(cb, str.length) } } @@ -41,17 +41,17 @@ tape('read', function (t) { fs.readFile(path.join(mnt, 'test'), function (err, buf) { t.error(err, 'no error') - t.same(buf, new Buffer('hello world'), 'read file') + t.same(buf, Buffer.from('hello world'), 'read file') fs.readFile(path.join(mnt, 'test'), function (err, buf) { t.error(err, 'no error') - t.same(buf, new Buffer('hello world'), 'read file again') + t.same(buf, Buffer.from('hello world'), 'read file again') fs.createReadStream(path.join(mnt, 'test'), { start: 0, end: 4 }).pipe(concat(function (buf) { - t.same(buf, new Buffer('hello'), 'partial read file') + t.same(buf, Buffer.from('hello'), 'partial read file') fs.createReadStream(path.join(mnt, 'test'), { start: 6, end: 10 }).pipe(concat(function (buf) { - t.same(buf, new Buffer('world'), 'partial read file + start offset') + t.same(buf, Buffer.from('world'), 'partial read file + start offset') fuse.unmount(function () { t.end() diff --git a/test/write.js b/test/write.js index 12102bf..7239598 100644 --- a/test/write.js +++ b/test/write.js @@ -8,35 +8,35 @@ const stat = require('./fixtures/stat') tape('write', function (t) { var created = false - var data = new Buffer(1024) + var data = Buffer.alloc(1024) var size = 0 var ops = { force: true, readdir: function (path, cb) { - if (path === '/') return cb(null, created ? ['hello'] : []) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, created ? ['hello'] : [], []) + return process.nextTick(cb, Fuse.ENOENT) }, truncate: function (path, size, cb) { - cb(0) + process.nextTick(cb, 0) }, getattr: function (path, cb) { - if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 })) - if (path === '/hello' && created) return cb(0, stat({ mode: 'file', size: size })) - return cb(Fuse.ENOENT) + if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 })) + if (path === '/hello' && created) return process.nextTick(cb, 0, stat({ mode: 'file', size: size })) + return process.nextTick(cb, Fuse.ENOENT) }, create: function (path, flags, cb) { t.ok(!created, 'file not created yet') created = true - cb(0, 42) + process.nextTick(cb, 0, 42) }, release: function (path, fd, cb) { - cb(0) + process.nextTick(cb, 0) }, write: function (path, fd, buf, len, pos, cb) { buf.slice(0, len).copy(data, pos) size = Math.max(pos + len, size) - cb(buf.length) + process.nextTick(cb, buf.length) } } @@ -46,7 +46,7 @@ tape('write', function (t) { fs.writeFile(path.join(mnt, 'hello'), 'hello world', function (err) { t.error(err, 'no error') - t.same(data.slice(0, size), new Buffer('hello world'), 'data was written') + t.same(data.slice(0, size), Buffer.from('hello world'), 'data was written') fuse.unmount(function () { t.end()