diff options
Diffstat (limited to 'perl/loopback.pl')
-rw-r--r-- | perl/loopback.pl | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/perl/loopback.pl b/perl/loopback.pl new file mode 100644 index 0000000..2a8496a --- /dev/null +++ b/perl/loopback.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl + +use strict; +use Fuse; +use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT); +use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO); + +sub debug { + print(STDERR join(",",@_),"\n"); +} + +sub fixup { return "/tmp/test" . shift } + +sub x_getattr { + my ($file) = fixup(shift); + debug("getattr $file"); + return -ENOENT() unless -e $file; + debug(stat($file)); + return (stat($file)); +} + +sub x_getdir { + my ($dirname) = fixup(shift); + debug("getdir >$dirname<"); + unless(opendir(DIRHANDLE,$dirname)) { + debug("ENOENT"); + return -ENOENT(); + } + debug("ok"); + my (@files) = readdir(DIRHANDLE); + closedir(DIRHANDLE); + debug(@files); + return (@files, 0); +} + +sub x_open { + my ($file) = fixup(shift); + debug("open flags = $_[0]"); + my ($fd) = POSIX::open($file,@_); + if(!defined($fd)) { + debug("POSIX::open(".join(",",$file,@_).") returned undef"); + return -ENOSYS(); + } + debug("open $file = $fd"); + return $fd if $fd < 0; + POSIX::close($fd); + debug("good: $fd"); + return 0; +} + +sub x_read { + my ($file,$bufsize,$off) = @_; + debug("read",@_); + my ($rv) = -ENOSYS(); + return -ENOENT() unless -e ($file = fixup($file)); + return -ENOSYS() unless sysopen(FILE,$file,O_RDONLY()); + if(sysseek(FILE,$off,0)) { sysread(FILE,$rv,$bufsize); } + close(FILE); + debug("good"); + return $rv; +} + +sub x_write { + my ($file,$buf,$off) = @_; + debug("write",@_); + my ($rv); + return -ENOENT() unless -e ($file = fixup($file)); + return -ENOSYS() unless sysopen(FILE,$file,O_RDWR()|O_APPEND()|O_CREAT()); + if(sysseek(FILE,$off,0)) { $rv = syswrite(FILE,$buf); } + $rv = -ENOSYS() unless $rv; + close(FILE); + debug("good"); + return $rv; +} + +sub err { return (-shift || -$!) } + +sub x_readlink { return err(readlink(fixup(shift)) ); } +sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!; } +sub x_rmdir { return err(rmdir(fixup(shift)) ); } +sub x_symlink { return err(symlink(fixup(shift),fixup(shift))); } +sub x_rename { return err(rename(fixup(shift),fixup(shift)) ); } +sub x_link { return err(link(fixup(shift),fixup(shift)) ); } +sub x_mkdir { return err(mkdir(fixup(shift),shift) ); } +sub x_chmod { return err(chmod(fixup(shift),shift) ); } +sub x_chown { return err(chown(fixup(shift),shift,shift) ); } +sub x_chmod { return err(chmod(fixup(shift),shift) ); } +sub x_truncate { return err(truncate(fixup(shift),shift) ); } +sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; } + +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) = @_; + return -EEXIST() if -e ($file = fixup($file)); + return -EPERM() if (system("touch $file 2>/dev/null") >> 8); + if(S_ISBLK($modes) || S_ISCHR($modes) || S_ISFIFO($modes)) { + system("rm -f $file 2>/dev/null"); + my ($chr) = 'c'; + my ($omodes) = sprintf("%o",$modes & 0x1ff); + $chr = 'b' if S_ISBLK($modes); + if(S_ISFIFO($modes)) { + $chr = 'p'; + $dev = ""; + } else { + $dev = (($dev>>8) & 255) . " " . ($dev & 255); + } + system("mknod --mode=$omodes '$file' $chr $dev"); + } +} + +my ($mountpoint) = ""; +$mountpoint = shift(@ARGV) if @ARGV; +Fuse::main(mountpoint=>$mountpoint, getattr=>\&x_getattr, readlink=>\&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 +); |