Cast the 'cmd' argument as unsigned.
[perl-fuse.git] / Fuse.xs
diff --git a/Fuse.xs b/Fuse.xs
index fb73a12..893f1a0 100755 (executable)
--- a/Fuse.xs
+++ b/Fuse.xs
@@ -5,7 +5,7 @@
 
 #include <fuse.h>
 
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if (defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__NetBSD__)
 # define XATTR_CREATE 1
 # define XATTR_REPLACE 2
 #else
@@ -1423,16 +1423,19 @@ int _PLfuse_bmap(const char *file, size_t blocksize, uint64_t *idx) {
 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)));
-       XPUSHs(sv_2mortal(newSViv(cmd)));
-    XPUSHs(sv_2mortal(newSViv((uintptr_t)arg)));
+       /* 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(newSViv((unsigned int)cmd)));
        XPUSHs(sv_2mortal(newSViv(flags)));
-       if (_IOC_DIR(cmd) & _IOC_READ)
+       if (_IOC_DIR(cmd) & _IOC_WRITE)
                XPUSHs(sv_2mortal(newSVpvn(data, _IOC_SIZE(cmd))));
        else
                XPUSHs(&PL_sv_undef);
@@ -1440,12 +1443,18 @@ int _PLfuse_ioctl(const char *file, int cmd, void *arg,
        PUTBACK;
        rv = call_sv(MY_CXT.callback[39],G_ARRAY);
        SPAGAIN;
-       if (_IOC_DIR(cmd) & _IOC_WRITE) {
-               if (rv == 2) {
-                       SV *sv = POPs;
+       if ((_IOC_DIR(cmd) & _IOC_READ) && (rv == 2)) {
+               sv = POPs;
+               rv--;
+       }
+
+       if (rv > 0)
+               rv = POPi;
+
+       if ((_IOC_DIR(cmd) & _IOC_READ) && !rv) {
+               if (sv) {
                        size_t len;
                        char *rdata = SvPV(sv, len);
-            rv--;
 
                        if (len > _IOC_SIZE(cmd)) {
                                fprintf(stderr, "ioctl(): returned data was too large for data area\n");
@@ -1457,12 +1466,10 @@ int _PLfuse_ioctl(const char *file, int cmd, void *arg,
                        }
                }
                else {
-                       fprintf(stderr, "ioctl(): ioctl was a write op, but no data was returned from call?\n");
+                       fprintf(stderr, "ioctl(): ioctl was a read op, but no data was returned from call?\n");
                        rv = -EFAULT;
                }
        }
-       if (rv > 0)
-               rv = POPi;
        FREETMPS;
        LEAVE;
        PUTBACK;
@@ -1613,7 +1620,6 @@ fuse_version()
        OUTPUT:
        RETVAL
 
-#ifndef __FreeBSD__
 SV *
 XATTR_CREATE()
        CODE:
@@ -1628,8 +1634,6 @@ XATTR_REPLACE()
        OUTPUT:
        RETVAL
 
-#endif
-
 void
 perl_fuse_main(...)
        PREINIT: