X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=examples%2Floopback.pl;h=88d81b9f7f1a197cd0c326e0e28a9f0ebcdf542c;hb=c872ed31deaaa06128547ff845ea2dd669e953fa;hp=bdc8c2218f1d7bb8c23f5c91bc68c575c3992c43;hpb=06dd8ebb4bc96acd173c00b24251546d74762990;p=perl-fuse.git diff --git a/examples/loopback.pl b/examples/loopback.pl old mode 100644 new mode 100755 index bdc8c22..88d81b9 --- a/examples/loopback.pl +++ b/examples/loopback.pl @@ -1,97 +1,134 @@ -#!/usr/bin/perl - +#!/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); -require 'syscall.ph'; # for SYS_mknod and SYS_lchown +use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET S_ISREG S_ISFIFO S_IMODE S_ISCHR S_ISBLK S_ISSOCK); +use Getopt::Long; +use Lchown; +use Unix::Mknod qw(:all); + +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'); -sub fixup { return "/tmp/fusetest" . shift } +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 || -$!) } -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_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; + 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 { - 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; + my ($fn) = fixup(shift); + local $!; + print "nonexistent $fn\n" unless -e $fn; + my ($uid,$gid) = @_; + lchown($uid, $gid, $fn); + return -$!; } 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:-$!; } @@ -100,37 +137,84 @@ 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 { - # 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 -$!; + # 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 (S_ISREG($modes)) { + open(FILE, '>', $file) || return -$!; + print FILE ''; + close(FILE); + chmod S_IMODE($modes), $file; + return 0; + } + elsif (S_ISFIFO($modes)) { + my ($rv) = POSIX::mkfifo($file, S_IMODE($modes)); + return $rv ? 0 : -POSIX::errno(); + } + elsif (S_ISCHR($modes) || S_ISBLK($modes)) { + mknod($file, $modes, $dev); + return -$!; + } + # S_ISSOCK maybe should be handled; however, for our test it should + # not really matter. + else { + return -&ENOSYS; + } + 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=>\&x_getattr, - readlink=>\&x_readlink, - getdir=>\&x_getdir, - mknod=>\&x_mknod, - mkdir=>\&x_mkdir, - unlink=>\&x_unlink, - rmdir=>\&x_rmdir, - symlink=>\&x_symlink, - rename=>\&x_rename, - link=>\&x_link, - chmod=>\&x_chmod, - chown=>\&x_chown, - truncate=>\&x_truncate, - utime=>\&x_utime, - open=>\&x_open, - read=>\&x_read, - write=>\&x_write, - statfs=>\&x_statfs, + '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