#!/usr/bin/perl use strict; use DBI; use File::Basename; use Data::Dumper; use Fuse; use POSIX qw(ENOENT EISDIR EINVAL EEXIST); my (%files) = ( '/.' => { type => 0040, mode => 0755, uid => 0, gid => 0, ctime => time()-1000, atime => time()-1000, mtime => time()-1000, }, ); # Functions to parse paths sub path { my $f = shift; return undef unless $f; my($file, $dir, undef) = fileparse($f, ("")); return ($file, $dir); } sub d { my(undef, $dir) = path(shift); return $dir; } sub f { my ($file, undef) = path(shift); return $file; } sub ff_getdir { # Get the directory we are in my $path = shift; print "getdir(), \$path = $path\n"; my @list = (".",".."); if($files{$path}{'type'} != 0040) { $path = d($path); } foreach my $f (keys %files) { # we only want to send the files that belong here! if(d($f) ne $path) { if(d($f) ne "$path/") { next; } } next if f($f) =~ m/^.$/; next if $f eq $path; push @list, f($f); } print "DIR $path: [@list]\n"; return @list,0; } sub ff_open { my ($file, $dir) = path(shift); my $path = $dir.$file; return -EISDIR() if $file eq '.' or $file eq '..'; return -ENOENT() unless exists $files{$path}; return 0; } sub ff_getattr { my ($file, $dir) = path(shift); $file =~ s,^/,,; $file = '.' unless length($file); my $path = $dir.$file; return -ENOENT() unless exists($files{$path}); my ($size) = exists($files{"$dir$file"}{cont}) ? length($files{$path}{cont}) : 0; print "\$files{\$path}{mode} = $files{$path}{'mode'}\n"; print "[$files{$path}{'type'}, $files{$path}{'mode'}]\n"; my ($modes) = ($files{$path}{type}<<9) + $files{$path}{mode}; my ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = (0,0,0,1,0,0,1,1024); $uid = $files{$path}{'uid'}; $gid = $files{$path}{'gid'}; # We do not really have a block size since everything is in memroy. # We will make one up as 1K. $blocks = int($size/1024); $blocks = 1 if $blocks <= 0; # Add our times my ($atime, $ctime, $mtime); $atime = $files{$path}{'atime'}; $ctime = $files{$path}{'ctime'}; $mtime = $files{$path}{'mtime'}; # 2 possible types of return values: #return -ENOENT(); # or any other error you care to #print(join(",",($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)),"\n"); print "$dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks\n"; return ($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks); } sub ff_truncate { my($file, $dir) = f(shift); print "-> ff_truncate()\n"; return -EISDIR() if $file eq '.' or $file eq '..'; if(exists($files{$file}{'cont'})) { $files{$file}{'cont'} = ""; } print "ok\n"; return 0; } sub ff_read { # return an error numeric, or binary/text string. (note: 0 means EOF, "0" will # give a byte (ascii "0") to the reading program) my ($file, $dir) = path(shift); my $path = $dir.$file; my ($buf,$off) = @_; return -ENOENT() unless exists($files{$path}); return -EINVAL() if $off > length($files{$path}{cont}); return 0 if $off == length($files{$path}{cont}); return substr($files{$path}{cont},$off,$buf); } sub ff_write { my ($file, $dir) = path(shift); my $path = $dir.$file; my ($buf,$off) = @_; return -ENOENT() unless exists($files{$path}); $files{$path}{'cont'} .= $buf; return length($buf); } sub ff_unlink { my $file = f(shift); return -EISDIR() if $file eq '.' or $file eq '..'; return -ENOENT() unless exists($files{$file}); delete $files{$file}; return 0; } sub ff_statfs { my $tot = 0; my $fnum = 0; foreach my $f ( keys %files ) { $tot += length($files{$f}{'cont'}); $fnum++; } return(255, $fnum, 1, int($tot/1024), int($tot/1024)+1, 1024); } sub ff_readlink { return -ENOENT(); } sub ff_rmdir { return -ENOENT(); } sub ff_symlink { return -ENOENT(); } sub ff_rename { return -ENOENT(); } sub ff_link { return -ENOENT(); } sub ff_chmod { my $path = shift; my $modes = shift; return -ENOENT() unless exists $files{$path}; # now we need to get the mode my $mode = 0; $mode += 400 if ($modes & 0400); $mode += 200 if ($modes & 0200); $mode += 100 if ($modes & 0100); $mode += 40 if ($modes & 0040); $mode += 20 if ($modes & 0020); $mode += 10 if ($modes & 0010); $mode += 4 if ($modes & 0004); $mode += 2 if ($modes & 0002); $mode += 1 if ($modes & 0001); #$files{$path}{'mode'} = $mode; return 0; } sub ff_chown { return 0; } sub ff_utime { return 0; } sub ff_flush { return 0; } sub ff_release { return 0; } sub ff_fsync { return 0; } sub ff_setxattr { return 0; } sub ff_getxattr { return 0; } sub ff_listxattr { return 0; } sub ff_removexattr { return 0; } sub ff_mknod { my ($f, $modes, $dev) = @_; my ($file, $dir) = path($f); my $path = $dir.$file; if(not exists($files{$path})) { $files{$path}{'cont'} = ""; $files{$path}{'type'} = 0100; $files{$path}{'mode'} = 0644; $files{$path}{'ctime'} = time(); $files{$path}{'atime'} = time(); $files{$path}{'mtime'} = time(); } return 0; } sub ff_mkdir { my ($file, $dir) = path(shift); my $path = $dir.$file; return -EEXIST() if exists $files{$path}; $files{$path}{'type'} = 0040; $files{$path}{'mode'} = 0755; $files{$path}{'ctime'} = time(); $files{$path."/."}{'type'} = 0040; $files{$path."/."}{'mode'} = 0755; $files{$path."/."}{'ctime'} = time(); return 0; } my ($mountpoint) = ""; $mountpoint = shift(@ARGV) if @ARGV; Fuse::main( 'mountpoint'=> $mountpoint, 'chmod' => "main::ff_chmod", 'open' => "main::ff_open", 'read' => "main::ff_read", write => "main::ff_write", 'getdir' => "main::ff_getdir", 'getattr' => "main::ff_getattr", 'truncate' => "main::ff_truncate", 'readlink' => "main::ff_readlink", 'unlink' => "main::ff_unlink", 'rmdir' => "main::ff_rmdir", 'symlink' => "main::ff_symlink", 'rename' => "main::ff_rename", 'link' => "main::ff_link", 'chown' => "main::ff_chown", 'utime' => "main::ff_utime", 'statfs' => "main::ff_statfs", 'flush' => "main::ff_flush", 'release' => "main::ff_release", 'fsync' => "main::ff_fsync", 'setxattr' => "main::ff_setxattr", 'getxattr' => "main::ff_getxattr", 'listxattr' => "main::ff_listxattr", 'removexattr' => "main::ff_removexattr", 'mknod' => "main::ff_mknod", mkdir =>"main::ff_mkdir", 'threaded' => 0, 'debug' => 1 ); # vi: set ts=2 sw=2: #