Multiple changes for better *BSD compatibility, including:
authorDerrik Pates <demon@now.ai>
Fri, 24 Jun 2011 13:36:53 +0000 (07:36 -0600)
committerDerrik Pates <demon@now.ai>
Fri, 24 Jun 2011 13:36:53 +0000 (07:36 -0600)
- For OS X/Darwin, use alternate function argument lists that add an
  extra parameter for the setxattr() and getxattr() call wrappers. This
  eliminates some compile-time warnings, and makes sure the call stack
  isn't getting unbalanced when those calls are made.
- For OS X/Darwin, force the use of -lfuse_ino64 on OS X 10.6 (Snow
  Leopard); FUSE filesystems won't work at all otherwise due to changes
  in the inode structure definition, and the pkgconfig files don't check
  for this.
- For OS X/Darwin, don't set the PERL_DL_NONLAZY=1 environment variable
  during "make test"; MacFuse builds their libfuse with a reference to
  _iconv, but doesn't link in -liconv at build time, and due to
  differences in their dynamic linker, linking -liconv into our library
  doesn't get that symbol into its namespace, so tests fail completely
  on OS X due to the unsatisfied link symbol when RTLD_NOW is passed to
  dlopen().
- Enabled alternate mknod handling for NetBSD and OS X/Darwin in
  addition to FreeBSD in the example code.
- Synchronized all changes (except enabling threading) from
  examples/loopback_t.pl to examples/loopback.pl.
- Reenabled threading use for OS X/Darwin in tests; testing on my
  MacBook running OS X 10.6.7 always passes with it enabled (though
  does not with threading disabled, which probably needs some
  diagnosing).
- In the mknod() test, use a different major number shift value (24
  instead of 8) for OS X/Darwin.
- In the statfs() test, use sys/syscall.ph instead of syscall.ph (works
  on Linux and all *BSDs, though NetBSD and OS X/Darwin perls don't h2ph
  the system headers at install time).
- In the statfs() test, altered the Linux pack mask for the statfs()
  syscall, added masks for FreeBSD and OS X/Darwin, and added statvfs1()
  call semantics for NetBSD, so this test will work on all supported
  platforms (though the FreeBSD pack mask may not work on non-64bit
  FreeBSDs, need to test that).
- In the statfs() test, ignore f_namelen field for NetBSD and
  OS X/Darwin. OS X/Darwin doesn't even have such a field, and NetBSD
  seems to not handle it right for PUFFS filesystems.
- In the symlink() test, use 'cp -R' on NetBSD instead of 'cp -a', since
  NetBSD's 'cp' doesn't know the '-a' option.

Fuse.xs
Makefile.PL
examples/loopback.pl
examples/loopback_t.pl
test/helper.pm
test/mknod.t
test/statfs.t
test/symlink.t

diff --git a/Fuse.xs b/Fuse.xs
index f86995d..fb3686f 100755 (executable)
--- a/Fuse.xs
+++ b/Fuse.xs
@@ -733,7 +733,11 @@ int _PLfuse_fsync (const char *file, int datasync, struct fuse_file_info *fi) {
        return rv;
 }
 
+#if __FreeBSD__ >= 10
+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");
@@ -756,7 +760,11 @@ int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_
        return rv;
 }
 
+#if __FreeBSD__ >= 10
+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");
index 1522ff5..f096413 100644 (file)
@@ -1,8 +1,32 @@
 use ExtUtils::MakeMaker;
+use POSIX;
 use Config;
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
 
+# Note: This is a hack. This hack is necessary because MacFUSE's libfuse
+# (and libfuse_ino64, by extension) don't link in libiconv. This wouldn't
+# be a problem, but it appears the Darwin/OS X dynamic linker won't
+# satisfy runtime link dependencies in those libraries from libraries
+# imported by our library, and it uses a symbol from libiconv without
+# actually linking the library to itself. Awesome.
+package MY;
+sub test_via_harness {
+  my($self, $perl, $tests) = @_;
+  local $_ = $self->SUPER::test_via_harness($perl, $tests);
+  s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
+  return $_;
+}
+
+sub test_via_script {
+  my($self, $perl, $tests) = @_;
+  local $_ = $self->SUPER::test_via_script($perl, $tests);
+  s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
+  return $_;
+}
+
+package main;
+
 my $ver = `fusermount -V`;
 my $ver2 = `mount_fusefs -V`;
 chomp(my $ver3 = `mount_fusefs -V 2>&1 | head -n1`);
@@ -30,6 +54,9 @@ if ($ver && $ver + 0 < 2.5) {
 
 my $inc = '-DFUSE_USE_VERSION=26 ' . `pkg-config --cflags fuse` || '-I ../include -D_FILE_OFFSET_BITS=64';
 my $obj = `pkg-config --libs fuse` || (($^O eq 'netbsd') ? '-lrefuse' : '-lfuse');
+if ($^O eq 'darwin' && (uname())[2] =~ /^10\./) {
+       $obj =~ s/-lfuse/-lfuse_ino64/;
+}
 my $def = '-Wall -g -ggdb';
 $def .= ' -D__FreeBSD__=10 -D_FILE_OFFSET_BITS=64' if $^O eq 'darwin';
 $def .= ' -DPERL_HAS_64BITINT' if $Config{'use64bitint'};
index 81ee2e1..2dea378 100755 (executable)
@@ -5,12 +5,11 @@ use blib;
 use Fuse;
 use IO::File;
 use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
-use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET);
+use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET S_ISREG S_ISFIFO S_IMODE);
 my $can_syscall = eval {
        require 'syscall.ph'; # for SYS_mknod and SYS_lchown
 };
 if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
-       local $/ = undef;
        my %sys = do { local $/ = undef;
                        <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
         };
@@ -22,17 +21,7 @@ if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
        }
 }
 
-my $tmp = -d '/private' ? '/private/tmp' : '/tmp';
-my $tmp_path = "$tmp/fusetest-" . $ENV{LOGNAME};
-if (! -e $tmp_path) {
-       mkdir($tmp_path) || die "can't create $tmp_path: $!";
-}
-
-sub fixup { print STDERR "fixup $_[0] from @{[caller]}\n";
-            my ($path) = @_;
-            return $tmp_path if $path eq '/';
-            return $tmp_path . $path;
-}
+sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
 
 sub x_getattr {
        my ($file) = fixup(shift);
@@ -130,7 +119,18 @@ sub x_mknod {
        # and possibly run the real mknod command.
        my ($file, $modes, $dev) = @_;
        $file = fixup($file);
-       $! = 0;
+       undef $!;
+       if ($^O eq 'freebsd' || $^O eq 'darwin' || $^O eq 'netbsd') {
+               if (S_ISREG($modes)) {
+                       open(FILE, '>', $file) || return -$!;
+                       print FILE "";
+                       close(FILE);
+                       return 0;
+               } elsif (S_ISFIFO($modes)) {
+                       my ($rv) = POSIX::mkfifo($file, S_IMODE($modes));
+                       return $rv ? 0 : -POSIX::errno();
+               }
+       }
        syscall(&SYS_mknod,$file,$modes,$dev);
        return -$!;
 }
index db03fb9..863a3f4 100755 (executable)
@@ -122,7 +122,7 @@ sub x_mknod {
        my ($file, $modes, $dev) = @_;
        $file = fixup($file);
        undef $!;
-       if ($^O eq 'freebsd') {
+       if ($^O eq 'freebsd' || $^O eq 'darwin' || $^O eq 'netbsd') {
                if (S_ISREG($modes)) {
                        open(FILE, '>', $file) || return -$!;
                        print FILE "";
index 32e629a..2b8579f 100644 (file)
@@ -9,7 +9,8 @@ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
 @EXPORT_OK = qw($_loop $_point $_pidfile $_real);
 my $tmp = -d '/private' ? '/private/tmp' : '/tmp';
 our($_loop, $_point, $_pidfile, $_real) = ("","$tmp/fusemnt-".$ENV{LOGNAME},"test/s/mounted.pid","$tmp/fusetest-".$ENV{LOGNAME});
-$_loop = $^O ne 'darwin' && $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
+#$_loop = $^O ne 'darwin' && $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
+$_loop = $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
 if($0 !~ qr|s/u?mount\.t$|) {
        my ($reject) = 1;
        if(open my $fh, '<', $_pidfile) {
index ab85465..8ea3b46 100644 (file)
@@ -4,6 +4,9 @@ use Test::More;
 plan tests => 24;
 use English;
 
+my $maj_off = 8;
+if ($^O eq 'darwin') { $maj_off = 24; }
+
 my (@stat);
 
 chdir($_point);
@@ -34,9 +37,9 @@ SKIP: {
        ok(-b "blk" ,"blkdev is blkdev");
 
        @stat = stat("chr");
-       is($stat[6],3+(2<<8),"chrdev has right major,minor");
+       is($stat[6],3+(2<<$maj_off),"chrdev has right major,minor");
        @stat = stat("blk");
-       is($stat[6],3+(2<<8),"blkdev has right major,minor");
+       is($stat[6],3+(2<<$maj_off),"blkdev has right major,minor");
 }
 
 chdir($_point);
@@ -54,9 +57,9 @@ SKIP: {
        ok(-b "blk" ,"blkdev is blkdev");
 
        @stat = stat("chr");
-       is($stat[6],3+(2<<8),"chrdev has right major,minor");
+       is($stat[6],3+(2<<$maj_off),"chrdev has right major,minor");
        @stat = stat("blk");
-       is($stat[6],3+(2<<8),"blkdev has right major,minor");
+       is($stat[6],3+(2<<$maj_off),"blkdev has right major,minor");
 }
 
 map { unlink } qw(reg chr blk fifo);
index 2335546..1adfe9f 100644 (file)
@@ -2,23 +2,59 @@
 use test::helper qw($_real $_point);
 use Test::More;
 eval {
-   require 'syscall.ph'; # for SYS_statfs
+   require 'sys/syscall.ph'; # for SYS_statfs
 } or plan skip_all => 'No syscall.ph';
 
-plan tests => 7;
-my ($statfs_data) = 0x00 x 8 x 16;
+# Maybe not the best way to do this... but it works. Only extract the values
+# we care about, so we don't have to worry about changing field ordering
+# around and other such nastiness.
+my $packmask;
+if ($^O eq 'linux') {
+    $packmask = 'x[L!]L![6]x[L!]L!';
+}
+elsif ($^O eq 'freebsd') {
+       # Only sure about this on 64-bit FreeBSD...
+       $packmask = 'x[16]Qx[8]Q[2]qQqx[112]Lx[4]';
+}
+elsif ($^O eq 'netbsd') {
+       # Only sure about this on 64-bit NetBSD...
+       $packmask = 'x[8]Lx![q]x[16]Q[3]x[8]Q[2]x[64]L';
+}
+elsif ($^O eq 'darwin') {
+    # Accurate for OS X 10.6; 10.5 and earlier may not actually correspond
+       # to this, if my understanding of statfs(2) on OS X is fair.
+    $packmask = 'x[L!]L!x[L!]L![5]';
+} else {
+       plan skip_all => 'Platform not known, need to know how to statfs';
+}
+
+if ($^O eq 'netbsd' || $^O eq 'darwin') {
+    # Ignoring the f_namelen field; no such animal on OS X statfs(), and
+       # NetBSD's statvfs1(2) syscall doesn't seem to handle f_namelen right
+       # for PUFFS-based filesystems. Not our failure, and mostly irrelevant.
+    plan tests => 6;
+}
+else {
+    plan tests => 7;
+}
+# Just make the buffer large enough that we don't have to care...
+my ($statfs_data) = "\0" x 4096;
 my ($tmp) = $_point;
-ok(!syscall(&SYS_statfs,$tmp,$statfs_data),"statfs");
-# FIXME: this is soooooo linux-centric.  perhaps parse the output of /bin/df?
-my @list = unpack("L!7L2L!7",$statfs_data);
+if ($^O eq 'netbsd') {
+    # NetBSD doesn't have statfs(2); statvfs1(2) is its closest analogue.
+       ok(!syscall(&SYS_statvfs1,$tmp,$statfs_data,1),'statvfs1');
+}
+else {
+       ok(!syscall(&SYS_statfs,$tmp,$statfs_data),'statfs');
+}
+my @list = unpack($packmask,$statfs_data);
 diag "statfs: ",join(', ', @list);
+is(shift(@list),4096,'block size');
+is(shift(@list),1000000,'blocks');
+is(shift(@list),500000,'blocks free');
 shift(@list);
-is(shift(@list),4096,"block size");
-is(shift(@list),1000000,"blocks");
-is(shift(@list),500000,"blocks free");
-shift(@list);
-is(shift(@list),1000000,"files");
-is(shift(@list),500000,"files free");
-shift(@list);
-shift(@list);
-is(shift(@list),255,"namelen");
+is(shift(@list),1000000,'files');
+is(shift(@list),500000,'files free');
+unless ($^O eq 'netbsd' || $^O eq 'darwin') {
+    is(shift(@list),255,'namelen');
+}
index 19cc72d..a17860f 100644 (file)
@@ -15,5 +15,7 @@ unlink("def");
 # reports an error
 mkdir("dira");
 system("cd dira; touch filea; ln -s filea fileb");
-is(system("cp -a dira dirb")>>8,0,"cp -a");
+my $cp = 'cp -a';
+if ($^O eq 'netbsd') { $cp = 'cp -R'; }
+is(system($cp . " dira dirb")>>8,0,$cp);
 system("rm -rf dira dirb");