@ -18,6 +18,10 @@
# include <sys/wait.h>
# include <pthread.h>
static int IS_ARRAY_BUFFER_DETACH_SUPPORTED = 0 ;
napi_status napi_detach_arraybuffer ( napi_env env , napi_value buf ) ;
# define FUSE_NATIVE_CALLBACK(fn, blk)\
napi_env env = ft - > env ; \
napi_handle_scope scope ; \
@ -43,7 +47,7 @@
uint32_t op = op_ # # name ; \
FUSE_NATIVE_CALLBACK ( ft - > handlers [ op ] , { \
napi_value argv [ callbackArgs + 2 ] ; \
napi_ create_external_buffer( env , sizeof ( fuse_thread_locals_t ) , l , & fin , NULL , & ( argv [ 0 ] ) ) ; \
napi_ get_reference_value( env , l - > self , & ( argv [ 0 ] ) ) ; \
napi_create_uint32 ( env , l - > op , & ( argv [ 1 ] ) ) ; \
callbackBlk \
NAPI_MAKE_CALLBACK ( env , NULL , ctx , callback , callbackArgs + 2 , argv , NULL ) \
@ -116,6 +120,7 @@ typedef struct {
pthread_t thread ;
pthread_attr_t attr ;
napi_ref ctx ;
napi_ref malloc ;
// Operation handlers
napi_ref handlers [ 35 ] ;
@ -132,6 +137,8 @@ typedef struct {
} fuse_thread_t ;
typedef struct {
napi_ref self ;
// Opcode
uint32_t op ;
void * op_fn ;
@ -175,15 +182,11 @@ typedef struct {
} fuse_thread_locals_t ;
static pthread_key_t thread_locals_key ;
static fuse_thread_locals_t * get_thread_locals ( ) ;
static fuse_thread_locals_t * get_thread_locals ( ) ;
// Helpers
// TODO: Extract into a separate file.
static void fin ( napi_env env , void * fin_data , void * fin_hint ) {
// noop
}
static uint64_t uint32s_to_uint64 ( uint32_t * * ints ) {
uint64_t low = * ( ( * ints ) + + ) ;
uint64_t high = * ( ( * ints ) + + ) ;
@ -367,7 +370,7 @@ FUSE_METHOD_VOID(releasedir, 2, 0, (const char *path, struct fuse_file_info *inf
}
} )
FUSE_METHOD ( read , 6 , 1 , ( const char * path , char * buf , size_t len , off_t offset , struct fuse_file_info * info ) , {
FUSE_METHOD ( read , 6 , 2 , ( const char * path , char * buf , size_t len , off_t offset , struct fuse_file_info * info ) , {
l - > path = path ;
l - > buf = buf ;
l - > len = len ;
@ -376,14 +379,14 @@ FUSE_METHOD(read, 6, 1, (const char *path, char *buf, size_t len, off_t offset,
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_uint32 ( env , l - > info - > fh , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > len , ( char * ) l - > buf , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > len , ( char * ) l - > buf , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , l - > len , & ( argv [ 5 ] ) ) ;
FUSE_UINT64_TO_INTS_ARGV ( l - > offset , 6 )
} , {
// TODO: handle bytes processed?
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 3 ] ) = = napi_ok ) ;
} )
FUSE_METHOD ( write , 6 , 1 , ( const char * path , const char * buf , size_t len , off_t offset , struct fuse_file_info * info ) , {
FUSE_METHOD ( write , 6 , 2 , ( const char * path , const char * buf , size_t len , off_t offset , struct fuse_file_info * info ) , {
l - > path = path ;
l - > buf = buf ;
l - > len = len ;
@ -392,11 +395,11 @@ FUSE_METHOD(write, 6, 1, (const char *path, const char *buf, size_t len, off_t o
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_uint32 ( env , l - > info - > fh , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > len , ( char * ) l - > buf , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > len , ( char * ) l - > buf , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , l - > len , & ( argv [ 5 ] ) ) ;
FUSE_UINT64_TO_INTS_ARGV ( l - > offset , 6 )
} , {
// TODO: handle bytes processed?
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 3 ] ) = = napi_ok ) ;
} )
FUSE_METHOD ( readdir , 1 , 2 , ( const char * path , void * buf , fuse_fill_dir_t filler , off_t offset , struct fuse_file_info * info ) , {
@ -446,7 +449,7 @@ FUSE_METHOD(readdir, 1, 2, (const char *path, void *buf, fuse_fill_dir_t filler,
# ifdef __APPLE__
FUSE_METHOD _VOID ( setxattr , 5 , 0 , ( const char * path , const char * name , const char * value , size_t size , int flags , uint32_t position ) , {
FUSE_METHOD ( setxattr , 5 , 1 , ( const char * path , const char * name , const char * value , size_t size , int flags , uint32_t position ) , {
l - > path = path ;
l - > name = name ;
l - > value = value ;
@ -456,12 +459,14 @@ FUSE_METHOD_VOID(setxattr, 5, 0, (const char *path, const char *name, const char
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_string_utf8 ( env , l - > name , NAPI_AUTO_LENGTH , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , l - > position , & ( argv [ 5 ] ) ) ;
napi_create_uint32 ( env , l - > flags , & ( argv [ 6 ] ) ) ;
} , {
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 2 ] ) = = napi_ok ) ;
} )
FUSE_METHOD _VOID ( getxattr , 4 , 0 , ( const char * path , const char * name , char * value , size_t size , uint32_t position ) , {
FUSE_METHOD ( getxattr , 4 , 1 , ( const char * path , const char * name , char * value , size_t size , uint32_t position ) , {
l - > path = path ;
l - > name = name ;
l - > value = value ;
@ -470,13 +475,15 @@ FUSE_METHOD_VOID(getxattr, 4, 0, (const char *path, const char *name, char *valu
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_string_utf8 ( env , l - > name , NAPI_AUTO_LENGTH , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , l - > position , & ( argv [ 5 ] ) ) ;
} , {
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 2 ] ) = = napi_ok ) ;
} )
# else
FUSE_METHOD _VOID ( setxattr , 5 , 0 , ( const char * path , const char * name , const char * value , size_t size , int flags ) , {
FUSE_METHOD ( setxattr , 5 , 1 , ( const char * path , const char * name , const char * value , size_t size , int flags ) , {
l - > path = path ;
l - > name = name ;
l - > value = value ;
@ -485,12 +492,14 @@ FUSE_METHOD_VOID(setxattr, 5, 0, (const char *path, const char *name, const char
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_string_utf8 ( env , l - > name , NAPI_AUTO_LENGTH , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , 0 , & ( argv [ 5 ] ) ) ; // normalize apis between mac and linux
napi_create_uint32 ( env , l - > flags , & ( argv [ 6 ] ) ) ;
} , {
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 2 ] ) = = napi_ok ) ;
} )
FUSE_METHOD _VOID ( getxattr , 4 , 0 , ( const char * path , const char * name , char * value , size_t size ) , {
FUSE_METHOD ( getxattr , 4 , 1 , ( const char * path , const char * name , char * value , size_t size ) , {
l - > path = path ;
l - > name = name ;
l - > value = value ;
@ -498,19 +507,23 @@ FUSE_METHOD_VOID(getxattr, 4, 0, (const char *path, const char *name, char *valu
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_string_utf8 ( env , l - > name , NAPI_AUTO_LENGTH , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , & fin , NULL , & ( argv [ 4 ] ) ) ;
napi_create_external_buffer ( env , l - > size , ( char * ) l - > value , NULL , NULL , & ( argv [ 4 ] ) ) ;
napi_create_uint32 ( env , 0 , & ( argv [ 5 ] ) ) ;
} , {
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 2 ] ) = = napi_ok ) ;
} )
# endif
FUSE_METHOD _VOID ( listxattr , 2 , 0 , ( const char * path , char * list , size_t size ) , {
FUSE_METHOD ( listxattr , 2 , 1 , ( const char * path , char * list , size_t size ) , {
l - > path = path ;
l - > list = list ;
l - > size = size ;
} , {
napi_create_string_utf8 ( env , l - > path , NAPI_AUTO_LENGTH , & ( argv [ 2 ] ) ) ;
napi_create_external_buffer ( env , l - > size , l - > list , & fin , NULL , & ( argv [ 3 ] ) ) ;
napi_create_external_buffer ( env , l - > size , l - > list , NULL , NULL , & ( argv [ 3 ] ) ) ;
} , {
if ( IS_ARRAY_BUFFER_DETACH_SUPPORTED = = 1 ) assert ( napi_detach_arraybuffer ( env , argv [ 2 ] ) = = napi_ok ) ;
} )
FUSE_METHOD_VOID ( removexattr , 2 , 0 , ( const char * path , const char * name ) , {
@ -670,8 +683,10 @@ FUSE_METHOD_VOID(rmdir, 1, 0, (const char *path), {
static void fuse_native_dispatch_init ( uv_async_t * handle , fuse_thread_locals_t * l , fuse_thread_t * ft ) { \
FUSE_NATIVE_CALLBACK ( ft - > handlers [ op_init ] , {
napi_value argv [ 2 ] ;
napi_create_external_buffer ( env , sizeof ( fuse_thread_locals_t ) , l , & fin , NULL , & ( argv [ 0 ] ) ) ;
napi_get_reference_value ( env , l - > self , & ( argv [ 0 ] ) ) ;
napi_create_uint32 ( env , l - > op , & ( argv [ 1 ] ) ) ;
NAPI_MAKE_CALLBACK ( env , NULL , ctx , callback , 2 , argv , NULL ) ;
} )
}
@ -687,10 +702,13 @@ NAPI_METHOD(fuse_native_signal_init) {
static void * fuse_native_init ( struct fuse_conn_info * conn ) {
fuse_thread_locals_t * l = get_thread_locals ( ) ;
l - > op = op_init ;
l - > op_fn = fuse_native_dispatch_init ;
uv_async_send ( & ( l - > async ) ) ;
uv_sem_wait ( & ( l - > sem ) ) ;
return l - > fuse ;
}
@ -700,12 +718,27 @@ static void fuse_native_dispatch (uv_async_t* handle) {
fuse_thread_locals_t * l = ( fuse_thread_locals_t * ) handle - > data ;
fuse_thread_t * ft = l - > fuse ;
void ( * fn ) ( uv_async_t * , fuse_thread_locals_t * , fuse_thread_t * ) = l - > op_fn ;
fn ( handle , l , ft ) ;
}
static void fuse_native_async_init ( uv_async_t * handle ) {
fuse_thread_locals_t * l = ( fuse_thread_locals_t * ) handle - > data ;
fuse_thread_t * ft = l - > fuse ;
fuse_thread_t * ft = ( fuse_thread_t * ) handle - > data ;
fuse_thread_locals_t * l ;
FUSE_NATIVE_CALLBACK ( ft - > malloc , {
napi_value argv [ 1 ] ;
napi_create_uint32 ( ft - > env , ( uint32_t ) sizeof ( fuse_thread_locals_t ) , & ( argv [ 0 ] ) ) ;
napi_value buf ;
NAPI_MAKE_CALLBACK ( ft - > env , NULL , ctx , callback , 1 , argv , & buf ) ;
size_t l_len ;
napi_get_buffer_info ( env , buf , ( void * * ) & l , & l_len ) ;
napi_create_reference ( env , buf , 1 , & ( l - > self ) ) ;
} )
int err = uv_async_init ( uv_default_loop ( ) , & ( l - > async ) , ( uv_async_cb ) fuse_native_dispatch ) ;
assert ( err > = 0 ) ;
@ -714,6 +747,8 @@ static void fuse_native_async_init (uv_async_t* handle) {
uv_sem_init ( & ( l - > sem ) , 0 ) ;
l - > async . data = l ;
ft - > async . data = l ;
l - > fuse = ft ;
uv_sem_post ( & ( ft - > sem ) ) ;
}
@ -725,21 +760,18 @@ static fuse_thread_locals_t* get_thread_locals () {
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 ;
// Need to lock the mutation of l->async.
uv_mutex_lock ( & ( ft - > mut ) ) ;
ft - > async . data = l ;
ft - > async . data = ft ;
// Notify the main thread to uv_async_init l->async.
uv_async_send ( & ( ft - > async ) ) ;
uv_sem_wait ( & ( ft - > sem ) ) ;
l - > async . data = l ;
fuse_thread_locals_t * l = ( fuse_thread_locals_t * ) ft - > async . data ;
pthread_setspecific ( thread_locals_key , ( void * ) l ) ;
uv_mutex_unlock ( & ( ft - > mut ) ) ;
@ -759,14 +791,15 @@ static void* start_fuse_thread (void *data) {
}
NAPI_METHOD ( fuse_native_mount ) {
NAPI_ARGV ( 6 )
NAPI_ARGV ( 7 )
NAPI_ARGV_UTF8 ( mnt , 1024 , 0 ) ;
NAPI_ARGV_UTF8 ( mntopts , 1024 , 1 ) ;
NAPI_ARGV_BUFFER_CAST ( fuse_thread_t * , ft , 2 ) ;
napi_create_reference ( env , argv [ 3 ] , 1 , & ( ft - > ctx ) ) ;
napi_value handlers = argv [ 4 ] ;
NAPI_ARGV_BUFFER_CAST ( uint32_t * , implemented , 5 )
napi_create_reference ( env , argv [ 4 ] , 1 , & ( ft - > malloc ) ) ;
napi_value handlers = argv [ 5 ] ;
NAPI_ARGV_BUFFER_CAST ( uint32_t * , implemented , 6 )
for ( int i = 0 ; i < 35 ; i + + ) {
ft - > handlers [ i ] = NULL ;
@ -869,6 +902,13 @@ NAPI_METHOD(fuse_native_unmount) {
}
NAPI_INIT ( ) {
const napi_node_version * version ;
assert ( napi_get_node_version ( env , & version ) = = napi_ok ) ;
if ( version - > major > 12 | | ( version - > major = = 12 & & version - > minor > = 16 ) ) {
IS_ARRAY_BUFFER_DETACH_SUPPORTED = 1 ;
}
pthread_key_create ( & ( thread_locals_key ) , NULL ) ; // TODO: add destructor
NAPI_EXPORT_SIZEOF ( fuse_thread_t )