X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=Fuse.xs;h=a9d70ed6cddae9ae189ed594df4e672bb016c9f9;hb=48e91793fca961bcf8c0cda9b62aa9deb722a45a;hp=9574fdd7dfa73edce8e7c7aa22cd1ba21da734c1;hpb=6fd3b1c8bbfdf8b1ee8e9613b9121f5205660633;p=perl-fuse.git diff --git a/Fuse.xs b/Fuse.xs index 9574fdd..a9d70ed 100755 --- a/Fuse.xs +++ b/Fuse.xs @@ -1,33 +1,121 @@ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" +#include + +#if (defined(__FreeBSD__) && !defined(__APPLE__)) || defined(__NetBSD__) +# define XATTR_CREATE 1 +# define XATTR_REPLACE 2 +#else +# include +#endif + +#if defined(__linux__) +# define STAT_NSEC(st, st_xtim) ((st)->st_xtim.tv_nsec) +#else +# define STAT_NSEC(st, st_xtim) ((st)->st_xtim##espec.tv_nsec) +#endif + +/* Implement a macro to handle multiple formats (integer, float, and array + * containing seconds and nanoseconds). */ +#define PULL_TIME(st, st_xtim, svp) \ +{ \ + SV *sv = svp; \ + if (SvROK(sv)) { \ + AV *av = (AV *)SvRV(sv); \ + if (SvTYPE((SV *)av) != SVt_PVAV) { \ + Perl_croak_nocontext("Reference was not array ref"); \ + } \ + if (av_len(av) != 1) { \ + Perl_croak_nocontext("Array of incorrect dimension"); \ + } \ + (st)->st_xtim##e = SvIV(*(av_fetch(av, 0, FALSE))); \ + STAT_NSEC(st, st_xtim) = SvIV(*(av_fetch(av, 1, FALSE))); \ + } \ + else if (SvNOK(sv) || SvIOK(sv)) { \ + double tm = SvNV(sv); \ + (st)->st_xtim##e = (int)tm; \ + STAT_NSEC(st, st_xtim) = (tm - (int)tm) * 1000000000; \ + } \ + else { \ + Perl_croak_nocontext("Invalid data type passed"); \ + } \ +} + +/* Determine if threads support should be included */ #ifdef USE_ITHREADS # ifdef I_PTHREAD -/* perl implements threads with pthread. So, we use the pthread API for - * handling thread-local storage. */ -# include -PerlInterpreter *master_interp = NULL; -static inline void create_perl_context() { - if(master_interp) { - PerlInterpreter *me = PERL_GET_CONTEXT; - if(!me) { - PERL_SET_CONTEXT(master_interp); - me = perl_clone(master_interp, CLONEf_CLONE_HOST); - } - } -} -# define FUSE_CONTEXT_PRE create_perl_context(); { dSP -# define FUSE_CONTEXT_POST } # define FUSE_USE_ITHREADS +# if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION < 9) +# define tTHX PerlInterpreter* +# define STR_WITH_LEN(s) ("" s ""), (sizeof(s)-1) +# define hv_fetchs(hv,key,lval) Perl_hv_fetch(aTHX_ hv, STR_WITH_LEN(key), lval) +# define dMY_CXT_INTERP(interp) \ + SV *my_cxt_sv = *hv_fetchs(interp->Imodglobal, MY_CXT_KEY, TRUE); \ + my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)) +# endif # else -# error "Sorry, I don't know how to handle ithreads on this architecture." +# warning "Sorry, I don't know how to handle ithreads on this architecture. Building non-threaded version" # endif +#endif + +/* Global Data */ + +#define MY_CXT_KEY "Fuse::_guts" XS_VERSION +#if FUSE_VERSION >= 28 +# define N_CALLBACKS 41 +#else +# define N_CALLBACKS 38 +#endif + +typedef struct { + SV *callback[N_CALLBACKS]; + HV *handles; +#ifdef USE_ITHREADS + tTHX self; +#endif + int threaded; +#ifdef USE_ITHREADS + perl_mutex mutex; +#endif + int utimens_as_array; +} my_cxt_t; +START_MY_CXT; + +#ifdef FUSE_USE_ITHREADS +tTHX master_interp = NULL; + +#define CLONE_INTERP(parent) S_clone_interp(parent) +tTHX S_clone_interp(tTHX parent) { +# if (PERL_VERSION < 10) + tTHX my_perl = parent; +#endif + dMY_CXT_INTERP(parent); + if(MY_CXT.threaded) { + MUTEX_LOCK(&MY_CXT.mutex); + PERL_SET_CONTEXT(parent); + dTHX; +#if (PERL_VERSION > 10) || (PERL_VERSION == 10 && PERL_SUBVERSION >= 1) + tTHX child = perl_clone(parent, CLONEf_CLONE_HOST); +#else + tTHX child = perl_clone(parent, CLONEf_CLONE_HOST | CLONEf_KEEP_PTR_TABLE); + ptr_table_free(PL_ptr_table); + PL_ptr_table = NULL; +#endif + MUTEX_UNLOCK(&MY_CXT.mutex); + return child; + } + return NULL; +} + +# define FUSE_CONTEXT_PRE dTHX; if(!aTHX) aTHX = CLONE_INTERP(master_interp); { dMY_CXT; dSP; +# define FUSE_CONTEXT_POST } #else -# define FUSE_CONTEXT_PRE dSP +# define FUSE_CONTEXT_PRE dTHX; dMY_CXT; dSP; # define FUSE_CONTEXT_POST #endif -#include #undef DEBUGf #if 0 @@ -36,8 +124,48 @@ static inline void create_perl_context() { #define DEBUGf(a...) #endif -#define N_CALLBACKS 25 -SV *_PLfuse_callbacks[N_CALLBACKS]; +#define FH_KEY(fi) sv_2mortal(newSViv((fi)->fh)) +#define FH_GETHANDLE(fi) S_fh_get_handle(aTHX_ aMY_CXT_ fi) +#define FH_STOREHANDLE(fi,sv) S_fh_store_handle(aTHX_ aMY_CXT_ fi, sv) +#define FH_RELEASEHANDLE(fi) S_fh_release_handle(aTHX_ aMY_CXT_ fi) + +SV *S_fh_get_handle(pTHX_ pMY_CXT_ struct fuse_file_info *fi) { + SV *val; + val = &PL_sv_undef; + if(fi->fh != 0) { + HE *he; + if((he = hv_fetch_ent(MY_CXT.handles, FH_KEY(fi), 0, 0))) { + val = HeVAL(he); + SvGETMAGIC(val); + } + } + return val; +} + +void S_fh_release_handle(pTHX_ pMY_CXT_ struct fuse_file_info *fi) { + if(fi->fh != 0) { + (void)hv_delete_ent(MY_CXT.handles, FH_KEY(fi), G_DISCARD, 0); + fi->fh = 0; + } +} + +void S_fh_store_handle(pTHX_ pMY_CXT_ struct fuse_file_info *fi, SV *sv) { + if(SvOK(sv)) { +#ifdef FUSE_USE_ITHREADS + if(MY_CXT.threaded) { + SvSHARE(sv); + } +#endif + /* This seems to be screwing things up... */ + // MAGIC *mg = (SvTYPE(sv) == SVt_PVMG) ? mg_find(sv, PERL_MAGIC_shared_scalar) : NULL; + // fi->fh = mg ? PTR2IV(mg->mg_ptr) : PTR2IV(sv); + fi->fh = PTR2IV(sv); + if(hv_store_ent(MY_CXT.handles, FH_KEY(fi), SvREFCNT_inc(sv), 0) == NULL) { + SvREFCNT_dec(sv); + } + SvSETMAGIC(sv); + } +} int _PLfuse_getattr(const char *file, struct stat *result) { int rv; @@ -48,7 +176,7 @@ int _PLfuse_getattr(const char *file, struct stat *result) { PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,strlen(file)))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[0],G_ARRAY); + rv = call_sv(MY_CXT.callback[0],G_ARRAY); SPAGAIN; if(rv != 13) { if(rv > 1) { @@ -61,9 +189,9 @@ int _PLfuse_getattr(const char *file, struct stat *result) { } else { result->st_blocks = POPi; result->st_blksize = POPi; - result->st_ctime = POPi; - result->st_mtime = POPi; - result->st_atime = POPi; + PULL_TIME(result, st_ctim, POPs); + PULL_TIME(result, st_mtim, POPs); + PULL_TIME(result, st_atim, POPs); result->st_size = POPn; // we pop double here to support files larger than 4Gb (long limit) result->st_rdev = POPi; result->st_gid = POPi; @@ -84,16 +212,16 @@ int _PLfuse_getattr(const char *file, struct stat *result) { int _PLfuse_readlink(const char *file,char *buf,size_t buflen) { int rv; - FUSE_CONTEXT_PRE; if(buflen < 1) return EINVAL; + FUSE_CONTEXT_PRE; DEBUGf("readlink begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[1],G_SCALAR); + rv = call_sv(MY_CXT.callback[1],G_SCALAR); SPAGAIN; if(!rv) rv = -ENOENT; @@ -115,15 +243,9 @@ int _PLfuse_readlink(const char *file,char *buf,size_t buflen) { return rv; } -#if 0 -/* - * This doesn't yet work... we alwas get ENOSYS when trying to use readdir(). - * Well, of course, getdir() is fine as well. - */ - int _PLfuse_readdir(const char *file, void *dirh, fuse_fill_dir_t dirfil, off_t off, struct fuse_file_info *fi) { -#endif int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) { int prv, rv; + SV **swp; FUSE_CONTEXT_PRE; DEBUGf("getdir begin\n"); ENTER; @@ -131,12 +253,17 @@ int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) { PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); PUTBACK; - prv = call_sv(_PLfuse_callbacks[2],G_ARRAY); + prv = call_sv(MY_CXT.callback[2],G_ARRAY); SPAGAIN; if(prv) { + /* Should yield the bottom of the current stack... */ + swp = &TOPs - prv + 1; rv = POPi; - while(--prv) - dirfil(dirh,POPp,0,0); + /* Sort of a hack to walk the stack in order, instead of reverse + * order - trying to explain to potential users why they need to + * reverse the order of this array would be confusing, at best. */ + while (swp <= &TOPs) + dirfil(dirh,SvPVx_nolen(*(swp++)),0,0); } else { fprintf(stderr,"getdir() handler returned nothing!\n"); rv = -ENOSYS; @@ -160,12 +287,9 @@ int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) { XPUSHs(sv_2mortal(newSViv(mode))); XPUSHs(sv_2mortal(newSViv(dev))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[3],G_SCALAR); + rv = call_sv(MY_CXT.callback[3],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -184,12 +308,9 @@ int _PLfuse_mkdir (const char *file, mode_t mode) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSViv(mode))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[4],G_SCALAR); + rv = call_sv(MY_CXT.callback[4],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -208,12 +329,9 @@ int _PLfuse_unlink (const char *file) { PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[5],G_SCALAR); + rv = call_sv(MY_CXT.callback[5],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -231,12 +349,9 @@ int _PLfuse_rmdir (const char *file) { PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[6],G_SCALAR); + rv = call_sv(MY_CXT.callback[6],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -255,12 +370,9 @@ int _PLfuse_symlink (const char *file, const char *new) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSVpv(new,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[7],G_SCALAR); + rv = call_sv(MY_CXT.callback[7],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -279,12 +391,9 @@ int _PLfuse_rename (const char *file, const char *new) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSVpv(new,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[8],G_SCALAR); + rv = call_sv(MY_CXT.callback[8],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -303,12 +412,9 @@ int _PLfuse_link (const char *file, const char *new) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSVpv(new,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[9],G_SCALAR); + rv = call_sv(MY_CXT.callback[9],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -327,12 +433,9 @@ int _PLfuse_chmod (const char *file, mode_t mode) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSViv(mode))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[10],G_SCALAR); + rv = call_sv(MY_CXT.callback[10],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -352,12 +455,9 @@ int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) { XPUSHs(sv_2mortal(newSViv(uid))); XPUSHs(sv_2mortal(newSViv(gid))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[11],G_SCALAR); + rv = call_sv(MY_CXT.callback[11],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -380,17 +480,15 @@ int _PLfuse_truncate (const char *file, off_t off) { #ifdef PERL_HAS_64BITINT XPUSHs(sv_2mortal(newSViv(off))); #else - asprintf(&temp, "%llu", off); + if (asprintf(&temp, "%llu", off) == -1) + croak("Memory allocation failure!"); XPUSHs(sv_2mortal(newSVpv(temp, 0))); free(temp); #endif PUTBACK; - rv = call_sv(_PLfuse_callbacks[12],G_SCALAR); + rv = call_sv(MY_CXT.callback[12],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -410,12 +508,9 @@ int _PLfuse_utime (const char *file, struct utimbuf *uti) { XPUSHs(sv_2mortal(newSViv(uti->actime))); XPUSHs(sv_2mortal(newSViv(uti->modtime))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[13],G_SCALAR); + rv = call_sv(MY_CXT.callback[13],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -440,34 +535,21 @@ int _PLfuse_open (const char *file, struct fuse_file_info *fi) { */ fi->fh = 0; /* Ensure it starts with 0 - important if they don't set it */ fihash = newHV(); -#if FUSE_VERSION >= 24 - hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0); - hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0); -#endif -#if FUSE_VERSION >= 29 - hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0); + (void) hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0); + (void) hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0); +#if FUSE_VERSION >= 28 + (void) hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0); #endif XPUSHs(sv_2mortal(newRV_noinc((SV*) fihash))); /* All hashref things done */ PUTBACK; /* Open called with filename, flags */ - rv = call_sv(_PLfuse_callbacks[14],G_ARRAY); + rv = call_sv(MY_CXT.callback[14],G_ARRAY); SPAGAIN; - if(rv) - { - SV *sv; - if (rv > 1) - { - sv = POPs; - if (SvOK(sv)) - { - /* We're holding on to the sv reference until - * after exit of this function, so we need to - * increment its reference count - */ - fi->fh = SvREFCNT_inc(sv); - } + if(rv) { + if(rv > 1) { + FH_STOREHANDLE(fi,POPs); } rv = POPi; } @@ -476,25 +558,14 @@ int _PLfuse_open (const char *file, struct fuse_file_info *fi) { if (rv == 0) { /* Success, so copy the file handle which they returned */ -#if FUSE_VERSION >= 24 SV **svp; - svp = hv_fetch(fihash, "direct_io", 9, 0); - if (svp != NULL) - { - fi->direct_io = SvIV(*svp); - } - svp = hv_fetch(fihash, "keep_cache", 10, 0); - if (svp != NULL) - { - fi->keep_cache = SvIV(*svp); - } -#endif -#if FUSE_VERSION >= 29 - svp = hv_fetch(fihash, "nonseekable", 11, 0); - if (svp != NULL) - { - fi->nonseekable = SvIV(*svp); - } + if ((svp = hv_fetch(fihash, "direct_io", 9, 0)) != NULL) + fi->direct_io = SvIV(*svp); + if ((svp = hv_fetch(fihash, "keep_cache", 10, 0)) != NULL) + fi->keep_cache = SvIV(*svp); +#if FUSE_VERSION >= 28 + if ((svp = hv_fetch(fihash, "nonseekable", 11, 0)) != NULL) + fi->nonseekable = SvIV(*svp); #endif } FREETMPS; @@ -505,7 +576,8 @@ int _PLfuse_open (const char *file, struct fuse_file_info *fi) { return rv; } -int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) { +int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, + struct fuse_file_info *fi) { int rv; #ifndef PERL_HAS_64BITINT char *temp; @@ -515,18 +587,19 @@ int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, struct ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); XPUSHs(sv_2mortal(newSViv(buflen))); #ifdef PERL_HAS_64BITINT XPUSHs(sv_2mortal(newSViv(off))); #else - asprintf(&temp, "%llu", off); + if (asprintf(&temp, "%llu", off) == -1) + croak("Memory allocation failure!"); XPUSHs(sv_2mortal(newSVpv(temp, 0))); free(temp); #endif - XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh); + XPUSHs(FH_GETHANDLE(fi)); PUTBACK; - rv = call_sv(_PLfuse_callbacks[15],G_SCALAR); + rv = call_sv(MY_CXT.callback[15],G_SCALAR); SPAGAIN; if(!rv) rv = -ENOENT; @@ -564,23 +637,21 @@ int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off, ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); XPUSHs(sv_2mortal(newSVpvn(buf,buflen))); #ifdef PERL_HAS_64BITINT XPUSHs(sv_2mortal(newSViv(off))); #else - asprintf(&temp, "%llu", off); + if (asprintf(&temp, "%llu", off) == -1) + croak("Memory allocation failure!"); XPUSHs(sv_2mortal(newSVpv(temp, 0))); free(temp); #endif - XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh); + XPUSHs(FH_GETHANDLE(fi)); PUTBACK; - rv = call_sv(_PLfuse_callbacks[16],G_SCALAR); + rv = call_sv(MY_CXT.callback[16],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -597,7 +668,7 @@ int _PLfuse_statfs (const char *file, struct statvfs *st) { SAVETMPS; PUSHMARK(SP); PUTBACK; - rv = call_sv(_PLfuse_callbacks[17],G_ARRAY); + rv = call_sv(MY_CXT.callback[17],G_ARRAY); SPAGAIN; DEBUGf("statfs got %i params\n",rv); if(rv == 6 || rv == 7) { @@ -641,15 +712,12 @@ int _PLfuse_flush (const char *file, struct fuse_file_info *fi) { ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(file,0))); - XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); + XPUSHs(FH_GETHANDLE(fi)); PUTBACK; - rv = call_sv(_PLfuse_callbacks[18],G_SCALAR); + rv = call_sv(MY_CXT.callback[18],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -666,24 +734,14 @@ int _PLfuse_release (const char *file, struct fuse_file_info *fi) { ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); XPUSHs(sv_2mortal(newSViv(flags))); - XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh); + XPUSHs(FH_GETHANDLE(fi)); PUTBACK; - rv = call_sv(_PLfuse_callbacks[19],G_SCALAR); + rv = call_sv(MY_CXT.callback[19],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; - /* We're now finished with the handle that we were given, so - * we should decrement its count so that it can be freed. - */ - if (fi->fh != 0) - { - SvREFCNT_dec((SV *)fi->fh); - fi->fh = 0; - } + rv = (rv ? POPi : 0); + FH_RELEASEHANDLE(fi); FREETMPS; LEAVE; PUTBACK; @@ -700,16 +758,13 @@ int _PLfuse_fsync (const char *file, int datasync, struct fuse_file_info *fi) { ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); XPUSHs(sv_2mortal(newSViv(flags))); - XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh); + XPUSHs(FH_GETHANDLE(fi)); PUTBACK; - rv = call_sv(_PLfuse_callbacks[20],G_SCALAR); + rv = call_sv(MY_CXT.callback[20],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -718,7 +773,11 @@ int _PLfuse_fsync (const char *file, int datasync, struct fuse_file_info *fi) { return rv; } +#ifdef __APPLE__ +int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags, uint32_t position) { +#else int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) { +#endif int rv; FUSE_CONTEXT_PRE; DEBUGf("setxattr begin\n"); @@ -730,12 +789,9 @@ int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_ XPUSHs(sv_2mortal(newSVpvn(buf,buflen))); XPUSHs(sv_2mortal(newSViv(flags))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[21],G_SCALAR); + rv = call_sv(MY_CXT.callback[21],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -744,7 +800,11 @@ int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_ return rv; } +#ifdef __APPLE__ +int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen, uint32_t position) { +#else int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) { +#endif int rv; FUSE_CONTEXT_PRE; DEBUGf("getxattr begin\n"); @@ -754,7 +814,7 @@ int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t bufl XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSVpv(name,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[22],G_SCALAR); + rv = call_sv(MY_CXT.callback[22],G_SCALAR); SPAGAIN; if(!rv) rv = -ENOENT; @@ -796,7 +856,7 @@ int _PLfuse_listxattr (const char *file, char *list, size_t size) { PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); PUTBACK; - prv = call_sv(_PLfuse_callbacks[23],G_ARRAY); + prv = call_sv(MY_CXT.callback[23],G_ARRAY); SPAGAIN; if(!prv) rv = -ENOENT; @@ -861,12 +921,9 @@ int _PLfuse_removexattr (const char *file, const char *name) { XPUSHs(sv_2mortal(newSVpv(file,0))); XPUSHs(sv_2mortal(newSVpv(name,0))); PUTBACK; - rv = call_sv(_PLfuse_callbacks[24],G_SCALAR); + rv = call_sv(MY_CXT.callback[24],G_SCALAR); SPAGAIN; - if(rv) - rv = POPi; - else - rv = 0; + rv = (rv ? POPi : 0); FREETMPS; LEAVE; PUTBACK; @@ -875,107 +932,828 @@ int _PLfuse_removexattr (const char *file, const char *name) { return rv; } -struct fuse_operations _available_ops = { -getattr: _PLfuse_getattr, -readlink: _PLfuse_readlink, -getdir: _PLfuse_getdir, -#if 0 -readdir: _PLfuse_readdir, -#endif -mknod: _PLfuse_mknod, -mkdir: _PLfuse_mkdir, -unlink: _PLfuse_unlink, -rmdir: _PLfuse_rmdir, -symlink: _PLfuse_symlink, -rename: _PLfuse_rename, -link: _PLfuse_link, -chmod: _PLfuse_chmod, -chown: _PLfuse_chown, -truncate: _PLfuse_truncate, -utime: _PLfuse_utime, -open: _PLfuse_open, -read: _PLfuse_read, -write: _PLfuse_write, -statfs: _PLfuse_statfs, -flush: _PLfuse_flush, -release: _PLfuse_release, -fsync: _PLfuse_fsync, -setxattr: _PLfuse_setxattr, -getxattr: _PLfuse_getxattr, -listxattr: _PLfuse_listxattr, -removexattr: _PLfuse_removexattr, -}; - -MODULE = Fuse PACKAGE = Fuse -PROTOTYPES: DISABLE +int _PLfuse_opendir(const char *file, struct fuse_file_info *fi) { + int rv; + FUSE_CONTEXT_PRE; + DEBUGf("opendir begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + fi->fh = 0; /* Ensure it starts with 0 - important if they don't set it */ + PUTBACK; + rv = call_sv(MY_CXT.callback[25], G_ARRAY); + SPAGAIN; + if (rv) { + if (rv > 1) { + FH_STOREHANDLE(fi, POPs); + } + rv = POPi; + } else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("opendir end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; -SV* -fuse_get_context() - PREINIT: - struct fuse_context *fc; - CODE: - fc = fuse_get_context(); - if(fc) { - HV *hash = newHV(); - hv_store(hash, "uid", 3, newSViv(fc->uid), 0); - hv_store(hash, "gid", 3, newSViv(fc->gid), 0); - hv_store(hash, "pid", 3, newSViv(fc->pid), 0); - RETVAL = newRV_noinc((SV*)hash); - } else { - XSRETURN_UNDEF; - } - OUTPUT: - RETVAL +} -void -perl_fuse_main(...) - PREINIT: - struct fuse_operations fops = - {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; - int i, debug, threaded; - char *mountpoint; - char *mountopts; - struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); - struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL); - struct fuse_chan *fc; - INIT: - if(items != 29) { - fprintf(stderr,"Perl<->C inconsistency or internal error\n"); - XSRETURN_UNDEF; - } - CODE: - debug = SvIV(ST(0)); - threaded = SvIV(ST(1)); - if(threaded) { -#ifdef FUSE_USE_ITHREADS - master_interp = PERL_GET_CONTEXT; +int _PLfuse_readdir(const char *file, void *dirh, fuse_fill_dir_t dirfil, + off_t off, struct fuse_file_info *fi) { + int prv = 0, rv; + SV *sv, **svp, **swp; + AV *av, *av2; + struct stat st; + bool st_filled = 0; +#ifndef PERL_HAS_64BITINT + char *temp; +#endif + FUSE_CONTEXT_PRE; + DEBUGf("readdir begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); +#ifdef PERL_HAS_64BITINT + XPUSHs(sv_2mortal(newSViv(off))); #else - fprintf(stderr,"FUSE warning: Your script has requested multithreaded " - "mode, but your perl was not built with -Dusethreads. " - "Threads are disabled.\n"); - threaded = 0; + if (asprintf(&temp, "%llu", off) == -1) + croak("Memory allocation failure!"); + XPUSHs(sv_2mortal(newSVpv(temp, 0))); + free(temp); #endif + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + prv = call_sv(MY_CXT.callback[26],G_ARRAY); + SPAGAIN; + if (prv) { + /* Should yield the bottom of the current stack... */ + swp = &TOPs - prv + 1; + rv = POPi; + memset(&st, 0, sizeof(struct stat)); + /* Sort of a hack to walk the stack in order, instead of reverse + * order - trying to explain to potential users why they need to + * reverse the order of this array would be confusing, at best. */ + while (swp <= &TOPs) { + sv = *(swp++); + if (!SvROK(sv) && SvPOK(sv)) + /* Just a bare SV (probably a string; hopefully a string) */ + dirfil(dirh, SvPVx_nolen(sv), NULL, 0); + else if (SvROK(sv) && SvTYPE(av = (AV *)SvRV(sv)) == SVt_PVAV) { + if (av_len(av) >= 2) { + /* The third element of the array should be the args that + * would otherwise go to getattr(); a lot of filesystems + * will, or at least can, return that info as part of the + * enumeration process... */ + svp = av_fetch(av, 2, FALSE); + if (SvROK(*svp) && + SvTYPE(av2 = (AV *)SvRV(*svp)) == SVt_PVAV && + av_len(av2) == 12) { + st.st_dev = SvIV(*(av_fetch(av2, 0, FALSE))); + st.st_ino = SvIV(*(av_fetch(av2, 1, FALSE))); + st.st_mode = SvIV(*(av_fetch(av2, 2, FALSE))); + st.st_nlink = SvIV(*(av_fetch(av2, 3, FALSE))); + st.st_uid = SvIV(*(av_fetch(av2, 4, FALSE))); + st.st_gid = SvIV(*(av_fetch(av2, 5, FALSE))); + st.st_rdev = SvIV(*(av_fetch(av2, 6, FALSE))); + st.st_size = SvNV(*(av_fetch(av2, 7, FALSE))); + PULL_TIME(&st, st_atim, *(av_fetch(av2, 8, FALSE))); + PULL_TIME(&st, st_mtim, *(av_fetch(av2, 9, FALSE))); + PULL_TIME(&st, st_ctim, *(av_fetch(av2, 10, FALSE))); + st.st_blksize = SvIV(*(av_fetch(av2, 11, FALSE))); + st.st_blocks = SvIV(*(av_fetch(av2, 12, FALSE))); + st_filled = 1; + } + else + fprintf(stderr,"Extra SV didn't appear to be correct, ignoring\n"); + /* For now if the element isn't what we want, just + * quietly ignore it... */ + } + if (av_len(av) >= 1) { + char *entryname = SvPVx_nolen(*(av_fetch(av, 1, FALSE))); + off_t elemnum = SvNV(*(av_fetch(av, 0, FALSE))); + dirfil(dirh, entryname, st_filled ? &st : NULL, elemnum); + } + if (st_filled) { + memset(&st, 0, sizeof(struct stat)); + st_filled = 0; + } + } + else + fprintf(stderr, "ERROR: Unknown entry passed via readdir\n"); + } + } else { + fprintf(stderr,"readdir() handler returned nothing!\n"); + rv = -ENOSYS; } - mountpoint = SvPV_nolen(ST(2)); - mountopts = SvPV_nolen(ST(3)); - for(i=0;iflags))); + fi->fh = 0; /* Ensure it starts with 0 - important if they don't set it */ + /* Create a hashref containing the details from fi + * which we can look at or modify. + */ + fihash = newHV(); + (void) hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0); + (void) hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0); +#if FUSE_VERSION >= 28 + (void) hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0); +#endif + XPUSHs(sv_2mortal(newRV_noinc((SV*) fihash))); + /* All hashref things done */ + + PUTBACK; + rv = call_sv(MY_CXT.callback[32], G_ARRAY); + SPAGAIN; + if (rv) { + if (rv > 1) { + FH_STOREHANDLE(fi,POPs); + } + rv = POPi; + } + else { + fprintf(stderr, "create() handler returned nothing!\n"); + rv = -ENOSYS; + } + if (rv == 0) { + /* Success, so copy the file handle which they returned */ + SV **svp; + if ((svp = hv_fetch(fihash, "direct_io", 9, 0)) != NULL) + fi->direct_io = SvIV(*svp); + if ((svp = hv_fetch(fihash, "keep_cache", 10, 0)) != NULL) + fi->keep_cache = SvIV(*svp); +#if FUSE_VERSION >= 28 + if ((svp = hv_fetch(fihash, "nonseekable", 11, 0)) != NULL) + fi->nonseekable = SvIV(*svp); +#endif + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("create end: %d\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_ftruncate(const char *file, off_t off, struct fuse_file_info *fi) { + int rv; +#ifndef PERL_HAS_64BITINT + char *temp; +#endif + FUSE_CONTEXT_PRE; + DEBUGf("ftruncate begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); +#ifdef PERL_HAS_64BITINT + XPUSHs(sv_2mortal(newSViv(off))); +#else + if (asprintf(&temp, "%llu", off) == -1) + croak("Memory allocation failure!"); + XPUSHs(sv_2mortal(newSVpv(temp, 0))); + free(temp); +#endif + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + rv = call_sv(MY_CXT.callback[33],G_SCALAR); + SPAGAIN; + rv = (rv ? POPi : 0); + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("ftruncate end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_fgetattr(const char *file, struct stat *result, + struct fuse_file_info *fi) { + int rv; + FUSE_CONTEXT_PRE; + DEBUGf("fgetattr begin: %s\n",file); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + rv = call_sv(MY_CXT.callback[34],G_ARRAY); + SPAGAIN; + if(rv != 13) { + if(rv > 1) { + fprintf(stderr,"inappropriate number of returned values from getattr\n"); + rv = -ENOSYS; + } else if(rv) + rv = POPi; + else + rv = -ENOENT; + } else { + result->st_blocks = POPi; + result->st_blksize = POPi; + PULL_TIME(result, st_ctim, POPs); + PULL_TIME(result, st_mtim, POPs); + PULL_TIME(result, st_atim, POPs); + result->st_size = POPn; // we pop double here to support files larger than 4Gb (long limit) + result->st_rdev = POPi; + result->st_gid = POPi; + result->st_uid = POPi; + result->st_nlink = POPi; + result->st_mode = POPi; + result->st_ino = POPi; + result->st_dev = POPi; + rv = 0; + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("fgetattr end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_lock(const char *file, struct fuse_file_info *fi, int cmd, + struct flock *lockinfo) { + int rv; + HV *lihash; + SV *sv; +#ifndef PERL_HAS_64BITINT + char *temp; +#endif + FUSE_CONTEXT_PRE; + DEBUGf("lock begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(file ? sv_2mortal(newSVpv(file,0)) : &PL_sv_undef); + XPUSHs(sv_2mortal(newSViv(cmd))); + lihash = newHV(); + if (lockinfo) { + (void) hv_store(lihash, "l_type", 6, newSViv(lockinfo->l_type), 0); + (void) hv_store(lihash, "l_whence", 8, newSViv(lockinfo->l_whence), 0); +#ifdef PERL_HAS_64BITINT + sv = newSViv(lockinfo->l_start); +#else + if (asprintf(&temp, "%llu", lockinfo->l_start) == -1) + croak("Memory allocation failure!"); + sv = newSVpv(temp, 0); + free(temp); +#endif + (void) hv_store(lihash, "l_start", 7, sv, 0); +#ifdef PERL_HAS_64BITINT + sv = newSViv(lockinfo->l_len); +#else + if (asprintf(&temp, "%llu", lockinfo->l_len) == -1) + croak("Memory allocation failure!"); + sv = newSVpv(temp, 0); + free(temp); #endif - _PLfuse_callbacks[i] = var; + (void) hv_store(lihash, "l_len", 5, sv, 0); + (void) hv_store(lihash, "l_pid", 5, newSViv(lockinfo->l_pid), 0); + } + XPUSHs(sv_2mortal(newRV_noinc((SV*) lihash))); + XPUSHs(FH_GETHANDLE(fi)); + + PUTBACK; + rv = call_sv(MY_CXT.callback[35],G_SCALAR); + SPAGAIN; + rv = (rv ? POPi : 0); + if (lockinfo && !rv) { + /* Need to copy back any altered values from the hash into + * the struct... */ + SV **svp; + if ((svp = hv_fetch(lihash, "l_type", 6, 0)) != NULL) + lockinfo->l_type = SvIV(*svp); + if ((svp = hv_fetch(lihash, "l_whence", 8, 0)) != NULL) + lockinfo->l_whence = SvIV(*svp); + if ((svp = hv_fetch(lihash, "l_start", 7, 0)) != NULL) + lockinfo->l_start = SvNV(*svp); + if ((svp = hv_fetch(lihash, "l_len", 5, 0)) != NULL) + lockinfo->l_len = SvNV(*svp); + if ((svp = hv_fetch(lihash, "l_pid", 5, 0)) != NULL) + lockinfo->l_pid = SvIV(*svp); + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("lock end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_utimens(const char *file, const struct timespec tv[2]) { + int rv; + FUSE_CONTEXT_PRE; + DEBUGf("utimens begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + if (MY_CXT.utimens_as_array) { + /* Pushing timespecs as 2-element arrays (if tv is present). */ + AV *av; + if (tv) { + av = newAV(); + av_push(av, newSViv(tv[0].tv_sec)); + av_push(av, newSViv(tv[0].tv_nsec)); + XPUSHs(sv_2mortal(newRV_noinc((SV *)av))); + av = newAV(); + av_push(av, newSViv(tv[1].tv_sec)); + av_push(av, newSViv(tv[1].tv_nsec)); + XPUSHs(sv_2mortal(newRV_noinc((SV *)av))); + } + else { + XPUSHs(&PL_sv_undef); + XPUSHs(&PL_sv_undef); + } + + } + else { + /* Pushing timespecs as floating point (double) values. */ + XPUSHs(tv ? sv_2mortal(newSVnv(tv[0].tv_sec + (tv[0].tv_nsec / 1000000000.0))) : &PL_sv_undef); + XPUSHs(tv ? sv_2mortal(newSVnv(tv[1].tv_sec + (tv[1].tv_nsec / 1000000000.0))) : &PL_sv_undef); + } + PUTBACK; + rv = call_sv(MY_CXT.callback[36],G_SCALAR); + SPAGAIN; + rv = (rv ? POPi : 0); + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("utimens end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_bmap(const char *file, size_t blocksize, uint64_t *idx) { + int rv; +#ifndef PERL_HAS_64BITINT + char *temp; +#endif + FUSE_CONTEXT_PRE; + DEBUGf("bmap begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSViv(blocksize))); +#ifdef PERL_HAS_64BITINT + XPUSHs(sv_2mortal(newSViv(*idx))); +#else + if (asprintf(&temp, "%llu", *idx) == -1) + croak("Memory allocation failure!"); + XPUSHs(sv_2mortal(newSVpv(temp, 0))); + free(temp); +#endif + PUTBACK; + rv = call_sv(MY_CXT.callback[37],G_ARRAY); + SPAGAIN; + if (rv > 0 && rv < 3) { + if (rv == 2) + *idx = POPn; + rv = POPi; + } + else { + fprintf(stderr, "bmap(): wrong number of values returned?\n"); + rv = -ENOSYS; + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("bmap end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +#if FUSE_VERSION >= 28 + +# ifndef __linux__ +# define _IOC_SIZE(n) IOCPARM_LEN(n) +# endif + +int _PLfuse_ioctl(const char *file, int cmd, void *arg, + struct fuse_file_info *fi, unsigned int flags, void *data) { + int rv; + SV *sv = NULL; + FUSE_CONTEXT_PRE; + DEBUGf("ioctl begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + /* I don't know why cmd is a signed int in the first place; + * casting as unsigned so stupid tricks don't have to be done on + * the perl side */ + XPUSHs(sv_2mortal(newSVuv((unsigned int)cmd))); + XPUSHs(sv_2mortal(newSViv(flags))); + if (cmd & IOC_IN) + XPUSHs(sv_2mortal(newSVpvn(data, _IOC_SIZE(cmd)))); + else + XPUSHs(&PL_sv_undef); + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + rv = call_sv(MY_CXT.callback[39],G_ARRAY); + SPAGAIN; + if ((cmd & IOC_OUT) && (rv == 2)) { + sv = POPs; + rv--; + } + + if (rv > 0) + rv = POPi; + + if ((cmd & IOC_OUT) && !rv) { + if (sv) { + size_t len; + char *rdata = SvPV(sv, len); + + if (len > _IOC_SIZE(cmd)) { + fprintf(stderr, "ioctl(): returned data was too large for data area\n"); + rv = -EFBIG; + } + else { + memset(data, 0, _IOC_SIZE(cmd)); + memcpy(data, rdata, len); + } + } + else { + fprintf(stderr, "ioctl(): ioctl was a read op, but no data was returned from call?\n"); + rv = -EFAULT; + } + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("ioctl end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_poll(const char *file, struct fuse_file_info *fi, + struct fuse_pollhandle *ph, unsigned *reventsp) { + int rv; + SV *sv = NULL; + FUSE_CONTEXT_PRE; + DEBUGf("poll begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + if (ph) { + /* Still gotta figure out how to do this right... */ + sv = newSViv(PTR2IV(ph)); + SvREADONLY_on(sv); + SvSHARE(sv); + XPUSHs(sv); + } + else + XPUSHs(&PL_sv_undef); + XPUSHs(sv_2mortal(newSViv(*reventsp))); + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + rv = call_sv(MY_CXT.callback[40],G_ARRAY); + SPAGAIN; + if (rv > 1) { + *reventsp = POPi; + rv--; + } + rv = (rv ? POPi : 0); + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("poll end: %i\n", rv); + FUSE_CONTEXT_POST; + return rv; +} +#endif /* FUSE_VERSION >= 28 */ + +struct fuse_operations _available_ops = { +getattr: _PLfuse_getattr, +readlink: _PLfuse_readlink, +getdir: _PLfuse_getdir, +mknod: _PLfuse_mknod, +mkdir: _PLfuse_mkdir, +unlink: _PLfuse_unlink, +rmdir: _PLfuse_rmdir, +symlink: _PLfuse_symlink, +rename: _PLfuse_rename, +link: _PLfuse_link, +chmod: _PLfuse_chmod, +chown: _PLfuse_chown, +truncate: _PLfuse_truncate, +utime: _PLfuse_utime, +open: _PLfuse_open, +read: _PLfuse_read, +write: _PLfuse_write, +statfs: _PLfuse_statfs, +flush: _PLfuse_flush, +release: _PLfuse_release, +fsync: _PLfuse_fsync, +setxattr: _PLfuse_setxattr, +getxattr: _PLfuse_getxattr, +listxattr: _PLfuse_listxattr, +removexattr: _PLfuse_removexattr, +opendir: _PLfuse_opendir, +readdir: _PLfuse_readdir, +releasedir: _PLfuse_releasedir, +fsyncdir: _PLfuse_fsyncdir, +init: _PLfuse_init, +destroy: _PLfuse_destroy, +access: _PLfuse_access, +create: _PLfuse_create, +ftruncate: _PLfuse_ftruncate, +fgetattr: _PLfuse_fgetattr, +lock: _PLfuse_lock, +utimens: _PLfuse_utimens, +bmap: _PLfuse_bmap, +#if FUSE_VERSION >= 28 +ioctl: _PLfuse_ioctl, +poll: _PLfuse_poll, +#endif /* FUSE_VERSION >= 28 */ +}; + +MODULE = Fuse PACKAGE = Fuse +PROTOTYPES: DISABLE + +BOOT: + MY_CXT_INIT; +#ifdef USE_ITHREADS + MY_CXT.self = aTHX; +#endif + +void +CLONE(...) + PREINIT: +#ifdef USE_ITHREADS + int i; + dTHX; +#endif + CODE: +#ifdef USE_ITHREADS + MY_CXT_CLONE; + tTHX parent = MY_CXT.self; + MY_CXT.self = my_perl; +#if (PERL_VERSION < 10) || (PERL_VERSION == 10 && PERL_SUBVERSION <= 0) + /* CLONE entered without a pointer table, so we can't safely clone static data */ + if(!PL_ptr_table) { + for(i=0;i 13) || (PERL_VERSION == 13 && PERL_SUBVERSION >= 2) + clone_param = Perl_clone_params_new(parent, aTHX); +#else + CLONE_PARAMS raw_param; + raw_param.flags = 0; + raw_param.proto_perl = parent; + raw_param.stashes = (AV*)sv_2mortal((SV*)newAV()); + clone_param = &raw_param; +#endif + for(i=0;i 13) || (PERL_VERSION == 13 && PERL_SUBVERSION >= 2) + Perl_clone_params_del(clone_param); +#endif + } +#endif + +SV* +fuse_get_context() + PREINIT: + struct fuse_context *fc; + CODE: + fc = fuse_get_context(); + if(fc) { + HV *hash = newHV(); + (void) hv_store(hash, "uid", 3, newSViv(fc->uid), 0); + (void) hv_store(hash, "gid", 3, newSViv(fc->gid), 0); + (void) hv_store(hash, "pid", 3, newSViv(fc->pid), 0); + if (fc->private_data) + (void) hv_store(hash, "private", 7, fc->private_data, 0); +#if FUSE_VERSION >= 28 + (void) hv_store(hash, "umask", 5, newSViv(fc->umask), 0); +#endif /* FUSE_VERSION >= 28 */ + RETVAL = newRV_noinc((SV*)hash); + } else { + XSRETURN_UNDEF; + } + OUTPUT: + RETVAL + +SV * +fuse_version() + CODE: + RETVAL = newSVpvf("%d.%d", FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION); + OUTPUT: + RETVAL + +SV * +XATTR_CREATE() + CODE: + RETVAL = newSViv(XATTR_CREATE); + OUTPUT: + RETVAL + +SV * +XATTR_REPLACE() + CODE: + RETVAL = newSViv(XATTR_REPLACE); + OUTPUT: + RETVAL + +void +perl_fuse_main(...) + PREINIT: + struct fuse_operations fops; + int i, debug; + char *mountpoint; + char *mountopts; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse_chan *fc; + dMY_CXT; + INIT: + if(items != N_CALLBACKS + 6) { + fprintf(stderr,"Perl<->C inconsistency or internal error\n"); + XSRETURN_UNDEF; + } + memset(&fops, 0, sizeof(struct fuse_operations)); + CODE: + debug = SvIV(ST(0)); + MY_CXT.threaded = SvIV(ST(1)); + MY_CXT.handles = (HV*)(sv_2mortal((SV*)(newHV()))); + if(MY_CXT.threaded) { +#ifdef FUSE_USE_ITHREADS + master_interp = aTHX; + MUTEX_INIT(&MY_CXT.mutex); + SvSHARE((SV*)(MY_CXT.handles)); +#else + fprintf(stderr,"FUSE warning: Your script has requested multithreaded " + "mode, but your perl was not built with a supported " + "thread model. Threads are disabled.\n"); + MY_CXT.threaded = 0; +#endif + } + mountpoint = SvPV_nolen(ST(2)); + mountopts = SvPV_nolen(ST(3)); +#if FUSE_VERSION >= 28 + fops.flag_nullpath_ok = SvIV(ST(4)); +#endif /* FUSE_VERSION >= 28 */ + MY_CXT.utimens_as_array = SvIV(ST(5)); + for(i=0;i= 28 + +void +pollhandle_destroy(...) + PREINIT: + struct fuse_pollhandle *ph; + INIT: + if (items != 1) { + fprintf(stderr, "No pollhandle passed?\n"); + XSRETURN_UNDEF; + } + CODE: + ph = INT2PTR(struct fuse_pollhandle*, SvIV(ST(0))); + fuse_pollhandle_destroy(ph); + +int +notify_poll(...) + PREINIT: + struct fuse_pollhandle *ph; + INIT: + if (items != 1) { + fprintf(stderr, "No pollhandle passed?\n"); + XSRETURN_UNDEF; + } + CODE: + ph = INT2PTR(struct fuse_pollhandle*, SvIV(ST(0))); + RETVAL = fuse_notify_poll(ph); + OUTPUT: + RETVAL + +#endif