--- perl/trunk/Fuse.xs 2004/11/18 12:09:10 7 +++ perl-llin/Fuse.xs 2006/05/29 08:57:50 92 @@ -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) { + int rv; + FUSE_CONTEXT_PRE; dSP; - int rv, statcount; + DEBUGf("getattr begin: %s\n",file); ENTER; SAVETMPS; PUSHMARK(SP); @@ -32,37 +60,36 @@ 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; result->st_uid = POPi; result->st_nlink = POPi; result->st_mode = POPi; - /*result->st_ino =*/ POPi; + result->st_ino = POPi; result->st_dev = POPi; rv = 0; } 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; + FUSE_CONTEXT_PRE; dSP; - I32 ax; if(buflen < 1) return EINVAL; + DEBUGf("readlink begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -85,12 +112,23 @@ LEAVE; buf[buflen-1] = 0; PUTBACK; + DEBUGf("readlink end: %i\n",rv); + FUSE_CONTEXT_POST; 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; + FUSE_CONTEXT_PRE; dSP; + DEBUGf("getdir begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -109,14 +147,16 @@ FREETMPS; LEAVE; PUTBACK; + DEBUGf("getdir end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) { int rv; - SV *rvsv; - char *rvstr; + FUSE_CONTEXT_PRE; dSP; + DEBUGf("mknod begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -133,15 +173,16 @@ FREETMPS; LEAVE; PUTBACK; + DEBUGf("mknod end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_mkdir (const char *file, mode_t mode) { 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,17 +198,17 @@ 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; } int _PLfuse_unlink (const char *file) { 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,16 +223,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("unlink end: %i\n",sp-PL_stack_base); + DEBUGf("unlink end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_rmdir (const char *file) { 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,16 +247,16 @@ 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; } int _PLfuse_symlink (const char *file, const char *new) { 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,16 +272,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("symlink end: %i\n",sp-PL_stack_base); + DEBUGf("symlink end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_rename (const char *file, const char *new) { 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,16 +297,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("rename end: %i\n",sp-PL_stack_base); + DEBUGf("rename end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_link (const char *file, const char *new) { 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,16 +322,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("link end: %i\n",sp-PL_stack_base); + DEBUGf("link end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_chmod (const char *file, mode_t mode) { 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,16 +347,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("chmod end: %i\n",sp-PL_stack_base); + DEBUGf("chmod end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) { 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,16 +373,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("chown end: %i\n",sp-PL_stack_base); + DEBUGf("chown end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_truncate (const char *file, off_t off) { 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,16 +398,16 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("truncate end: %i\n",sp-PL_stack_base); + DEBUGf("truncate end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } int _PLfuse_utime (const char *file, struct utimbuf *uti) { 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,16 +424,17 @@ FREETMPS; LEAVE; PUTBACK; - DEBUGf("utime end: %i\n",sp-PL_stack_base); + DEBUGf("utime end: %i\n",rv); + FUSE_CONTEXT_POST; return rv; } -int _PLfuse_open (const char *file, int flags) { +int _PLfuse_open (const char *file, struct fuse_file_info *fi) { int rv; - SV *rvsv; - char *rvstr; + int flags = fi->flags; + FUSE_CONTEXT_PRE; dSP; - DEBUGf("open begin: %i\n",sp-PL_stack_base); + DEBUGf("open begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); @@ -408,15 +450,16 @@ 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 _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) { 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 +490,16 @@ 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 _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) { 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 +516,38 @@ 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) { +int _PLfuse_statfs (const char *file, struct 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; + /* 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; + + if(rv == 7) rv = POPi; else rv = 0; @@ -509,29 +562,277 @@ 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, struct fuse_file_info *fi) { + int rv; + 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, struct fuse_file_info *fi) { + int rv; + int flags = fi->flags; + 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 datasync, struct fuse_file_info *fi) { + int rv; + int flags = fi->flags; + 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; + 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; + 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; + 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; + + 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; + 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, +#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 @@ -540,33 +841,82 @@ 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, debug, threaded; char *mountpoint; - STRLEN n_a; - STRLEN l; + char *mountopts; + struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); + struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL); 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