Merge branch 'master' of github.com:dpavlin/perl-fuse
authorDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 4 Jul 2011 08:05:55 +0000 (10:05 +0200)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 4 Jul 2011 08:05:55 +0000 (10:05 +0200)
MANIFEST
Makefile.PL
README
examples/loopback-statvfs.pl [deleted file]
examples/loopback.pl
examples/loopback_t.pl [deleted file]
test/helper.pm
test/s/mount.t
test/statfs.t

index 923ad41..2a3991f 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -33,7 +33,5 @@ test/pod.t
 examples/example.pl
 examples/example_t.pl
 examples/loopback.pl
-examples/loopback_t.pl
 examples/rmount_remote.pl
 examples/rmount.pl
-examples/loopback-statvfs.pl
index f096413..e40f912 100644 (file)
@@ -12,80 +12,76 @@ use Config;
 # 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 $_;
+    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 $_;
+    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`);
-$ver =~ s/^.*?version:\s+//;
-$ver2 =~ s/^.*?version:\s+//;
-$ver3 =~ s/^.*?version\s+//;
-if (! $ver && ! $ver2 && ! $ver3) {
-       # make CPANPLUS happy and don't report errors if fuse isn't installed
-       die("No support for os: $^O\n",
-               "You need to have fuse-dev (or similar) package installed and have sufficient permissions in order to install this module\n",
-               $^O eq 'darwin' ? ("One option on Mac is http://code.google.com/p/macfuse/\n") : (),
-       );
+chomp(my $fusever = `pkg-config --modversion fuse 2> /dev/null`);
+# Required for refuse on NetBSD
+unless ($fusever) {
+    chomp($fusever = `fusermount -V`);
+    $fusever =~ s/^.*?version:\s+//;
 }
-if ($ver && $ver + 0 < 2.5) {
-       die "Fuse perl bindings need Linux fuse version 2.5 or newer\n";
-} elsif ($ver2 && $ver2 + 0 < 0.3) {
-       die "Fuse perl bindings need FreeBSD fuse version 0.3 or newer\n";
-} elsif ($^O eq 'darwin' && $ver3 && !(($ver3 ge "0.1.0b006") || ($ver3 eq "0.1.0"))) {
-       # the "ge" string-compare check will match all later revs and all later
-       # betas, but not the final release of the current rev (0.1.0).
-       die "Fuse perl bindings need MacFUSE version 0.1.0b006 or newer, your version is \"$ver3\"\n";
+
+unless ($fusever) {
+    # make CPANPLUS happy and don't report errors if fuse isn't installed
+    die("No support for os: $^O\n",
+        "You need to have fuse-dev (or similar) package installed and have sufficient permissions in order to install this module\n",
+        $^O eq 'darwin' ? ("One option on Mac is http://code.google.com/p/macfuse/\n") : (),
+    );
+}
+if ($fusever && $fusever + 0 < 2.6) {
+    die "FUSE API is ", $fusever, ", must be 2.6 or later\n";
 } else {
-       warn "fuse version found: ", $ver || $ver2 || $ver3, "\n";
+    warn "fuse version found: ", $fusever, "\n";
 }
 
-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');
+chomp(my $inc = `pkg-config --cflags-only-I fuse 2> /dev/null` || '-I ../include');
+chomp(my $libs = `pkg-config --libs-only-L fuse 2> /dev/null`);
+chomp($libs .= `pkg-config --libs-only-l fuse 2> /dev/null` || (($^O eq 'netbsd') ? '-lrefuse' : '-lfuse'));
 if ($^O eq 'darwin' && (uname())[2] =~ /^10\./) {
-       $obj =~ s/-lfuse/-lfuse_ino64/;
+    $libs =~ s/-lfuse/-lfuse_ino64/;
 }
-my $def = '-Wall -g -ggdb';
-$def .= ' -D__FreeBSD__=10 -D_FILE_OFFSET_BITS=64' if $^O eq 'darwin';
+chomp(my $def = '-Wall -g -ggdb -DFUSE_USE_VERSION=26 ' . `pkg-config --cflags-only-other fuse 2> /dev/null` || '-D_FILE_OFFSET_BITS=64');
+chomp($def .= `pkg-config --libs-only-other fuse 2> /dev/null`);
 $def .= ' -DPERL_HAS_64BITINT' if $Config{'use64bitint'};
 
 WriteMakefile(
-       'NAME'                  => 'Fuse',
-       'VERSION_FROM'  => 'Fuse.pm', # finds $VERSION
-       'PREREQ_PM'             => {}, # e.g., Module::Name => 1.1
-       ($] >= 5.005 ?  ## Add these new keywords supported since 5.005
-               (ABSTRACT_FROM  => 'Fuse.pm', # retrieve abstract from module
-               AUTHOR                  => 'Mark Glines <mark@glines.org>') : ()),
-               ($ExtUtils::MakeMaker::VERSION < 6.46 ? () : (
-                       META_MERGE => {
-                               resources => {
-                               bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Fuse',
-                               repository => 'http://github.com/dpavlin/perl-fuse'
-                       }
-               })
-       ),
-       'LIBS'                  => [''], # e.g., '-lm'
-       'DEFINE'                => $def, # e.g., '-DHAVE_SOMETHING'
+    'NAME'          => 'Fuse',
+    'VERSION_FROM'  => 'Fuse.pm', # finds $VERSION
+    'PREREQ_PM'     => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?  ## Add these new keywords supported since 5.005
+       (ABSTRACT_FROM   => 'Fuse.pm', # retrieve abstract from module
+        AUTHOR          => 'Mark Glines <mark@glines.org>') : ()),
+    ($ExtUtils::MakeMaker::VERSION < 6.46 ? () : (
+        META_MERGE => {
+            resources => {
+                bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Fuse',
+                repository => 'http://github.com/dpavlin/perl-fuse'
+            },
+        })
+    ),
+       'LIBS'          => '-lpthread ' . $libs, # e.g., '-lm'
+       'DEFINE'        => $def, # e.g., '-DHAVE_SOMETHING'
        # Insert -I. if you add *.h files later:
-       'INC'                   => $inc, # e.g., '-I/usr/include/other'
+       'INC'           => $inc, # e.g., '-I/usr/include/other'
        # Un-comment this if you add C files to link with later:
-       'OBJECT'                => "$obj Fuse.o -lpthread", # link all the C files too
+       'OBJECT'        => 'Fuse$(OBJ_EXT)', # link all the C files too
 );
 
 sub MY::postamble {
-       return <<'MAKE_MORE';
+    return <<'MAKE_MORE';
 
 cpan:
        make clean
@@ -104,3 +100,5 @@ sf:
 
 MAKE_MORE
 };
+
+# vim: ts=4 ai et hls
diff --git a/README b/README
index 1a66bce..4a60518 100644 (file)
--- a/README
+++ b/README
@@ -12,8 +12,6 @@ database as file system, but there will be more.
 This is a pre-production release.  It seems to work quite well.  In fact, I
 can't find any problems with it whatsoever.  If you do, I want to know.
 
-Support for FreeBSD is experimental, so expect tests to fail.
-
 INSTALLATION
 
 To install this module type the standard commands as root:
@@ -100,3 +98,6 @@ which correct the issues that cause the test failures. However, there is
 still a bug in librefuse that causes readdir() to only be called once.
 We will be addressing this with the appropriate developers in the near
 future.
+
+Also note that on NetBSD and FreeBSD, extended attributes do not work. These
+are specifics related to the FUSE implementations on those platforms.
diff --git a/examples/loopback-statvfs.pl b/examples/loopback-statvfs.pl
deleted file mode 100755 (executable)
index 66f1abf..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-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);
-require 'syscall.ph'; # for SYS_mknod and SYS_lchown
-use Filesys::Statvfs;
-
-my $tmp_path = "/tmp/fusetest-" . $ENV{LOGNAME};
-if (! -e $tmp_path) {
-       mkdir($tmp_path) || die "can't create $tmp_path: $!";
-}
-
-sub fixup { return $tmp_path . shift }
-
-sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
-}
-
-sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
-}
-
-sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
-}
-
-sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
-}
-
-sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
-}
-
-sub err { return (-shift || -$!) }
-
-sub x_readlink { return readlink(fixup(shift)                 ); }
-sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!;          }
-sub x_rmdir { return err(rmdir(fixup(shift))               ); }
-
-sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
-
-sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
-}
-sub x_link {
-       my ($from) = shift;
-       my ($to) = shift;
-       print "link $from -> $to\n";
-       my ($err) = link(fixup($from),fixup($to)) ? 0 : -$!;
-       return $err;
-}
-sub x_chown {
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
-}
-sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
-}
-sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
-sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
-
-sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
-sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
-
-sub x_mknod {
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       $! = 0;
-       syscall(&SYS_mknod,$file,$modes,$dev);
-       return -$!;
-}
-
-# kludge
-sub x_statfs {
-       my $name = fixup(shift);
-       my($bsize, $frsize, $blocks, $bfree, $bavail,
-               $files, $ffree, $favail, $fsid, $basetype, $flag,
-               $namemax, $fstr) = statvfs("/tmp") || return -$!;
-       return ($namemax, $files, $ffree, $blocks, $bavail, $bsize);
-}
-       
-my ($mountpoint) = "";
-$mountpoint = shift(@ARGV) if @ARGV;
-Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>0,
-       debug => 1,
-);
index 2dea378..1df7535 100755 (executable)
 #!/usr/bin/perl -w
 use strict;
 
+use Carp ();
+local $SIG{'__WARN__'} = \&Carp::cluck;
+
+my $has_threads = 0;
+eval {
+    require threads;
+    require threads::shared;
+    1;
+} and do {
+    $has_threads = 1;
+    threads->import();
+    threads::shared->import();
+};
+
+my $has_Filesys__Statvfs = 0;
+eval {
+    require Filesys::Statvfs;
+    1;
+} and do {
+    $has_Filesys__Statvfs = 1;
+    Filesys::Statvfs->import();
+};
+
 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 S_ISREG S_ISFIFO S_IMODE);
+use Getopt::Long;
+
+my %extraopts = ( 'threaded' => 0, 'debug' => 0 );
+my($use_real_statfs, $pidfile);
+GetOptions(
+    'use-threads'       => sub {
+        if ($has_threads) {
+            $extraopts{'threaded'} = 1;
+        }
+    },
+    'debug'             => sub {
+        $extraopts{'debug'} = 1;
+    },
+    'use-real-statfs'   => \$use_real_statfs,
+    'pidfile=s'         => \$pidfile,
+) || die('Error parsing options');
+
 my $can_syscall = eval {
-       require 'syscall.ph'; # for SYS_mknod and SYS_lchown
+    require 'sys/syscall.ph'; # for SYS_mknod and SYS_lchown
 };
 if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
-       my %sys = do { local $/ = undef;
-                       <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
+    my %sys = do { local $/ = undef;
+            <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
         };
-       close $fh;
-       if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
-               *SYS_mknod  = sub { $sys{SYS_mknod}  };
-               *SYS_lchown = sub { $sys{SYS_lchown} };
-               $can_syscall = 1;
-       }
+    close $fh;
+    if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
+        *SYS_mknod  = sub { $sys{SYS_mknod}  };
+        *SYS_lchown = sub { $sys{SYS_lchown} };
+        $can_syscall = 1;
+    }
 }
 
 sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
 
 sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
+    my ($file) = fixup(shift);
+    my (@list) = lstat($file);
+    return -$! unless @list;
+    return @list;
 }
 
 sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
+    my ($dirname) = fixup(shift);
+    unless(opendir(DIRHANDLE,$dirname)) {
+        return -ENOENT();
+    }
+    my (@files) = readdir(DIRHANDLE);
+    closedir(DIRHANDLE);
+    return (@files, 0);
 }
 
 sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
+    my ($file) = fixup(shift);
+    my ($mode) = shift;
+    return -$! unless sysopen(FILE,$file,$mode);
+    close(FILE);
+    return 0;
 }
 
 sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
+    my ($file,$bufsize,$off) = @_;
+    my ($rv) = -ENOSYS();
+    my ($handle) = new IO::File;
+    return -ENOENT() unless -e ($file = fixup($file));
+    my ($fsize) = -s $file;
+    return -ENOSYS() unless open($handle,$file);
+    if(seek($handle,$off,SEEK_SET)) {
+        read($handle,$rv,$bufsize);
+    }
+    return $rv;
 }
 
 sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
+    my ($file,$buf,$off) = @_;
+    my ($rv);
+    return -ENOENT() unless -e ($file = fixup($file));
+    my ($fsize) = -s $file;
+    return -ENOSYS() unless open(FILE,'+<',$file);
+    if($rv = seek(FILE,$off,SEEK_SET)) {
+        $rv = print(FILE $buf);
+    }
+    $rv = -ENOSYS() unless $rv;
+    close(FILE);
+    return length($buf);
 }
 
 sub err { return (-shift || -$!) }
@@ -83,29 +123,29 @@ sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
 sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
 
 sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
+    my ($old) = fixup(shift);
+    my ($new) = fixup(shift);
+    my ($err) = rename($old,$new) ? 0 : -ENOENT();
+    return $err;
 }
 sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
 sub x_chown {
-       return -ENOSYS() if ! $can_syscall;
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
+    return -ENOSYS() if ! $can_syscall;
+    my ($fn) = fixup(shift);
+    print "nonexistent $fn\n" unless -e $fn;
+    my ($uid,$gid) = @_;
+    # perl's chown() does not chown symlinks, it chowns the symlink's
+    # target.  it fails when the link's target doesn't exist, because
+    # the stat64() syscall fails.
+    # this causes error messages when unpacking symlinks in tarballs.
+    my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
+    return $err;
 }
 sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
+    my ($fn) = fixup(shift);
+    my ($mode) = shift;
+    my ($err) = chmod($mode,$fn) ? 0 : -$!;
+    return $err;
 }
 sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
 sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
@@ -114,51 +154,77 @@ sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); ret
 sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
 
 sub x_mknod {
-       return -ENOSYS() if ! $can_syscall;
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       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 -$!;
+    return -ENOSYS() if ! $can_syscall;
+    # since this is called for ALL files, not just devices, I'll do some checks
+    # and possibly run the real mknod command.
+    my ($file, $modes, $dev) = @_;
+    $file = fixup($file);
+    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 -$!;
 }
 
 # kludge
-sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
-my ($mountpoint) = "";
+sub x_statfs {
+    if ($has_Filesys__Statvfs && $use_real_statfs) {
+        (my($bsize, $frsize, $blocks, $bfree, $bavail,
+            $files, $ffree, $favail, $flag,
+            $namemax) = statvfs('/tmp')) || return -$!;
+        return ($namemax, $files, $ffree, $blocks, $bavail, $bsize);
+    }
+    return 255,1000000,500000,1000000,500000,4096;
+}
+my ($mountpoint) = '';
 $mountpoint = shift(@ARGV) if @ARGV;
+
+if (! -d $mountpoint) {
+    print STDERR "ERROR: attempted to mount to non-directory\n";
+    return -&ENOTDIR
+}
+my $pid = fork();
+die("fork() failed: $!") unless defined $pid;
+
+if ($pid > 0) {
+    # parent process
+    exit(0);
+}
+if ($pidfile) {
+    open(PIDFILE, '>', $pidfile);
+    print PIDFILE $$, "\n";
+    close(PIDFILE);
+}
 Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>0,
-       debug => 1,
+    'mountpoint'    => $mountpoint,
+    'getattr'       => 'main::x_getattr',
+    'readlink'      => 'main::x_readlink',
+    'getdir'        => 'main::x_getdir',
+    'mknod'         => 'main::x_mknod',
+    'mkdir'         => 'main::x_mkdir',
+    'unlink'        => 'main::x_unlink',
+    'rmdir'         => 'main::x_rmdir',
+    'symlink'       => 'main::x_symlink',
+    'rename'        => 'main::x_rename',
+    'link'          => 'main::x_link',
+    'chmod'         => 'main::x_chmod',
+    'chown'         => 'main::x_chown',
+    'truncate'      => 'main::x_truncate',
+    'utime'         => 'main::x_utime',
+    'open'          => 'main::x_open',
+    'read'          => 'main::x_read',
+    'write'         => 'main::x_write',
+    'statfs'        => 'main::x_statfs',
+    %extraopts,
 );
+
+# vim: ts=4 ai et hls
diff --git a/examples/loopback_t.pl b/examples/loopback_t.pl
deleted file mode 100755 (executable)
index 863a3f4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/perl -w
-use strict;
-use threads;
-use threads::shared;
-
-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 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') {
-       my %sys = do { local $/ = undef;
-                       <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
-        };
-       close $fh;
-       if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
-               *SYS_mknod  = sub { $sys{SYS_mknod}  };
-               *SYS_lchown = sub { $sys{SYS_lchown} };
-               $can_syscall = 1;
-       }
-}
-
-sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
-
-sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
-}
-
-sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
-}
-
-sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
-}
-
-sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
-}
-
-sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
-}
-
-sub err { return (-shift || -$!) }
-
-sub x_readlink { return readlink(fixup(shift));         }
-sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
-
-sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
-
-sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
-}
-sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
-sub x_chown {
-       return -ENOSYS() if ! $can_syscall;
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
-}
-sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
-}
-sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
-sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
-
-sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
-sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
-
-sub x_mknod {
-       return -ENOSYS() if ! $can_syscall;
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       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 -$!;
-}
-
-# kludge
-sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
-my ($mountpoint) = "";
-$mountpoint = shift(@ARGV) if @ARGV;
-Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>1,
-);
index 2b8579f..a259448 100644 (file)
@@ -6,11 +6,11 @@ use Config;
 use POSIX qw(WEXITSTATUS);
 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
 @ISA = "Exporter";
-@EXPORT_OK = qw($_loop $_point $_pidfile $_real);
+@EXPORT_OK = qw($_loop $_opts $_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 = $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
+our($_loop, $_point, $_pidfile, $_real, $_opts) = ('examples/loopback.pl',"$tmp/fusemnt-".$ENV{LOGNAME},"test/s/mounted.pid","$tmp/fusetest-".$ENV{LOGNAME}, '');
+$_opts = '--pidfile ' . $_pidfile;
+$_opts .= $Config{useithreads} ? ' --use-threads' : '';
 if($0 !~ qr|s/u?mount\.t$|) {
        my ($reject) = 1;
        if(open my $fh, '<', $_pidfile) {
index 2381734..46ca258 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/perl -w
-use test::helper qw($_point $_loop $_real $_pidfile);
+use test::helper qw($_point $_loop $_opts $_real $_pidfile);
 use strict;
+use Errno qw(:POSIX);
 use Test::More tests => 3;
 
 sub is_mounted {
@@ -11,19 +12,16 @@ sub is_mounted {
 ok(!is_mounted(),"already mounted");
 ok(-f $_loop,"loopback exists");
 
-if(!fork()) {
-       #close(STDIN);
-       close(STDOUT);
-       close(STDERR);
-       mkdir $_point;
-       mkdir $_real;
-       `echo $$ >test/s/mounted.pid`;
-       diag "mounting $_loop to $_point";
-       open STDOUT, '>', '/tmp/fusemnt.log';
-       open STDERR, '>&', \*STDOUT;
-       exec("perl -Iblib/lib -Iblib/arch $_loop $_point");
-       exit(1);
-}
+mkdir $_point;
+mkdir $_real;
+diag "mounting $_loop to $_point";
+open REALSTDOUT, '>&STDOUT';
+open REALSTDERR, '>&STDERR';
+open STDOUT, '>', '/tmp/fusemnt.log';
+open STDERR, '>&', \*STDOUT;
+system("perl -Iblib/lib -Iblib/arch $_loop $_opts $_point");
+open STDOUT, '>&', \*REALSTDOUT;
+open STDERR, '>&', \*REALSTDERR;
 
 my ($success, $count) = (0,0);
 while ($count++ < 50 && !$success) {
index 67c9474..1a5b973 100644 (file)
@@ -2,49 +2,73 @@
 use test::helper qw($_real $_point);
 use Test::More;
 use Config;
+
+my $has_Filesys__Statvfs = 0;
+eval {
+    require Filesys::Statvfs;
+    1;
+} and do {
+    $has_Filesys__Statvfs = 1;
+    Filesys::Statvfs->import();
+};
+
+my $has_syscall = 0;
 eval {
    require 'sys/syscall.ph'; # for SYS_statfs
-} or plan skip_all => 'No syscall.ph';
+   1;
+} and do {
+    $has_syscall = 1;
+};
+
+if (!($has_syscall || $has_Filesys__Statvfs)) {
+    plan skip_all => 'No Filesys::Statvfs and no sys/syscall.ph';
+}
 
 # 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]x[L]L';
-}
-elsif ($^O eq 'freebsd') {
-    $packmask = 'x[16]Qx[8]Q[2]qQqx[112]Lx[4]';
-}
-elsif ($^O eq 'netbsd') {
-    if ($Config{'use64bitint'}) {
-        # This should work for any 64-bit NetBSD...
-        $packmask = 'x[8]Lx![q]x[16]Q[3]x[8]Q[2]x[64]L';
+# Don't even bother setting up a packmask if we have Filesys::Statvfs.
+# In that case, we can just make one call, and save ourselves a ton of
+# messing around.
+if (!$has_Filesys__Statvfs) {
+    if ($^O eq 'linux') {
+        $packmask = 'x[L!]L![6]x[L]x[L]L';
     }
-    else {
-        # NetBSD's perl on 32-bit doesn't handle quadword types, and
-        # this is my workaround. Ugly, but it does the job. And yes,
-        # won't work for big values. Good thing we're not testing
-        # with any, huh?
-        if ($Config{'byteorder'} eq '1234') { # little endian
-            $packmask = 'x[4]Lx[8]Lx[4]Lx[4]Lx[4]x[8]Lx[4]Lx[4]x[64]L';
-        }
-        elsif ($Config{'byteorder'} eq '4321') { # big endian
-            $packmask = 'x[4]Lx[8]x[4]Lx[4]Lx[4]Lx[8]x[4]Lx[4]Lx[64]L';
+    elsif ($^O eq 'freebsd') {
+        $packmask = 'x[16]Qx[8]Q[2]qQqx[112]Lx[4]';
+    }
+    elsif ($^O eq 'netbsd') {
+        if ($Config{'use64bitint'}) {
+            # This should work for any 64-bit NetBSD...
+            $packmask = 'x[8]Lx![q]x[16]Q[3]x[8]Q[2]x[64]L';
         }
         else {
-            plan skip_all => "Word ordering not known, don't know how to handle statvfs1()";
-            exit(1);
+            # NetBSD's perl on 32-bit doesn't handle quadword types, and
+            # this is my workaround. Ugly, but it does the job. And yes,
+            # won't work for big values. Good thing we're not testing
+            # with any, huh?
+            if ($Config{'byteorder'} eq '1234') { # little endian
+                $packmask = 'x[4]Lx[8]Lx[4]Lx[4]Lx[4]x[8]Lx[4]Lx[4]x[64]L';
+            }
+            elsif ($Config{'byteorder'} eq '4321') { # big endian
+                $packmask = 'x[4]Lx[8]x[4]Lx[4]Lx[4]Lx[8]x[4]Lx[4]Lx[64]L';
+            }
+            else {
+                plan skip_all => "Word ordering not known, don't know how to handle statvfs1()";
+                exit(1);
+            }
         }
     }
-}
-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';
-    exit(1);
+    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';
+        exit(1);
+    }
 }
 
 if ($^O eq 'netbsd' || $^O eq 'darwin') {
@@ -56,17 +80,24 @@ if ($^O eq 'netbsd' || $^O eq 'darwin') {
 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;
-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');
+my @list;
+if ($has_Filesys__Statvfs) {
+    # This is a neater way to do this - if it's available...
+    ok(@list = (statvfs($_point))[1,2,3,4,5,6,9]);
 }
-else {
-       ok(!syscall(&SYS_statfs,$tmp,$statfs_data),'statfs');
+elsif ($has_syscall) {
+    # Just make the buffer large enough that we don't have to care...
+    my ($statfs_data) = "\0" x 4096;
+    my ($tmp) = $_point;
+    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');
+    }
+    @list = unpack($packmask,$statfs_data);
 }
-my @list = unpack($packmask,$statfs_data);
 diag "statfs: ",join(', ', @list);
 is(shift(@list),4096,'block size');
 is(shift(@list),1000000,'blocks');