Add support for operations supported by FUSE 2.2.1 (flush, release, fsync, extended...
[perl-fuse.git] / Fuse.xs
diff --git a/Fuse.xs b/Fuse.xs
index adc63b7..9ead042 100644 (file)
--- a/Fuse.xs
+++ b/Fuse.xs
@@ -11,7 +11,8 @@
 #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;
@@ -510,25 +511,261 @@ int _PLfuse_statfs (const char *file, struct statfs *st) {
        return rv;
 }
 
+int _PLfuse_flush (const char *file) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("flush begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_release (const char *file, int flags) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("release begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_fsync (const char *file, int flags) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("fsync begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("setxattr begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("getxattr begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_listxattr (const char *file, char *list, size_t size) {
+       int prv, rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("listxattr begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       return rv;
+}
+
+int _PLfuse_removexattr (const char *file, const char *name) {
+       int rv;
+       char *rvstr;
+       dSP;
+       DEBUGf("removexattr begin: %i\n",sp-PL_stack_base);
+       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",sp-PL_stack_base);
+       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
@@ -537,13 +774,13 @@ PROTOTYPES: DISABLE
 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};
+       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, have_mnt;
        char *mountpoint;
        STRLEN n_a;
        STRLEN l;
        INIT:
-       if(items != 20) {
+       if(items != 27) {
                fprintf(stderr,"Perl<->C inconsistency or internal error\n");
                XSRETURN_UNDEF;
        }
@@ -551,7 +788,7 @@ perl_fuse_main(...)
        debug = SvIV(ST(0));
        mountpoint = SvPV_nolen(ST(1));
        /* FIXME: reevaluate multithreading support when perl6 arrives */
-       for(i=0;i<18;i++) {
+       for(i=0;i<N_CALLBACKS;i++) {
                SV *var = ST(i+2);
                if((var != &PL_sv_undef) && SvROK(var)) {
                        if(SvTYPE(SvRV(var)) == SVt_PVCV) {