Skip to content

Commit

Permalink
lots of work to bring fh goodness into the API
Browse files Browse the repository at this point in the history
  • Loading branch information
Apocalypse committed Jan 25, 2009
1 parent e998d4d commit 9eb45b7
Show file tree
Hide file tree
Showing 14 changed files with 533 additions and 193 deletions.
44 changes: 41 additions & 3 deletions Build.PL
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
# Build.PL
use Module::Build;

my $ver = `fusermount -V 2>&1`;
my $ver2 = `mount_fusefs -V 2>&1`;
my $ver3 = `mount_fusefs -V 2>&1 | head -n1`;
chomp $ver if defined $ver; chomp $ver2 if defined $ver2; chomp $ver3 if defined $ver3;
$ver =~ s/^.*?version:\s+// if defined $ver;
$ver2 =~ s/^.*?version:\s+// if defined $ver2;
$ver3 =~ s/^.*?version\s+// if defined $ver3;
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") : (),
);
}
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";
} else {
warn "fuse version found: ", $ver || $ver2 || $ver3, "\n";
}

my $inc = '-DFUSE_USE_VERSION=25 ' . `pkg-config --cflags fuse` || '-I ../include -D_FILE_OFFSET_BITS=64';
my $obj = `pkg-config --libs fuse` || '-lfuse';
$inc .= '-Wall -g -ggdb';
$inc .= ' -D__FreeBSD__=10 -D_FILE_OFFSET_BITS=64' if $^O eq 'darwin';

my $build = Module::Build->new(
# look up Module::Build::API for the info!
'dynamic_config' => 0,
Expand All @@ -23,6 +54,10 @@ my $build = Module::Build->new(
'Test::More' => '0.86', # require latest for note() support in t/a_is_prereq_outdated.t
},

# set our XS stuff
'extra_compiler_flags' => $inc,
'extra_linker_flags' => $obj,

'requires' => {
# POE Stuff
'POE' => 0,
Expand All @@ -33,12 +68,15 @@ my $build = Module::Build->new(
'POE::Wheel::Run' => 0,
'POE::Filter::Reference' => 0,

# FUSE support
'Fuse' => '0.09',

# system constants
'Errno' => 0,
'Fcntl' => 0,
'Config' => 0,
'Carp' => 0,
'DynaLoader' => 0,

# to find out stuff about $fh
'Scalar::Util' => 0,
},

'recommends' => {
Expand Down
2 changes: 2 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Revision history for Perl extension POE::Component::Fuse
* 0.02

added support for Filesys::Virtual::Async
added some more options
fixed stupid mode screwup in examples/fuse.pl
POD tweaks

* 0.01
Expand Down
5 changes: 5 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ README
lib/POE/Component/Fuse.pm
lib/POE/Component/Fuse/SubProcess.pm
lib/POE/Component/Fuse/AsyncFsV.pm
lib/POE/Component/Fuse/myFuse.pm
lib/POE/Component/Fuse/myFuse.xs
META.yml
Changes

examples/fuse.pl
examples/vfilesys.pl
examples/vfilesys_async.pl
examples/vfilesys_async_dispatcher.pl
examples/vfilesys_async_inmemory.pl

t/1_load.t

Expand Down
92 changes: 55 additions & 37 deletions examples/fuse.pl
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,30 @@ sub POE::Component::Fuse::DEBUG { 1 }
use Errno qw( :POSIX ); # ENOENT EISDIR etc
use Fcntl qw( :DEFAULT :mode ); # S_IFREG S_IFDIR, O_SYNC O_LARGEFILE etc

use File::Stat::ModeString;

my %files = (
'/' => {
type => 0040,
mode => 0755,
mode => oct( '040755' ),
ctime => time()-1000,
},
'/a' => {
cont => "File 'a'.\n",
type => 0100,
mode => 0755,
mode => oct( 100755 ),
ctime => time()-2000,
},
'/b' => {
cont => "This is file 'b'.\n",
type => 0100,
mode => 0644,
mode => oct( 100644 ),
ctime => time()-1000,
},
'/foo' => {
type => 0040,
mode => 0755,
mode => oct( '040755' ),
ctime => time()-3000,
},
'/foo/bar' => {
cont => "APOCAL is the best!\nJust kidding :)",
type => 0100,
mode => 0755,
cont => "APOCAL is the best!\nJust kidding :)\n",
mode => oct( 100755 ),
ctime => time()-5000,
},
);
Expand All @@ -54,11 +51,28 @@ sub POE::Component::Fuse::DEBUG { 1 }

sub _start : State {
# create the fuse session
POE::Component::Fuse->spawn;
POE::Component::Fuse->spawn(
'umount' => 1,
);
print "Check us out at the default place: /tmp/poefuse\n";
print "This is an entirely in-memory filesystem, some things might not work.\n";
print "This is an entirely in-memory filesystem, some things might not work...\n";

$_[KERNEL]->delay_set( 'print_fs' => 30 );
}

sub print_fs : State {
print "dumping \%files hash\n";
foreach my $f ( keys %files ) {
print "\t$f -> mode(" . sprintf( "%04o", $files{$f}->{'mode'} ) . " - " .
mode_to_string( $files{$f}->{'mode'} ) . ")\n";
}

$_[KERNEL]->delay_set( 'print_fs' => 30 );

return;
}


sub _child : State {
return;
}
Expand All @@ -68,6 +82,7 @@ sub _stop : State {

sub fuse_CLOSED : State {
print "shutdown: $_[ARG0]\n";
$_[KERNEL]->alarm_remove_all();
return;
}

Expand All @@ -78,8 +93,15 @@ sub fuse_getattr : State {
if ( exists $files{ $path } ) {
my $size = exists( $files{ $path }{'cont'} ) ? length( $files{ $path }{'cont'} ) : 0;
$size = $files{ $path }{'size'} if exists $files{ $path }{'size'};
my $modes = ( $files{ $path }{'type'} << 9 ) + $files{ $path }{'mode'};
my $modes = $files{ $path }{'mode'};

my ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = ( 0, 0, 0, 1, (split( /\s+/, $) ))[0], $>, 1, 1024 );
if ( S_ISDIR( $modes ) ) {
# count the children directories
$nlink = 2; # start with 2 ( . and .. )
$nlink += grep { $_ =~ /^$path\/?[^\/]+$/ and S_ISDIR( $files{ $_ }{'mode'} ) } ( keys %files );
}

$gid = $files{ $path }{'gid'} if exists $files{ $path }{'gid'};
$uid = $files{ $path }{'uid'} if exists $files{ $path }{'uid'};
my ($atime, $ctime, $mtime);
Expand Down Expand Up @@ -112,7 +134,7 @@ sub fuse_getdir : State {
#print "GETDIR: '$path'\n";

if ( exists $files{ $path } ) {
if ( $files{ $path }{'type'} & 0040 ) {
if ( S_ISDIR( $files{ $path }{'mode'} ) ) {
# construct all the data in this directory
my @list = map { $_ =~ s/^$path\/?//; $_ }
grep { $_ =~ /^$path\/?[^\/]+$/ } ( keys %files );
Expand Down Expand Up @@ -168,7 +190,7 @@ sub fuse_removexattr : State {
#print "REMOVEXATTR: '$path' - '$attr'\n";

# we don't have any extended attribute support
$postback->( 0 );
$postback->( -ENOSYS() );

return;
}
Expand All @@ -177,11 +199,8 @@ sub fuse_open : State {
my( $postback, $context, $path, $flags ) = @_[ ARG0 .. ARG3 ];
#print "OPEN: '$path' - " . dump_open_flags( $flags );

# set some fake data in the fh
$context->{'fh'} = 5;

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# accept the open! ( we ignore the flags for now )
$postback->( 0 );
} else {
Expand All @@ -201,7 +220,7 @@ sub fuse_read : State {
#print "READ: '$path' - '$size' - '$offset'\n";

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# valid file, proceed with the read!

# sanity check, offset cannot be bigger than the length of the file!
Expand Down Expand Up @@ -233,7 +252,7 @@ sub fuse_flush : State {
#print "FLUSH: '$path'\n";

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# allow flushing of a file ( we don't track state so who cares, ha! )
$postback->( 0 );
} else {
Expand All @@ -253,7 +272,7 @@ sub fuse_release : State {
#print "RELEASE: '$path' - " . dump_open_flags( $flags );

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# allow releasing of a file ( we don't track state so who cares, ha! )
$postback->( 0 );
} else {
Expand All @@ -273,7 +292,7 @@ sub fuse_truncate : State {
#print "TRUNCATE: '$path' - '$offset'\n";

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# valid file, proceed with the truncate!

# sanity check, offset cannot be bigger than the length of the file!
Expand Down Expand Up @@ -306,7 +325,7 @@ sub fuse_write : State {
#print "WRITE: '$path' - '" . length( $buffer ) . "' - '$offset'\n";

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# valid file, proceed with the write!

# sanity check, offset cannot be bigger than the length of the file!
Expand All @@ -333,12 +352,7 @@ sub fuse_write : State {

sub fuse_mknod : State {
my( $postback, $context, $path, $modes, $device ) = @_[ ARG0 .. ARG4 ];

# cleanup the mode ( for some reason we get '100644' instead of '0644' )
# FIXME this seems to also screw up the S_ISREG() stuff, have to investigate more...
$modes = $modes & 000777;

#print "MKNOD: '$path' - '" . sprintf( "%04o", $modes ) . "' - '$device'\n";
#print "MKNOD: '$path' - '" . mode_to_string( $modes ) . "' - '$device'\n";

if ( exists $files{ $path } or $path eq '.' or $path eq '..' ) {
# already exists!
Expand All @@ -349,8 +363,10 @@ sub fuse_mknod : State {

# we only allow regular files to be created
if ( $device == 0 ) {
# make sure mode is proper
$modes = $modes | oct( '100000' );

$files{ $path } = {
type => 0100,
mode => $modes,
ctime => time(),
cont => "",
Expand All @@ -369,7 +385,7 @@ sub fuse_mknod : State {

sub fuse_mkdir : State {
my( $postback, $context, $path, $modes ) = @_[ ARG0 .. ARG3 ];
#print "MKDIR: '$path' - '" . sprintf( "%04o", $modes ) . "'\n";
#print "MKDIR: '$path' - '" . mode_to_string( $modes ) . "'\n";

if ( exists $files{ $path } ) {
# already exists!
Expand All @@ -378,9 +394,11 @@ sub fuse_mkdir : State {
# should we add validation to make sure all parents already exist
# seems like mkdir() and friends check themselves, so we don't have to do it...

# make sure mode is proper
$modes = $modes | oct( '040000' );

# create the directory!
$files{ $path } = {
type => 0040,
mode => $modes,
ctime => time(),
};
Expand All @@ -397,7 +415,7 @@ sub fuse_unlink : State {
#print "UNLINK: '$path'\n";

if ( exists $files{ $path } ) {
unless ( $files{ $path }{'type'} & 0040 ) {
if ( ! S_ISDIR( $files{ $path }{'mode'} ) ) {
# valid file, proceed with the deletion!
delete $files{ $path };

Expand All @@ -420,7 +438,7 @@ sub fuse_rmdir : State {
#print "RMDIR: '$path'\n";

if ( exists $files{ $path } ) {
if ( $files{ $path }{'type'} & 0040 ) {
if ( S_ISDIR( $files{ $path }{'mode'} ) ) {
# valid directory, does this directory have any children ( files, subdirs ) ??
my $children = grep { $_ =~ /^$path/ } ( keys %files );
if ( $children == 1 ) {
Expand Down Expand Up @@ -491,7 +509,7 @@ sub fuse_link : State {

sub fuse_chmod : State {
my( $postback, $context, $path, $modes ) = @_[ ARG0 .. ARG3 ];
#print "CHMOD: '$path' - '" . sprintf( "%04o", $modes ) . "'\n";
print "CHMOD: '$path' - '" . sprintf( "%04o", $modes ) . " - " . mode_to_string( $modes ) . "'\n";

if ( exists $files{ $path } ) {
# okay, update the mode!
Expand Down
1 change: 1 addition & 0 deletions examples/vfilesys.pl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use POE::Component::Fuse;
POE::Component::Fuse->spawn(
'vfilesys' => $vfs,
'umount' => 1,
);

print "Check us out at the default place: /tmp/poefuse\n";
Expand Down
28 changes: 28 additions & 0 deletions examples/vfilesys_async.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/perl
use strict; use warnings;

# uncomment this to have debugging
sub POE::Component::Fuse::DEBUG { 1 }

# loopback to our home directory!
use Filesys::Virtual::Async::Plain;
my $vfs = Filesys::Virtual::Async::Plain->new(
'cwd' => '/',
'root' => $ENV{'PWD'},
'home_path' => '/',
);

# load FUSE goodness
use POE::Component::Fuse;
POE::Component::Fuse->spawn(
'vfilesys' => $vfs,
'umount' => 1,
);

print "Check us out at the default place: /tmp/poefuse\n";
print "In it you should see the contents of the directory you ran this script from.\n";
print "LOOPBACK MAGIC! :)\n";

# fire up POE
POE::Kernel->run();
exit;
Loading

0 comments on commit 9eb45b7

Please sign in to comment.