|
|
|
const binding = require('node-gyp-build')(__dirname)
|
|
|
|
|
|
|
|
const Opcodes = new Map([
|
|
|
|
[ 'init', 0 ],
|
|
|
|
[ 'error', 1 ],
|
|
|
|
[ 'access', 2 ],
|
|
|
|
[ 'statfs', 3 ],
|
|
|
|
[ 'fgetattr', 4 ],
|
|
|
|
[ 'getattr', 5 ],
|
|
|
|
[ 'flush', 6 ],
|
|
|
|
[ 'fsync', 7 ],
|
|
|
|
[ 'fsyncdir', 8 ],
|
|
|
|
[ 'readdir', 9 ],
|
|
|
|
[ 'truncate', 10 ],
|
|
|
|
[ 'ftruncate', 11 ],
|
|
|
|
[ 'utimens', 12 ],
|
|
|
|
[ 'readlink', 13 ],
|
|
|
|
[ 'chown', 14 ],
|
|
|
|
[ 'chmod', 15 ],
|
|
|
|
[ 'mknod', 16 ],
|
|
|
|
[ 'setxattr', 17 ],
|
|
|
|
[ 'getxattr', 18 ],
|
|
|
|
[ 'listxattr', 19 ],
|
|
|
|
[ 'removexattr', 20 ],
|
|
|
|
[ 'open', 21 ],
|
|
|
|
[ 'opendir', 22 ],
|
|
|
|
[ 'read', 23 ],
|
|
|
|
[ 'write', 24 ],
|
|
|
|
[ 'release', 25 ],
|
|
|
|
[ 'releasedir', 26 ],
|
|
|
|
[ 'create', 27 ],
|
|
|
|
[ 'unlink', 28 ],
|
|
|
|
[ 'rename', 29 ],
|
|
|
|
[ 'link', 30 ],
|
|
|
|
[ 'symlink', 31 ],
|
|
|
|
[ 'mkdir', 32 ],
|
|
|
|
[ 'rmdir', 33 ],
|
|
|
|
[ 'destroy', 34 ]
|
|
|
|
])
|
|
|
|
|
|
|
|
class Fuse {
|
|
|
|
constructor (mnt, ops, opts = {}) {
|
|
|
|
this.opts = opts
|
|
|
|
this.ops = ops
|
|
|
|
this.mnt = mnt
|
|
|
|
|
|
|
|
this._thread = Buffer.alloc(binding.sizeof_fuse_thread_t)
|
|
|
|
|
|
|
|
const implemented = []
|
|
|
|
if (ops) {
|
|
|
|
for (const [name, code] of Opcodes) {
|
|
|
|
if (ops[name]) implemented.push(code)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._implemented = new Set(implemented)
|
|
|
|
|
|
|
|
// Used to determine if the user-defined callback needs to be nextTick'd.
|
|
|
|
this._sync = true
|
|
|
|
}
|
|
|
|
|
|
|
|
_signal (signalFunc, args) {
|
|
|
|
/*
|
|
|
|
if (this._sync) process.nextTick(() => signalFunc.apply(null, args))
|
|
|
|
else signalFunc.apply(null, args)
|
|
|
|
*/
|
|
|
|
process.nextTick(() => signalFunc.apply(null, args))
|
|
|
|
}
|
|
|
|
|
|
|
|
mount () {
|
|
|
|
binding.fuse_native_mount(this.mnt, '-odebug', this._thread, this,
|
|
|
|
this.on_path_op, this.on_statfs_op, this.on_stat_op,
|
|
|
|
this.on_buffer_op, this.on_readdir, this.on_symlink)
|
|
|
|
}
|
|
|
|
|
|
|
|
unmount () {
|
|
|
|
binding.fuse_native_unmount(this.mnt)
|
|
|
|
}
|
|
|
|
|
|
|
|
on_symlink (handle, op, path, target) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_path.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
|
|
|
|
}
|
|
|
|
|
|
|
|
on_readdir (handle, op, path) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_readdir.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
|
|
|
|
}
|
|
|
|
|
|
|
|
on_buffer_op (handle, op, path, buf) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_buffer.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
|
|
|
|
}
|
|
|
|
|
|
|
|
on_statfs_op (handle, op, path) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_statfs.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
|
|
|
|
|
|
|
|
this.ops.statfs((err, statfs) => {
|
|
|
|
const arr = getStatfsArray(statfs)
|
|
|
|
return this._signal(signalFunc, [handle, err, ...arr])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
on_stat_op (handle, op, path) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_stat.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1, ...getStatArray()])
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case (binding.op_getattr):
|
|
|
|
this.ops.getattr(path, (err, stat) => {
|
|
|
|
const arrs = getStatArray(stat)
|
|
|
|
return this._signal(signalFunc, [handle, err, ...arrs])
|
|
|
|
})
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
return this._signal(signalFunc, [handle, -1, ...getStatArray()])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
on_path_op (handle, op, path) {
|
|
|
|
const signalFunc = binding.fuse_native_signal_path.bind(binding)
|
|
|
|
if (!this._implemented.has(op)) return this._signal(signalFunc, [handle, -1])
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getStatfsArray (statfs) {
|
|
|
|
const ints = Array(11)
|
|
|
|
|
|
|
|
ints[0] = (statfs && statfs.bsize) || 0
|
|
|
|
ints[1] = (statfs && statfs.frsize) || 0
|
|
|
|
ints[2] = (statfs && statfs.blocks) || 0
|
|
|
|
ints[3] = (statfs && statfs.bfree) || 0
|
|
|
|
ints[4] = (statfs && statfs.bavail) || 0
|
|
|
|
ints[5] = (statfs && statfs.files) || 0
|
|
|
|
ints[6] = (statfs && statfs.ffree) || 0
|
|
|
|
ints[7] = (statfs && statfs.favail) || 0
|
|
|
|
ints[8] = (statfs && statfs.fsid) || 0
|
|
|
|
ints[9] = (statfs && statfs.flag) || 0
|
|
|
|
ints[10] = (statfs && statfs.namemax) || 0
|
|
|
|
|
|
|
|
return ints
|
|
|
|
}
|
|
|
|
|
|
|
|
function getStatArray (stat) {
|
|
|
|
const ints = Array(13)
|
|
|
|
|
|
|
|
ints[0] = (stat && stat.mode) || 0
|
|
|
|
ints[1] = (stat && stat.uid) || 0
|
|
|
|
ints[2] = (stat && stat.gid) || 0
|
|
|
|
ints[3] = (stat && stat.size) || 0
|
|
|
|
ints[4] = (stat && stat.dev) || 0
|
|
|
|
ints[5] = (stat && stat.nlink) || 1
|
|
|
|
ints[6] = (stat && stat.ino) || 0
|
|
|
|
ints[7] = (stat && stat.rdev) || 0
|
|
|
|
ints[8] = (stat && stat.blksize) || 0
|
|
|
|
ints[9] = (stat && stat.blocks) || 0
|
|
|
|
ints[10] = (stat && stat.atim) || Date.now()
|
|
|
|
ints[11] = (stat && stat.mtim) || Date.now()
|
|
|
|
ints[12] = (stat && stat.ctim) || Date.now()
|
|
|
|
|
|
|
|
return ints
|
|
|
|
}
|
|
|
|
|
|
|
|
const f = new Fuse('mnt', {
|
|
|
|
getattr: (path, cb) => {
|
|
|
|
return cb(0, {
|
|
|
|
mtime: new Date(),
|
|
|
|
atime: new Date(),
|
|
|
|
ctime: new Date(),
|
|
|
|
nlink: 1,
|
|
|
|
size: 100,
|
|
|
|
mode: 16877,
|
|
|
|
uid: process.getuid ? process.getuid() : 0,
|
|
|
|
gid: process.getgid ? process.getgid() : 0
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
f.mount()
|
|
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
if (global.gc) gc()
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
// setTimeout(function () {
|
|
|
|
// foo = null
|
|
|
|
// console.log('now!')
|
|
|
|
// }, 5000)
|