mirror of
https://github.com/fuse-friends/fuse-native
synced 2024-10-27 18:34:01 +00:00
tests all pass
This commit is contained in:
parent
97e42d4fb9
commit
2961856b5b
@ -10,7 +10,8 @@
|
|||||||
],
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
"fuse-native.c"
|
"fuse-native.c"
|
||||||
]
|
],
|
||||||
|
"cflags": ["-rdynamic"]
|
||||||
}, {
|
}, {
|
||||||
"target_name": "postinstall",
|
"target_name": "postinstall",
|
||||||
"type": "none",
|
"type": "none",
|
||||||
|
@ -60,7 +60,7 @@ fuse.mount(err => {
|
|||||||
console.log('filesystem mounted on ' + fuse.mnt)
|
console.log('filesystem mounted on ' + fuse.mnt)
|
||||||
})
|
})
|
||||||
|
|
||||||
process.on('SIGINT', function () {
|
process.once('SIGINT', function () {
|
||||||
fuse.unmount(err => {
|
fuse.unmount(err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('filesystem at ' + fuse.mnt + ' not unmounted', err)
|
console.log('filesystem at ' + fuse.mnt + ' not unmounted', err)
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
#define FUSE_USE_VERSION 29
|
#define FUSE_USE_VERSION 29
|
||||||
|
|
||||||
#include "semaphore.h"
|
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
#include <node_api.h>
|
#include <node_api.h>
|
||||||
#include <napi-macros.h>
|
#include <napi-macros.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include <fuse_opt.h>
|
#include <fuse_opt.h>
|
||||||
|
#include <fuse_common.h>
|
||||||
#include <fuse_lowlevel.h>
|
#include <fuse_lowlevel.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -29,14 +30,11 @@
|
|||||||
napi_close_handle_scope(env, scope);
|
napi_close_handle_scope(env, scope);
|
||||||
|
|
||||||
#define FUSE_NATIVE_HANDLER(name, blk)\
|
#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();\
|
fuse_thread_locals_t *l = get_thread_locals();\
|
||||||
l->fuse = ft;\
|
|
||||||
l->op = op_##name;\
|
l->op = op_##name;\
|
||||||
blk\
|
blk\
|
||||||
uv_async_send(&(l->async));\
|
uv_async_send(&(l->async));\
|
||||||
fuse_native_semaphore_wait(&(l->sem));\
|
uv_sem_wait(&(l->sem));\
|
||||||
return l->res;
|
return l->res;
|
||||||
|
|
||||||
#define FUSE_METHOD(name, callbackArgs, signalArgs, signature, callBlk, callbackBlk, signalBlk)\
|
#define FUSE_METHOD(name, callbackArgs, signalArgs, signature, callBlk, callbackBlk, signalBlk)\
|
||||||
@ -57,7 +55,7 @@
|
|||||||
int ret = NULL;\
|
int ret = NULL;\
|
||||||
signalBlk\
|
signalBlk\
|
||||||
l->res = ret ? ret : res;\
|
l->res = ret ? ret : res;\
|
||||||
fuse_native_semaphore_signal(&(l->sem));\
|
uv_sem_post(&(l->sem));\
|
||||||
return ret;\
|
return ret;\
|
||||||
}\
|
}\
|
||||||
static int fuse_native_##name signature {\
|
static int fuse_native_##name signature {\
|
||||||
@ -115,8 +113,13 @@ typedef struct {
|
|||||||
|
|
||||||
struct fuse *fuse;
|
struct fuse *fuse;
|
||||||
struct fuse_chan *ch;
|
struct fuse_chan *ch;
|
||||||
bool mounted;
|
char* mnt;
|
||||||
|
char* mntopts;
|
||||||
|
int mounted;
|
||||||
|
|
||||||
uv_async_t async;
|
uv_async_t async;
|
||||||
|
uv_mutex_t mut;
|
||||||
|
uv_sem_t sem;
|
||||||
} fuse_thread_t;
|
} fuse_thread_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -156,7 +159,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Internal bookkeeping
|
// Internal bookkeeping
|
||||||
fuse_thread_t *fuse;
|
fuse_thread_t *fuse;
|
||||||
fuse_native_semaphore_t sem;
|
uv_sem_t sem;
|
||||||
uv_async_t async;
|
uv_async_t async;
|
||||||
|
|
||||||
} fuse_thread_locals_t;
|
} fuse_thread_locals_t;
|
||||||
@ -764,7 +767,28 @@ 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 () {
|
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);
|
void *data = pthread_getspecific(thread_locals_key);
|
||||||
|
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
@ -772,19 +796,20 @@ static fuse_thread_locals_t* get_thread_locals () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t));
|
fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t));
|
||||||
|
l->fuse = ft;
|
||||||
|
|
||||||
// TODO: mutex me??
|
// Need to lock the mutation of l->async.
|
||||||
int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch);
|
uv_mutex_lock(&(ft->mut));
|
||||||
|
ft->async.data = l;
|
||||||
|
|
||||||
|
// Notify the main thread to uv_async_init l->async.
|
||||||
|
uv_async_send(&(ft->async));
|
||||||
|
uv_sem_wait(&(ft->sem));
|
||||||
|
|
||||||
l->async.data = l;
|
l->async.data = l;
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
printf("uv_async failed: %i\n", err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_native_semaphore_init(&(l->sem));
|
|
||||||
pthread_setspecific(thread_locals_key, (void *) l);
|
pthread_setspecific(thread_locals_key, (void *) l);
|
||||||
|
uv_mutex_unlock(&(ft->mut));
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
@ -793,10 +818,9 @@ static void* start_fuse_thread (void *data) {
|
|||||||
fuse_thread_t *ft = (fuse_thread_t *) data;
|
fuse_thread_t *ft = (fuse_thread_t *) data;
|
||||||
fuse_loop_mt(ft->fuse);
|
fuse_loop_mt(ft->fuse);
|
||||||
|
|
||||||
// printf("her nu\n");
|
fuse_unmount(ft->mnt, ft->ch);
|
||||||
// fuse_unmount(mnt, ch);
|
fuse_session_remove_chan(ft->ch);
|
||||||
// fuse_session_remove_chan(ch);
|
fuse_destroy(ft->fuse);
|
||||||
// fuse_destroy(fuse);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -816,14 +840,12 @@ NAPI_METHOD(fuse_native_mount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAPI_FOR_EACH(handlers, handler) {
|
NAPI_FOR_EACH(handlers, handler) {
|
||||||
printf("creating reference for handler: %d\n", i);
|
|
||||||
napi_create_reference(env, handler, 1, &ft->handlers[i]);
|
napi_create_reference(env, handler, 1, &ft->handlers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ft->env = env;
|
ft->env = env;
|
||||||
|
|
||||||
struct fuse_operations ops = { };
|
struct fuse_operations ops = { };
|
||||||
|
|
||||||
if (implemented[op_access]) ops.access = fuse_native_access;
|
if (implemented[op_access]) ops.access = fuse_native_access;
|
||||||
if (implemented[op_truncate]) ops.truncate = fuse_native_truncate;
|
if (implemented[op_truncate]) ops.truncate = fuse_native_truncate;
|
||||||
if (implemented[op_ftruncate]) ops.ftruncate = fuse_native_ftruncate;
|
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);
|
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->fuse = fuse;
|
||||||
ft->ch = ch;
|
ft->ch = ch;
|
||||||
ft->mounted = true;
|
ft->mounted++;
|
||||||
|
|
||||||
if (fuse == NULL) {
|
int err = uv_async_init(uv_default_loop(), &(ft->async), (uv_async_cb) fuse_native_async_init);
|
||||||
|
|
||||||
|
if (fuse == NULL || err < 0) {
|
||||||
napi_throw_error(env, "fuse failed", "fuse failed");
|
napi_throw_error(env, "fuse failed", "fuse failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -896,12 +925,11 @@ NAPI_METHOD(fuse_native_unmount) {
|
|||||||
NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 1);
|
NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 1);
|
||||||
|
|
||||||
if (ft != NULL && ft->mounted) {
|
if (ft != NULL && ft->mounted) {
|
||||||
fuse_unmount(mnt, ft->ch);
|
|
||||||
printf("joining\n");
|
|
||||||
pthread_join(ft->thread, NULL);
|
pthread_join(ft->thread, NULL);
|
||||||
printf("joined\n");
|
|
||||||
}
|
}
|
||||||
ft->mounted = false;
|
|
||||||
|
uv_unref(&(ft->async));
|
||||||
|
ft->mounted--;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
247
index.js
247
index.js
@ -1,142 +1,143 @@
|
|||||||
const os = require('os')
|
const os = require('os')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
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 IS_OSX = os.platform() === 'darwin'
|
||||||
const OSX_FOLDER_ICON = '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericFolderIcon.icns'
|
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 HAS_FOLDER_ICON = IS_OSX && fs.existsSync(OSX_FOLDER_ICON)
|
||||||
|
|
||||||
const binding = require('node-gyp-build')(__dirname)
|
|
||||||
const OpcodesAndDefaults = new Map([
|
const OpcodesAndDefaults = new Map([
|
||||||
['init', {
|
['init', {
|
||||||
op: 0
|
op: binding.op_init
|
||||||
}],
|
}],
|
||||||
['error', {
|
['error', {
|
||||||
op: 1
|
op: binding.op_error
|
||||||
}],
|
}],
|
||||||
['access', {
|
['access', {
|
||||||
op: 2,
|
op: binding.op_access,
|
||||||
defaults: [0]
|
defaults: [0]
|
||||||
}],
|
}],
|
||||||
['statfs', {
|
['statfs', {
|
||||||
op: 3,
|
op: binding.op_statfs,
|
||||||
defaults: [getStatfsArray()]
|
defaults: [getStatfsArray()]
|
||||||
}],
|
}],
|
||||||
['fgetattr', {
|
['fgetattr', {
|
||||||
op: 4,
|
op: binding.op_fgetattr,
|
||||||
defaults: [getStatArray()]
|
defaults: [getStatArray()]
|
||||||
}],
|
}],
|
||||||
['getattr', {
|
['getattr', {
|
||||||
op: 5,
|
op: binding.op_getattr,
|
||||||
defaults: [getStatArray()]
|
defaults: [getStatArray()]
|
||||||
}],
|
}],
|
||||||
['flush', {
|
['flush', {
|
||||||
op: 6
|
op: binding.op_flush
|
||||||
}],
|
}],
|
||||||
['fsync', {
|
['fsync', {
|
||||||
op: 7
|
op: binding.op_fsync
|
||||||
}],
|
}],
|
||||||
['fsyncdir', {
|
['fsyncdir', {
|
||||||
op: 8
|
op: binding.op_fsyncdir
|
||||||
}],
|
}],
|
||||||
['readdir', {
|
['readdir', {
|
||||||
op: 9
|
op: binding.op_readdir
|
||||||
}],
|
}],
|
||||||
['truncate', {
|
['truncate', {
|
||||||
op: 10
|
op: binding.op_truncate
|
||||||
}],
|
}],
|
||||||
['ftruncate', {
|
['ftruncate', {
|
||||||
op: 11
|
op: binding.op_ftruncate
|
||||||
}],
|
}],
|
||||||
['utimens', {
|
['utimens', {
|
||||||
op: 12
|
op: binding.op_utimens
|
||||||
}],
|
}],
|
||||||
['readlink', {
|
['readlink', {
|
||||||
op: 13,
|
op: binding.op_readlink,
|
||||||
defaults: ['']
|
defaults: ['']
|
||||||
}],
|
}],
|
||||||
['chown', {
|
['chown', {
|
||||||
op: 14
|
op: binding.op_chown
|
||||||
}],
|
}],
|
||||||
['chmod', {
|
['chmod', {
|
||||||
op: 15
|
op: binding.op_chmod
|
||||||
}],
|
}],
|
||||||
['mknod', {
|
['mknod', {
|
||||||
op: 16
|
op: binding.op_mknod
|
||||||
}],
|
}],
|
||||||
['setxattr', {
|
['setxattr', {
|
||||||
op: 17
|
op: binding.op_setxattr
|
||||||
}],
|
}],
|
||||||
['getxattr', {
|
['getxattr', {
|
||||||
op: 18
|
op: binding.op_getxattr
|
||||||
}],
|
}],
|
||||||
['listxattr', {
|
['listxattr', {
|
||||||
op: 19
|
op: binding.op_listxattr
|
||||||
}],
|
}],
|
||||||
['removexattr', {
|
['removexattr', {
|
||||||
op: 20
|
op: binding.op_removexattr
|
||||||
}],
|
}],
|
||||||
['open', {
|
['open', {
|
||||||
op: 21,
|
op: binding.op_open,
|
||||||
defaults: [0]
|
defaults: [0]
|
||||||
}],
|
}],
|
||||||
['opendir', {
|
['opendir', {
|
||||||
op: 22,
|
op: binding.op_opendir,
|
||||||
defaults: [0]
|
defaults: [0]
|
||||||
}],
|
}],
|
||||||
['read', {
|
['read', {
|
||||||
op: 23,
|
op: binding.op_read,
|
||||||
defaults: [0]
|
defaults: [0]
|
||||||
}],
|
}],
|
||||||
['write', {
|
['write', {
|
||||||
op: 24,
|
op: binding.op_write,
|
||||||
defaults: [0]
|
defaults: [0]
|
||||||
}],
|
}],
|
||||||
['release', {
|
['release', {
|
||||||
op: 25
|
op: binding.op_release
|
||||||
}],
|
}],
|
||||||
['releasedir', {
|
['releasedir', {
|
||||||
op: 26
|
op: binding.op_releasedir
|
||||||
}],
|
}],
|
||||||
['create', {
|
['create', {
|
||||||
op: 27
|
op: binding.op_create
|
||||||
}],
|
}],
|
||||||
['unlink', {
|
['unlink', {
|
||||||
op: 28
|
op: binding.op_unlink
|
||||||
}],
|
}],
|
||||||
['rename', {
|
['rename', {
|
||||||
op: 29
|
op: binding.op_rename
|
||||||
}],
|
}],
|
||||||
['link', {
|
['link', {
|
||||||
op: 30
|
op: binding.op_link
|
||||||
}],
|
}],
|
||||||
['symlink', {
|
['symlink', {
|
||||||
op: 31
|
op: binding.op_symlink
|
||||||
}],
|
}],
|
||||||
['mkdir', {
|
['mkdir', {
|
||||||
op: 32
|
op: binding.op_mkdir
|
||||||
}],
|
}],
|
||||||
['rmdir', {
|
['rmdir', {
|
||||||
op: 33
|
op: binding.op_rmdir
|
||||||
}],
|
}],
|
||||||
['destroy', {
|
['destroy', {
|
||||||
op: 34
|
op: binding.op_destroy
|
||||||
}]
|
}]
|
||||||
])
|
])
|
||||||
|
|
||||||
class Fuse {
|
class Fuse extends Nanoresource {
|
||||||
constructor (mnt, ops, opts = {}) {
|
constructor (mnt, ops, opts = {}) {
|
||||||
|
super()
|
||||||
this.opts = opts
|
this.opts = opts
|
||||||
this.mnt = path.resolve(mnt)
|
this.mnt = path.resolve(mnt)
|
||||||
|
|
||||||
this.ops = ops
|
this.ops = ops
|
||||||
this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t)
|
this._thread = null
|
||||||
this._handlers = this._makeHandlerArray()
|
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) {
|
if (ops) {
|
||||||
for (const [name, { op }] of OpcodesAndDefaults) {
|
for (const [name, { op }] of OpcodesAndDefaults) {
|
||||||
if (ops[name]) implemented.push(op)
|
if (ops[name]) implemented.push(op)
|
||||||
@ -150,7 +151,7 @@ class Fuse {
|
|||||||
|
|
||||||
_getImplementedArray () {
|
_getImplementedArray () {
|
||||||
const implemented = new Uint32Array(35)
|
const implemented = new Uint32Array(35)
|
||||||
for (const impl of [...this._implemented]) {
|
for (const impl of this._implemented) {
|
||||||
implemented[impl] = 1
|
implemented[impl] = 1
|
||||||
}
|
}
|
||||||
return implemented
|
return implemented
|
||||||
@ -191,16 +192,6 @@ class Fuse {
|
|||||||
return options.map(o => '-o' + o).join(' ')
|
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 () {
|
_makeHandlerArray () {
|
||||||
const self = this
|
const self = this
|
||||||
const handlers = new Array(OpcodesAndDefaults.size)
|
const handlers = new Array(OpcodesAndDefaults.size)
|
||||||
@ -217,7 +208,7 @@ class Fuse {
|
|||||||
function makeHandler (name, op, defaults, nativeSignal) {
|
function makeHandler (name, op, defaults, nativeSignal) {
|
||||||
return function () {
|
return function () {
|
||||||
const boundSignal = signal.bind(null, arguments[0])
|
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)
|
if (!self[funcName] || !self._implemented.has(op)) return boundSignal(-1, ...defaults)
|
||||||
return self[funcName].apply(self, [boundSignal, ...[...arguments].slice(2)])
|
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) {
|
if (!this.ops.init) {
|
||||||
signal(0)
|
signal(0)
|
||||||
return
|
return
|
||||||
@ -240,7 +281,7 @@ class Fuse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_error (signal) {
|
_op_error (signal) {
|
||||||
if (!this.ops.error) {
|
if (!this.ops.error) {
|
||||||
signal(0)
|
signal(0)
|
||||||
return
|
return
|
||||||
@ -250,7 +291,7 @@ class Fuse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_statfs (signal) {
|
_op_statfs (signal) {
|
||||||
this.ops.statfs((err, statfs) => {
|
this.ops.statfs((err, statfs) => {
|
||||||
if (err) return signal(err)
|
if (err) return signal(err)
|
||||||
const arr = getStatfsArray(statfs)
|
const arr = getStatfsArray(statfs)
|
||||||
@ -258,7 +299,7 @@ class Fuse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_getattr (signal, path) {
|
_op_getattr (signal, path) {
|
||||||
if (!this.ops.getattr) {
|
if (!this.ops.getattr) {
|
||||||
if (path !== '/') {
|
if (path !== '/') {
|
||||||
signal(Fuse.EPERM)
|
signal(Fuse.EPERM)
|
||||||
@ -273,7 +314,7 @@ class Fuse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_fgetattr (signal, path, fd) {
|
_op_fgetattr (signal, path, fd) {
|
||||||
if (!this.ops.fgetattr) {
|
if (!this.ops.fgetattr) {
|
||||||
if (path !== '/') {
|
if (path !== '/') {
|
||||||
signal(Fuse.EPERM)
|
signal(Fuse.EPERM)
|
||||||
@ -288,31 +329,31 @@ class Fuse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_access (signal, path, mode) {
|
_op_access (signal, path, mode) {
|
||||||
this.ops.access(path, mode, err => {
|
this.ops.access(path, mode, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_open (signal, path, flags) {
|
_op_open (signal, path, flags) {
|
||||||
this.ops.open(path, flags, (err, fd) => {
|
this.ops.open(path, flags, (err, fd) => {
|
||||||
return signal(err, fd)
|
return signal(err, fd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_opendir (signal, path, flags) {
|
_op_opendir (signal, path, flags) {
|
||||||
this.ops.opendir(path, flags, (err, fd) => {
|
this.ops.opendir(path, flags, (err, fd) => {
|
||||||
return signal(err, fd)
|
return signal(err, fd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_create (signal, path, mode) {
|
_op_create (signal, path, mode) {
|
||||||
this.ops.create(path, mode, (err, fd) => {
|
this.ops.create(path, mode, (err, fd) => {
|
||||||
return signal(err, fd)
|
return signal(err, fd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_utimens (signal, path, atim, mtim) {
|
_op_utimens (signal, path, atim, mtim) {
|
||||||
atim = getDoubleInt(atim, 0)
|
atim = getDoubleInt(atim, 0)
|
||||||
mtim = getDoubleInt(mtim, 0)
|
mtim = getDoubleInt(mtim, 0)
|
||||||
this.ops.utimens(path, atim, mtim, err => {
|
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 => {
|
this.ops.release(path, fd, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_releasedir (signal, path, fd) {
|
_op_releasedir (signal, path, fd) {
|
||||||
this.ops.releasedir(path, fd, err => {
|
this.ops.releasedir(path, fd, err => {
|
||||||
return signal(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) => {
|
this.ops.read(path, fd, buf, len, offset, (err, bytesRead) => {
|
||||||
return signal(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) => {
|
this.ops.write(path, fd, buf, len, offset, (err, bytesWritten) => {
|
||||||
return signal(err, bytesWritten)
|
return signal(err, bytesWritten)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_readdir (signal, path) {
|
_op_readdir (signal, path) {
|
||||||
this.ops.readdir(path, (err, names, stats) => {
|
this.ops.readdir(path, (err, names, stats) => {
|
||||||
if (err) return signal(err)
|
if (err) return signal(err)
|
||||||
if (stats) stats = stats.map(getStatArray)
|
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 => {
|
this.ops.setxattr(path, name, value, size, position, flags, err => {
|
||||||
return signal(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 => {
|
this.ops.getxattr(path, name, value, size, position, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_listxattr (signal, path, list, size) {
|
_op_listxattr (signal, path, list, size) {
|
||||||
this.ops.listxattr(path, list, size, err => {
|
this.ops.listxattr(path, list, size, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_removexattr (signal, path, name) {
|
_op_removexattr (signal, path, name) {
|
||||||
this.ops.removexattr(path, name, err => {
|
this.ops.removexattr(path, name, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_flush (signal, path, datasync, fd) {
|
_op_flush (signal, path, datasync, fd) {
|
||||||
this.ops.flush(path, datasync, fd, err => {
|
this.ops.flush(path, datasync, fd, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_fsync (signal, path, datasync, fd) {
|
_op_fsync (signal, path, datasync, fd) {
|
||||||
this.ops.fsync(path, datasync, fd, err => {
|
this.ops.fsync(path, datasync, fd, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_fsyncdir (signal, path, datasync, fd) {
|
_op_fsyncdir (signal, path, datasync, fd) {
|
||||||
this.ops.fsyncdir(path, datasync, fd, err => {
|
this.ops.fsyncdir(path, datasync, fd, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_truncate (signal, path, size) {
|
_op_truncate (signal, path, size) {
|
||||||
this.ops.truncate(path, size, err => {
|
this.ops.truncate(path, size, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_ftruncate (signal, path, size, fd) {
|
_op_ftruncate (signal, path, size, fd) {
|
||||||
this.ops.ftruncate(path, size, fd, err => {
|
this.ops.ftruncate(path, size, fd, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_readlink (signal, path) {
|
_op_readlink (signal, path) {
|
||||||
this.ops.readlink(path, (err, linkname) => {
|
this.ops.readlink(path, (err, linkname) => {
|
||||||
return signal(err, linkname)
|
return signal(err, linkname)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_chown (signal, path, uid, gid) {
|
_op_chown (signal, path, uid, gid) {
|
||||||
this.ops.chown(path, uid, gid, err => {
|
this.ops.chown(path, uid, gid, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_chmod (signal, path, mode) {
|
_op_chmod (signal, path, mode) {
|
||||||
this.ops.chmod(path, mode, err => {
|
this.ops.chmod(path, mode, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_mknod (signal, path, mode, dev) {
|
_op_mknod (signal, path, mode, dev) {
|
||||||
this.ops.mknod(path, mode, dev, err => {
|
this.ops.mknod(path, mode, dev, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_unlink (signal, path) {
|
_op_unlink (signal, path) {
|
||||||
this.ops.unlink(path, err => {
|
this.ops.unlink(path, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_rename (signal, src, dest, flags) {
|
_op_rename (signal, src, dest, flags) {
|
||||||
this.ops.rename(src, dest, flags, err => {
|
this.ops.rename(src, dest, flags, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_link (signal, src, dest) {
|
_op_link (signal, src, dest) {
|
||||||
this.ops.link(src, dest, err => {
|
this.ops.link(src, dest, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_symlink (signal, src, dest) {
|
_op_symlink (signal, src, dest) {
|
||||||
this.ops.symlink(src, dest, err => {
|
this.ops.symlink(src, dest, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir (signal, path, mode) {
|
_op_mkdir (signal, path, mode) {
|
||||||
this.ops.mkdir(path, mode, err => {
|
this.ops.mkdir(path, mode, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_rmdir (signal, path) {
|
_op_rmdir (signal, path) {
|
||||||
this.ops.rmdir(path, err => {
|
this.ops.rmdir(path, err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroy (signal) {
|
_op_destroy (signal) {
|
||||||
this.ops.destroy(err => {
|
this.ops.destroy(err => {
|
||||||
return signal(err)
|
return signal(err)
|
||||||
})
|
})
|
||||||
@ -475,35 +516,11 @@ class Fuse {
|
|||||||
// Public API
|
// Public API
|
||||||
|
|
||||||
mount (cb) {
|
mount (cb) {
|
||||||
const opts = this._fuseOptions()
|
return this._open(cb)
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unmount (cb) {
|
unmount (cb) {
|
||||||
// TODO: asyncify
|
return this._close(cb)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errno (code) {
|
errno (code) {
|
||||||
|
@ -5,15 +5,17 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install": "node-gyp-build",
|
"install": "node-gyp-build",
|
||||||
"test": "standard && test/*.js",
|
"test": "tape test/*.js",
|
||||||
"prebuild": "prebuildify -a --strip",
|
"prebuild": "prebuildify -a --strip",
|
||||||
"prebuild-ia32": "prebuildify -a --strip --arch=ia32"
|
"prebuild-ia32": "prebuildify -a --strip --arch=ia32"
|
||||||
},
|
},
|
||||||
"gypfile": true,
|
"gypfile": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fuse-shared-library": "^1.0.1",
|
"fuse-shared-library": "^1.0.1",
|
||||||
|
"nanoresource": "^1.2.0",
|
||||||
"napi-macros": "^2.0.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": {
|
"devDependencies": {
|
||||||
"concat-stream": "^2.0.0",
|
"concat-stream": "^2.0.0",
|
||||||
|
@ -10,26 +10,26 @@ tape('readlink', function (t) {
|
|||||||
var ops = {
|
var ops = {
|
||||||
force: true,
|
force: true,
|
||||||
readdir: function (path, cb) {
|
readdir: function (path, cb) {
|
||||||
if (path === '/') return cb(null, ['hello', 'link'])
|
if (path === '/') return process.nextTick(cb, null, ['hello', 'link'])
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
readlink: function (path, cb) {
|
readlink: function (path, cb) {
|
||||||
cb(0, 'hello')
|
process.nextTick(cb, 0, 'hello')
|
||||||
},
|
},
|
||||||
getattr: function (path, cb) {
|
getattr: function (path, cb) {
|
||||||
if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 }))
|
if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 }))
|
||||||
if (path === '/hello') return cb(null, stat({ mode: 'file', size: 11 }))
|
if (path === '/hello') return process.nextTick(cb, null, stat({ mode: 'file', size: 11 }))
|
||||||
if (path === '/link') return cb(null, stat({ mode: 'link', size: 5 }))
|
if (path === '/link') return process.nextTick(cb, null, stat({ mode: 'link', size: 5 }))
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
open: function (path, flags, cb) {
|
open: function (path, flags, cb) {
|
||||||
cb(0, 42)
|
process.nextTick(cb, 0, 42)
|
||||||
},
|
},
|
||||||
read: function (path, fd, buf, len, pos, cb) {
|
read: function (path, fd, buf, len, pos, cb) {
|
||||||
var str = 'hello world'.slice(pos, pos + len)
|
var str = 'hello world'.slice(pos, pos + len)
|
||||||
if (!str) return cb(0)
|
if (!str) return process.nextTick(cb, 0)
|
||||||
buf.write(str)
|
buf.write(str)
|
||||||
return cb(str.length)
|
return process.nextTick(cb, str.length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ tape('readlink', function (t) {
|
|||||||
|
|
||||||
fs.readFile(path.join(mnt, 'link'), function (err, buf) {
|
fs.readFile(path.join(mnt, 'link'), function (err, buf) {
|
||||||
t.error(err, 'no error')
|
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()
|
t.end()
|
||||||
|
25
test/misc.js
25
test/misc.js
@ -1,26 +1,31 @@
|
|||||||
var mnt = require('./fixtures/mnt')
|
var mnt = require('./fixtures/mnt')
|
||||||
var fuse = require('../')
|
|
||||||
var tape = require('tape')
|
var tape = require('tape')
|
||||||
|
|
||||||
|
var Fuse = require('../')
|
||||||
|
|
||||||
tape('mount', function (t) {
|
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.error(err, 'no error')
|
||||||
t.ok(true, 'works')
|
t.ok(true, 'works')
|
||||||
fuse.unmount(mnt, function () {
|
fuse.unmount(function () {
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
tape('mount + unmount + mount', function (t) {
|
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.error(err, 'no error')
|
||||||
t.ok(true, 'works')
|
t.ok(true, 'works')
|
||||||
fuse.unmount(mnt, function () {
|
fuse1.unmount(function () {
|
||||||
fuse.mount(mnt, { force: true }, function (err) {
|
fuse2.mount(function (err) {
|
||||||
t.error(err, 'no error')
|
t.error(err, 'no error')
|
||||||
t.ok(true, 'works')
|
t.ok(true, 'works')
|
||||||
fuse.unmount(mnt, function () {
|
fuse2.unmount(function () {
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -29,14 +34,16 @@ tape('mount + unmount + mount', function (t) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
tape('mnt point must exist', 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.ok(err, 'had error')
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
tape('mnt point must be directory', function (t) {
|
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.ok(err, 'had error')
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
|
28
test/read.js
28
test/read.js
@ -11,27 +11,27 @@ tape('read', function (t) {
|
|||||||
var ops = {
|
var ops = {
|
||||||
force: true,
|
force: true,
|
||||||
readdir: function (path, cb) {
|
readdir: function (path, cb) {
|
||||||
if (path === '/') return cb(null, ['test'])
|
if (path === '/') return process.nextTick(cb, null, ['test'])
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
getattr: function (path, cb) {
|
getattr: function (path, cb) {
|
||||||
if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 }))
|
if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 }))
|
||||||
if (path === '/test') return cb(null, stat({ mode: 'file', size: 11 }))
|
if (path === '/test') return process.nextTick(cb, null, stat({ mode: 'file', size: 11 }))
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
open: function (path, flags, cb) {
|
open: function (path, flags, cb) {
|
||||||
cb(0, 42)
|
return process.nextTick(cb, 0, 42)
|
||||||
},
|
},
|
||||||
release: function (path, fd, cb) {
|
release: function (path, fd, cb) {
|
||||||
|
console.log('IN JS RELEASE')
|
||||||
t.same(fd, 42, 'fd was passed to 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) {
|
read: function (path, fd, buf, len, pos, cb) {
|
||||||
var str = 'hello world'.slice(pos, pos + len)
|
var str = 'hello world'.slice(pos, pos + len)
|
||||||
if (!str) return cb(0)
|
if (!str) return process.nextTick(cb, 0)
|
||||||
buf.write(str)
|
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) {
|
fs.readFile(path.join(mnt, 'test'), function (err, buf) {
|
||||||
t.error(err, 'no error')
|
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) {
|
fs.readFile(path.join(mnt, 'test'), function (err, buf) {
|
||||||
t.error(err, 'no error')
|
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) {
|
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) {
|
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 () {
|
fuse.unmount(function () {
|
||||||
t.end()
|
t.end()
|
||||||
|
@ -8,35 +8,35 @@ const stat = require('./fixtures/stat')
|
|||||||
|
|
||||||
tape('write', function (t) {
|
tape('write', function (t) {
|
||||||
var created = false
|
var created = false
|
||||||
var data = new Buffer(1024)
|
var data = Buffer.alloc(1024)
|
||||||
var size = 0
|
var size = 0
|
||||||
|
|
||||||
var ops = {
|
var ops = {
|
||||||
force: true,
|
force: true,
|
||||||
readdir: function (path, cb) {
|
readdir: function (path, cb) {
|
||||||
if (path === '/') return cb(null, created ? ['hello'] : [])
|
if (path === '/') return process.nextTick(cb, null, created ? ['hello'] : [], [])
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
truncate: function (path, size, cb) {
|
truncate: function (path, size, cb) {
|
||||||
cb(0)
|
process.nextTick(cb, 0)
|
||||||
},
|
},
|
||||||
getattr: function (path, cb) {
|
getattr: function (path, cb) {
|
||||||
if (path === '/') return cb(null, stat({ mode: 'dir', size: 4096 }))
|
if (path === '/') return process.nextTick(cb, null, stat({ mode: 'dir', size: 4096 }))
|
||||||
if (path === '/hello' && created) return cb(0, stat({ mode: 'file', size: size }))
|
if (path === '/hello' && created) return process.nextTick(cb, 0, stat({ mode: 'file', size: size }))
|
||||||
return cb(Fuse.ENOENT)
|
return process.nextTick(cb, Fuse.ENOENT)
|
||||||
},
|
},
|
||||||
create: function (path, flags, cb) {
|
create: function (path, flags, cb) {
|
||||||
t.ok(!created, 'file not created yet')
|
t.ok(!created, 'file not created yet')
|
||||||
created = true
|
created = true
|
||||||
cb(0, 42)
|
process.nextTick(cb, 0, 42)
|
||||||
},
|
},
|
||||||
release: function (path, fd, cb) {
|
release: function (path, fd, cb) {
|
||||||
cb(0)
|
process.nextTick(cb, 0)
|
||||||
},
|
},
|
||||||
write: function (path, fd, buf, len, pos, cb) {
|
write: function (path, fd, buf, len, pos, cb) {
|
||||||
buf.slice(0, len).copy(data, pos)
|
buf.slice(0, len).copy(data, pos)
|
||||||
size = Math.max(pos + len, size)
|
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) {
|
fs.writeFile(path.join(mnt, 'hello'), 'hello world', function (err) {
|
||||||
t.error(err, 'no error')
|
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 () {
|
fuse.unmount(function () {
|
||||||
t.end()
|
t.end()
|
||||||
|
Loading…
Reference in New Issue
Block a user