--- perl/trunk/Fuse.xs 2004/11/11 14:44:15 4 +++ perl-llin/Fuse.xs 2006/01/03 17:27:32 71 @@ -2,20 +2,48 @@ #include "perl.h" #include "XSUB.h" -#include +#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(); { +# define FUSE_CONTEXT_POST } +# define FUSE_USE_ITHREADS +# else +# error "Sorry, I don't know how to handle ithreads on this architecture." +# endif +#else +# define FUSE_CONTEXT_PRE +# define FUSE_CONTEXT_POST +#endif +#include #undef DEBUGf #if 0 -#define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,PL_stack_sp-PL_stack_base ,##a ) +#define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,sp-PL_stack_base ,##a ) #else #define DEBUGf(a...) #endif -SV *_PLfuse_callbacks[18]; +#define N_CALLBACKS 25 +SV *_PLfuse_callbacks[N_CALLBACKS]; int _PLfuse_getattr(const char *file, struct stat *result) { - dSP; int rv, statcount; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("getattr begin: %s\n",file); ENTER; SAVETMPS; PUSHMARK(SP); @@ -32,14 +60,11 @@ else rv = -ENOENT; } else { + result->st_blocks = POPi; result->st_blksize = POPi; result->st_ctime = POPi; result->st_mtime = POPi; result->st_atime = POPi; - /* What the HELL? Perl says the blockcount is the last argument. - * Everything else says the blockcount is the last argument. So why - * was it folded into the middle of the list? */ - result->st_blocks = POPi; result->st_size = POPi; result->st_rdev = POPi; result->st_gid = POPi; @@ -53,16 +78,20 @@ FREETMPS; LEAVE; PUTBACK; + DEBUGf("getattr end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_readlink(const char *file,char *buf,size_t buflen) { int rv; char *rvstr; - dSP; I32 ax; + FUSE_CONTEXT_PRE; + dSP; if(buflen < 1) return EINVAL; + DEBUGf("readlink begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -85,12 +114,16 @@ LEAVE; buf[buflen-1] = 0; PUTBACK; + DEBUGf("readlink end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) { int prv, rv; + FUSE_CONTEXT_PRE; dSP; + DEBUGf("getdir begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -109,6 +142,8 @@ FREETMPS; LEAVE; PUTBACK; + DEBUGf("getdir end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -116,7 +151,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; + DEBUGf("mknod begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -133,6 +170,8 @@ FREETMPS; LEAVE; PUTBACK; + DEBUGf("mknod end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -140,8 +179,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("mkdir begin: %i\n",sp-PL_stack_base); + DEBUGf("mkdir begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -157,7 +197,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("mkdir end: %i %i\n",sp-PL_stack_base,rv); + DEBUGf("mkdir end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -166,8 +207,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("unlink begin: %i\n",sp-PL_stack_base); + DEBUGf("unlink begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -182,7 +224,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("unlink end: %i\n",sp-PL_stack_base); + DEBUGf("unlink end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -190,8 +233,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("rmdir begin: %i\n",sp-PL_stack_base); + DEBUGf("rmdir begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -206,7 +250,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("rmdir end: %i %i\n",sp-PL_stack_base,rv); + DEBUGf("rmdir end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -214,8 +259,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("symlink begin: %i\n",sp-PL_stack_base); + DEBUGf("symlink begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -231,7 +277,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("symlink end: %i\n",sp-PL_stack_base); + DEBUGf("symlink end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -239,8 +286,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("rename begin: %i\n",sp-PL_stack_base); + DEBUGf("rename begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -256,7 +304,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("rename end: %i\n",sp-PL_stack_base); + DEBUGf("rename end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -264,8 +313,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("link begin: %i\n",sp-PL_stack_base); + DEBUGf("link begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -281,7 +331,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("link end: %i\n",sp-PL_stack_base); + DEBUGf("link end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -289,8 +340,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("chmod begin: %i\n",sp-PL_stack_base); + DEBUGf("chmod begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -306,7 +358,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("chmod end: %i\n",sp-PL_stack_base); + DEBUGf("chmod end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -314,8 +367,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("chown begin: %i\n",sp-PL_stack_base); + DEBUGf("chown begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -332,7 +386,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("chown end: %i\n",sp-PL_stack_base); + DEBUGf("chown end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -340,8 +395,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("truncate begin: %i\n",sp-PL_stack_base); + DEBUGf("truncate begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -357,7 +413,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("truncate end: %i\n",sp-PL_stack_base); + DEBUGf("truncate end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -365,8 +422,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("utime begin: %i\n",sp-PL_stack_base); + DEBUGf("utime begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -383,7 +441,8 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("utime end: %i\n",sp-PL_stack_base); + DEBUGf("utime end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } @@ -391,8 +450,9 @@ int rv; SV *rvsv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("open begin: %i\n",sp-PL_stack_base); + DEBUGf("open begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -408,15 +468,17 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("open end: %i %i\n",sp-PL_stack_base,rv); + DEBUGf("open end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) { int rv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("read begin: %i\n",sp-PL_stack_base); + DEBUGf("read begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -447,15 +509,17 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("read end: %i %i\n",sp-PL_stack_base,rv); + DEBUGf("read end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) { int rv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("write begin: %i\n",sp-PL_stack_base); + DEBUGf("write begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -472,29 +536,48 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("write end: %i\n",sp-PL_stack_base); + DEBUGf("write end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } -int _PLfuse_statfs (const char *file, struct statfs *st) { +/* FIXME check for old fuse API (< 21?) and use statfs here */ +#ifdef __FreeBSD__ + #define _fuse_statvfs statfs +#else + #define _fuse_statvfs statvfs +#endif +int _PLfuse_statfs (const char *file, struct _fuse_statvfs *st) { + int rv; char *rvstr; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("statfs begin: %i\n",sp-PL_stack_base); + DEBUGf("statfs begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; rv = call_sv(_PLfuse_callbacks[17],G_ARRAY); SPAGAIN; - if(rv > 5) { - st->f_bsize = POPi; - st->f_bfree = POPi; - st->f_blocks = POPi; - st->f_ffree = POPi; - st->f_files = POPi; - st->f_namelen = POPi; - if(rv > 6) + DEBUGf("statfs got %i params\n",rv); + if(rv == 6 || rv == 7) { + st->f_bsize = POPi; + st->f_bfree = POPi; + st->f_blocks = POPi; + st->f_ffree = POPi; + st->f_files = POPi; + st->f_namemax = POPi; +#ifndef __FreeBSD__ + /* zero and fill-in other */ + st->f_fsid = 0; + st->f_frsize = 4096; + st->f_flag = 0; + st->f_bavail = st->f_bfree; + st->f_favail = st->f_ffree; +#endif + + if(rv == 7) rv = POPi; else rv = 0; @@ -509,29 +592,280 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("statfs end: %i\n",sp-PL_stack_base); + DEBUGf("statfs end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_flush (const char *file) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("flush begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[18],G_SCALAR); + SPAGAIN; + if(rv) + rv = POPi; + else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("flush end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_release (const char *file, int flags) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("release begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSViv(flags))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[19],G_SCALAR); + SPAGAIN; + if(rv) + rv = POPi; + else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("release end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_fsync (const char *file, int flags) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("fsync begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSViv(flags))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[20],G_SCALAR); + SPAGAIN; + if(rv) + rv = POPi; + else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("fsync end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("setxattr begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSVpv(name,0))); + XPUSHs(sv_2mortal(newSVpvn(buf,buflen))); + XPUSHs(sv_2mortal(newSViv(flags))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[21],G_SCALAR); + SPAGAIN; + if(rv) + rv = POPi; + else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("setxattr end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("getxattr begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSVpv(name,0))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[22],G_SCALAR); + SPAGAIN; + if(!rv) + rv = -ENOENT; + else { + SV *mysv = POPs; + + rv = 0; + if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV) + rv = SvIV(mysv); + else { + if(SvPOK(mysv)) { + rv = SvCUR(mysv); + } else { + rv = 0; + } + if ((rv > 0) && (buflen > 0)) + { + if(rv > buflen) + rv = -ERANGE; + else + memcpy(buf,SvPV_nolen(mysv),rv); + } + } + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("getxattr end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_listxattr (const char *file, char *list, size_t size) { + int prv, rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("listxattr begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + PUTBACK; + prv = call_sv(_PLfuse_callbacks[23],G_ARRAY); + SPAGAIN; + if(!prv) + rv = -ENOENT; + else { + + char *p = list; + int spc = size; + int total_len = 0; + int i; + + rv = POPi; + prv--; + + /* Always nul terminate */ + if (list && (size > 0)) + list[0] = '\0'; + + while (prv > 0) + { + SV *mysv = POPs; + prv--; + + if (SvPOK(mysv)) { + /* Copy nul too */ + int s = SvCUR(mysv) + 1; + total_len += s; + + if (p && (size > 0) && (spc >= s)) + { + memcpy(p,SvPV_nolen(mysv),s); + p += s; + spc -= s; + } + } + } + + /* + * If the Perl returned an error, return that. + * Otherwise check that the buffer was big enough. + */ + if (rv == 0) + { + rv = total_len; + if ((size > 0) && (size < total_len)) + rv = -ERANGE; + } + } + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("listxattr end: %i\n",rv); + FUSE_CONTEXT_POST; + return rv; +} + +int _PLfuse_removexattr (const char *file, const char *name) { + int rv; + char *rvstr; + FUSE_CONTEXT_PRE; + dSP; + DEBUGf("removexattr begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + XPUSHs(sv_2mortal(newSVpv(name,0))); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[24],G_SCALAR); + SPAGAIN; + if(rv) + rv = POPi; + else + rv = 0; + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("removexattr end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } struct fuse_operations _available_ops = { -getattr: _PLfuse_getattr, - _PLfuse_readlink, - _PLfuse_getdir, - _PLfuse_mknod, - _PLfuse_mkdir, - _PLfuse_unlink, - _PLfuse_rmdir, - _PLfuse_symlink, - _PLfuse_rename, - _PLfuse_link, - _PLfuse_chmod, - _PLfuse_chown, - _PLfuse_truncate, - _PLfuse_utime, - _PLfuse_open, - _PLfuse_read, - _PLfuse_write, - _PLfuse_statfs +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, }; MODULE = Fuse PACKAGE = Fuse @@ -540,33 +874,58 @@ 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}; - int i, fd, varnum = 0, debug, have_mnt; + 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, fd, varnum = 0, debug, threaded, have_mnt; char *mountpoint; + char *mountopts; STRLEN n_a; STRLEN l; INIT: - if(items != 20) { + if(items != 29) { fprintf(stderr,"Perl<->C inconsistency or internal error\n"); XSRETURN_UNDEF; } CODE: debug = SvIV(ST(0)); - mountpoint = SvPV_nolen(ST(1)); - /* FIXME: reevaluate multithreading support when perl6 arrives */ - for(i=0;i<18;i++) { - SV *var = ST(i+2); - if((var != &PL_sv_undef) && SvROK(var)) { - if(SvTYPE(SvRV(var)) == SVt_PVCV) { - void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops; - tmp2[i] = tmp1[i]; - _PLfuse_callbacks[i] = var; - } else - croak("arg is not a code reference!"); + threaded = SvIV(ST(1)); + if(threaded) { +#ifdef FUSE_USE_ITHREADS + master_interp = PERL_GET_INTERP; +#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; +#endif + } + mountpoint = SvPV_nolen(ST(2)); + mountopts = SvPV_nolen(ST(3)); + for(i=0;i