From 07352cfe101f78448d40f451395702e30696843b Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Tue, 17 Mar 2015 13:32:09 +0100 Subject: [PATCH] better error handling and mount callback --- example.js | 3 +++ fuse-bindings.cc | 22 ++++++++++++++++++---- index.js | 29 +++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/example.js b/example.js index fbf8202..8fe2204 100644 --- a/example.js +++ b/example.js @@ -47,6 +47,9 @@ fuse.mount('./mnt', { buf.write(str) return cb(str.length) } +}, function (err) { + if (err) throw err + console.log('filesystem mounted on ./mnt') }) process.on('SIGINT', function () { diff --git a/fuse-bindings.cc b/fuse-bindings.cc index 39daa94..654865b 100644 --- a/fuse-bindings.cc +++ b/fuse-bindings.cc @@ -18,6 +18,7 @@ using namespace v8; enum bindings_ops_t { OP_INIT = 0, + OP_ERROR, OP_ACCESS, OP_STATFS, OP_FGETATTR, @@ -54,6 +55,7 @@ static Persistent buffer_constructor; static struct stat empty_stat; // TODO support more than a single mount +static int bindings_in_use = 0; static struct { // fuse data char mnt[1024]; @@ -68,6 +70,7 @@ static struct { // methods NanCallback *ops_init; + NanCallback *ops_error; NanCallback *ops_access; NanCallback *ops_statfs; NanCallback *ops_getattr; @@ -471,11 +474,9 @@ static void *bindings_thread (void *) { (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"); + bindings.op = OP_ERROR; + bindings_call(); } return NULL; @@ -623,6 +624,12 @@ static void bindings_dispatch (uv_async_t* handle, int status) { } return; + case OP_ERROR: { + Local tmp[] = {callback}; + bindings_call_op(bindings.ops_error, 1, tmp); + } + return; + case OP_STATFS: { Local tmp[] = {NanNew(bindings.path), callback}; bindings_call_op(bindings.ops_statfs, 2, tmp); @@ -849,12 +856,17 @@ static void bindings_append_opt (char *name) { NAN_METHOD(Mount) { NanScope(); + if (!args[0]->IsString()) return NanThrowError("mnt must be a string"); + if (bindings_in_use) return NanThrowError("Currently only a single filesystem can be mounted at the time"); + bindings_in_use = 1; + memset(&empty_stat, 0, sizeof(empty_stat)); // zero empty stat NanUtf8String path(args[0]); Local ops = args[1].As(); bindings.ops_init = ops->Has(NanNew("init")) ? new NanCallback(ops->Get(NanNew("init")).As()) : NULL; + bindings.ops_error = ops->Has(NanNew("error")) ? new NanCallback(ops->Get(NanNew("error")).As()) : NULL; bindings.ops_access = ops->Has(NanNew("access")) ? new NanCallback(ops->Get(NanNew("access")).As()) : NULL; bindings.ops_statfs = ops->Has(NanNew("statfs")) ? new NanCallback(ops->Get(NanNew("statfs")).As()) : NULL; bindings.ops_getattr = ops->Has(NanNew("getattr")) ? new NanCallback(ops->Get(NanNew("getattr")).As()) : NULL; @@ -944,6 +956,8 @@ NAN_METHOD(SetBuffer) { NAN_METHOD(Unmount) { NanScope(); + + if (!args[0]->IsString()) return NanThrowError("mnt must be a string"); NanUtf8String path(args[0]); Local callback = args[1].As(); diff --git a/index.js b/index.js index f0075c0..ee47227 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,10 @@ var bindings = require('bindings') var fuse = bindings('fuse_bindings') +var fs = require('fs') var path = require('path') var noop = function () {} +var call = function (cb) { cb() } var FuseBuffer = function () { this.length = 0 @@ -13,10 +15,33 @@ FuseBuffer.prototype = Buffer.prototype fuse.setBuffer(FuseBuffer) -exports.mount = function (mnt, ops) { +exports.mount = function (mnt, ops, cb) { + if (!cb) cb = noop if (!ops) ops = {} + if (/\*|(^,)fuse-bindings(,$)/.test(process.env.DEBUG)) ops.options = ['debug'].concat(ops.options || []) - return fuse.mount(path.resolve(mnt), ops) + mnt = path.resolve(mnt) + + var init = ops.init || call + ops.init = function (next) { + cb() + init(next) + } + + var error = ops.error || call + ops.error = function (next) { + cb(new Error('Mount failed')) + error(next) + } + + fs.stat(mnt, function (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(mnt, '..'), function(_, parent) { + if (parent && parent.dev !== stat.dev) return cb(new Error('Mountpoint in use')) + fuse.mount(mnt, ops) + }) + }) } exports.unmount = function (mnt, cb) {