aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2001-12-03 08:35:41 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2001-12-03 08:35:41 +0000
commitbf36016741c473b476aadef46ec9d7869523b8c0 (patch)
treeab629e0f6422709239daaed0ef10ce872bdde864
parent0e66d057a42a5ef6dff3a5354a449f0373f3415d (diff)
perl bindings
-rw-r--r--AUTHORS6
-rw-r--r--perl/Changes8
-rw-r--r--perl/Fuse.pm228
-rw-r--r--perl/Fuse.xs521
-rw-r--r--perl/MANIFEST8
-rw-r--r--perl/Makefile.PL17
-rw-r--r--perl/README26
-rwxr-xr-xperl/example.pl83
-rw-r--r--perl/test.pl18
9 files changed, 915 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index 5d0a86a..a81e3c0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,3 +8,9 @@ Python bindings
---------------
Jeff Epler <jepler@unpythonic.dhs.org>
+
+
+Perl bindings
+-------------
+
+Mark Glines <mark@glines.org>
diff --git a/perl/Changes b/perl/Changes
new file mode 100644
index 0000000..3981203
--- /dev/null
+++ b/perl/Changes
@@ -0,0 +1,8 @@
+Revision history for Perl extension Fuse.
+
+0.01 Wed Nov 28 21:45:20 2001
+ - original version; created by h2xs 1.21 with options
+ include/fuse.h
+
+0.02 Sun Dec 2 18:59:56 2001
+ - works well enough to release, but still needs testing
diff --git a/perl/Fuse.pm b/perl/Fuse.pm
new file mode 100644
index 0000000..2f4742a
--- /dev/null
+++ b/perl/Fuse.pm
@@ -0,0 +1,228 @@
+package Fuse;
+
+use 5.006;
+use strict;
+use warnings;
+use Errno;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+use Data::Dumper;
+our @ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use Fuse ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw(
+ FUSE_DEBUG
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+ FUSE_DEBUG
+);
+our $VERSION = '0.01';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my $constname;
+ our $AUTOLOAD;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "& not defined" if $constname eq 'constant';
+ my $val = constant($constname, @_ ? $_[0] : 0);
+ if ($! != 0) {
+ if ($!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined Fuse macro $constname";
+ }
+ }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+ if ($] >= 5.00561) {
+ *$AUTOLOAD = sub () { $val };
+ }
+ else {
+ *$AUTOLOAD = sub { $val };
+ }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap Fuse $VERSION;
+
+sub main {
+ my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+ my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink rename link chmod chown truncate utime open read write);
+ my ($tmp) = 0;
+ my (%mapping) = map { $_ => $tmp++ } (@names);
+ my (%otherargs) = (debug=>0, threaded=>1, mountpoint=>"");
+ while(my $name = shift) {
+ my ($subref) = shift;
+ if(exists($otherargs{$name})) {
+ $otherargs{$name} = $subref;
+ } else {
+ croak "There is no function $name" unless exists($mapping{$name});
+ croak "Usage: Fuse::main(getattr => &my_getattr, ...)" unless $subref;
+ croak "Usage: Fuse::main(getattr => &my_getattr, ...)" unless ref($subref);
+ croak "Usage: Fuse::main(getattr => &my_getattr, ...)" unless ref($subref) eq "CODE";
+ $subs[$mapping{$name}] = $subref;
+ }
+ }
+ perl_fuse_main($0,$otherargs{threaded},$otherargs{debug},$otherargs{mountpoint},@subs);
+}
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+Fuse - write filesystems in Perl using FUSE
+
+=head1 SYNOPSIS
+
+ use Fuse;
+ my ($mountpoint) = "";
+ $mountpoint = shift(@ARGV) if @ARGV;
+ Fuse::main(mountpoint=>$mountpoint,getattr=>\&my_getattr,getdir=>\&my_getdir, ...);
+
+=head1 DESCRIPTION
+
+This lets you implement filesystems in perl, through the FUSE (Filesystem in USErspace) kernel/lib interface.
+
+FUSE expects you to implement callbacks for the various functions.
+
+NOTE: I have only tested the things implemented in example.pl! It should work, but some things may not.
+
+In the following definitions, "errno" can be 0 (for a success), -EINVAL, -ENOENT, -EONFIRE, any integer less than 1 really.
+You can import standard error constants by saying something like "use POSIX qw(EDOTDOT ENOANO);".
+
+=head2 FUNCTIONS
+
+=head3 getattr
+
+Arguments: filename.
+Returns a list, one of the following 4 possibilities:
+
+$errno or
+
+($blocks,$size,$gid,$uid,$nlink,$modes,$time) or
+
+($errno,$blocks,$size,$gid,$uid,$nlink,$modes,$time) or
+
+($errno,$blksize,$blocks,$size,$gid,$uid,$nlink,$modes,$time)
+
+B<FIXME>: device numeric, for filesystems that implement mknod?
+
+=head3 readlink
+
+Arguments: link pathname.
+Returns a scalar: either a numeric constant, or a text string.
+
+=head3 getdir
+
+Arguments: Containing directory name.
+Returns a list: 0 or more text strings (the filenames), followed by errno (usually 0).
+
+=head3 mknod
+
+Arguments: Filename, numeric modes, numeric device
+Returns an errno (0 upon success, as usual).
+
+=head3 mkdir
+
+Arguments: New directory pathname, numeric modes.
+Returns an errno.
+
+=head3 unlink
+
+Arguments: Filename.
+Returns an errno.
+
+=head3 rmdir
+
+Arguments: Pathname.
+Returns an errno.
+
+=head3 symlink
+
+Arguments: Existing filename, symlink name.
+Returns an errno.
+
+=head3 rename
+
+Arguments: old filename, new filename.
+Returns an errno.
+
+=head3 link
+
+Arguments: Existing filename, hardlink name.
+Returns an errno.
+
+=head3 chmod
+
+Arguments: Pathname, numeric modes.
+Returns an errno.
+
+=head3 chown
+
+Arguments: Pathname, numeric uid, numeric gid.
+Returns an errno.
+
+=head3 truncate
+
+Arguments: Pathname, numeric offset.
+Returns an errno.
+
+=head3 utime
+
+Arguments: Pathname, numeric actime, numeric modtime.
+Returns an errno.
+
+=head3 open
+
+Arguments: Pathname, numeric flags (which is an OR-ing of stuff like O_RDONLY and O_SYNC, constants you can import from POSIX).
+Returns an errno.
+
+=head3 read
+
+Arguments: Pathname, numeric requestedsize, numeric offset.
+Returns a numeric errno, or a string scalar with up to $requestedsize bytes of data.
+
+=head3 write
+
+Arguments: Pathname, scalar buffer, numeric offset. You can use length($buffer) to find the buffersize.
+Returns an errno.
+
+=head2 EXPORT
+
+None by default.
+
+=head2 Exportable constants
+
+None.
+
+=head1 AUTHOR
+
+Mark Glines, E<lt>mark@glines.orgE<gt>
+
+=head1 SEE ALSO
+
+L<perl>, the FUSE documentation.
+
+=cut
diff --git a/perl/Fuse.xs b/perl/Fuse.xs
new file mode 100644
index 0000000..9770c3a
--- /dev/null
+++ b/perl/Fuse.xs
@@ -0,0 +1,521 @@
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <fuse.h>
+
+static int
+not_here(char *s)
+{
+ croak("%s not implemented on this architecture", s);
+ return -1;
+}
+
+static double
+constant(char *name, int len, int arg)
+{
+ errno = ENOENT;
+ return 0;
+}
+
+SV *_PLfuse_callbacks[17];
+
+int _PLfuse_getattr(const char *file, struct stat *result) {
+ dSP;
+ int rv, statcount;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,strlen(file))));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[0],G_ARRAY);
+ SPAGAIN;
+ if(rv < 7) {
+ if(rv > 1)
+ croak("inappropriate number of returned values from getattr");
+ if(rv)
+ rv = POPi;
+ else
+ rv = -EINVAL;
+ } else {
+ if(rv > 9)
+ croak("inappropriate number of returned values from getattr");
+ result->st_ctime = result->st_mtime = result->st_atime = POPi;
+ result->st_mode = POPi;
+ result->st_nlink = POPi;
+ result->st_uid = POPi;
+ result->st_gid = POPi;
+ result->st_size = POPi;
+ result->st_blocks = POPi;
+ if(rv > 7) {
+ if(rv > 8)
+ result->st_blksize = POPi;
+ else
+ result->st_blksize = 1024;
+ rv = POPi;
+ } else {
+ result->st_blksize = 1024;
+ rv = 0;
+ }
+ }
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
+ int rv;
+ char *rvstr;
+ dXSARGS;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
+ SPAGAIN;
+ if(!rv)
+ rv = -ENOENT;
+ else
+ if(SvTYPE(ST(0)) == SVt_IV)
+ rv = POPi;
+ else {
+ strncpy(buf,POPp,buflen);
+ rv = 0;
+ }
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
+ int prv, rv;
+ dXSARGS;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ PUTBACK;
+ prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
+ SPAGAIN;
+ if(prv) {
+ SV *mysv = POPs;
+ if(!SvIOK(mysv)) {
+ fprintf(stderr,"last getdir retval needs to be numeric (e.g. 0 or -ENOENT) (%s)\n",SvPV_nolen(mysv));
+ rv = -ENOSYS;
+ } else {
+ rv = SvIV(mysv);
+ while(--prv)
+ dirfil(dirh,POPp,0);
+ }
+ } else {
+ fprintf(stderr,"getdir() handler returned nothing!\n");
+ rv = -ENOSYS;
+ }
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(mode)));
+ XPUSHs(sv_2mortal(newSViv(dev)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[3],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_mkdir (const char *file, mode_t mode) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(mode)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[4],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+
+int _PLfuse_unlink (const char *file) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[5],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_rmdir (const char *file) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[6],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_symlink (const char *file, const char *new) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSVpv(new,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[7],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_rename (const char *file, const char *new) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSVpv(new,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[8],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_link (const char *file, const char *new) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSVpv(new,0)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[9],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_chmod (const char *file, mode_t mode) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(mode)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[10],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(uid)));
+ XPUSHs(sv_2mortal(newSViv(gid)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[11],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_truncate (const char *file, off_t off) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(off)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[12],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_utime (const char *file, struct utimbuf *uti) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(uti->actime)));
+ XPUSHs(sv_2mortal(newSViv(uti->modtime)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[13],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_open (const char *file, int flags) {
+ int rv;
+ SV *rvsv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(flags)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[14],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) {
+ int rv;
+ char *rvstr;
+ dXSARGS;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSViv(buflen)));
+ XPUSHs(sv_2mortal(newSViv(off)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[15],G_SCALAR);
+ SPAGAIN;
+ if(!rv)
+ rv = -ENOENT;
+ else {
+ SV *mysv = sv_2mortal(POPs);
+ if(SvTYPE(mysv) == SVt_IV)
+ rv = SvIV(mysv);
+ else {
+ rv = SvLEN(mysv);
+ if(rv > buflen)
+ croak("read() handler returned more than buflen!");
+ if(rv)
+ memcpy(buf,SvPV_nolen(mysv),rv);
+ }
+ }
+ return rv;
+}
+
+int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) {
+ int rv;
+ char *rvstr;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv(file,0)));
+ XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
+ XPUSHs(sv_2mortal(newSViv(off)));
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[16],G_SCALAR);
+ SPAGAIN;
+ if(rv)
+ rv = POPi;
+ else
+ rv = 0;
+ FREETMPS;
+ LEAVE;
+ return rv;
+}
+
+struct fuse_operations _available_ops = {
+getattr: _PLfuse_getattr,
+ _PLfuse_readlink,
+ _PLfuse_getdir,
+ _PLfuse_mknod,
+ _PLfuse_mkdir,
+ _PLfuse_unlink,
+ _PLfuse_rmdir,
+ _PLfuse_symlink,
+ _PLfuse_rename,
+ _PLfuse_link,
+ _PLfuse_chmod,
+ _PLfuse_chown,
+ _PLfuse_truncate,
+ _PLfuse_utime,
+ _PLfuse_open,
+ _PLfuse_read,
+ _PLfuse_write
+};
+
+MODULE = Fuse PACKAGE = Fuse
+PROTOTYPES: DISABLE
+
+
+double
+constant(sv,arg)
+ PREINIT:
+ STRLEN len;
+ INPUT:
+ SV * sv
+ char * s = SvPV(sv, len);
+ int arg
+ CODE:
+ RETVAL = constant(s,len,arg);
+ OUTPUT:
+ RETVAL
+
+void
+perl_fuse_main(...)
+ PREINIT:
+ struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ int i, varnum = 0, threads, debug, argc;
+ char **argv;
+ STRLEN n_a;
+ STRLEN l;
+ INIT:
+ if(items != 21) {
+ fprintf(stderr,"Perl<->C inconsistency or internal error\n");
+ XSRETURN_UNDEF;
+ }
+ CODE:
+ threads = !SvIV(ST(1));
+ debug = SvIV(ST(2));
+ if(threads && debug) {
+ argc = 4;
+ argv = ((char*[]){NULL,NULL,"-s","-d"});
+ } else if(threads) {
+ argc = 3;
+ argv = ((char*[]){NULL,NULL,"-s"});
+ } else if(debug) {
+ argc = 3;
+ argv = ((char*[]){NULL,NULL,"-d"});
+ } else {
+ argc = 2;
+ argv = ((char*[]){"str","mnt"});
+ }
+ argv[0] = SvPV(ST(0),n_a);
+ if(strlen(SvPV(ST(3),n_a)))
+ argv[1] = SvPV(ST(3),n_a);
+ else
+ argc--;
+
+ for(i=0;i<17;i++) {
+ SV *var = ST(i+4);
+ if((var != &PL_sv_undef) && SvROK(var)) {
+ if(SvTYPE(SvRV(var)) == SVt_PVCV) {
+ void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops;
+ tmp2[i] = tmp1[i];
+ _PLfuse_callbacks[i] = var;
+ } else
+ croak("arg is not a code reference!");
+ }
+ }
+ fuse_main(argc,argv,&fops);
diff --git a/perl/MANIFEST b/perl/MANIFEST
new file mode 100644
index 0000000..9d7f036
--- /dev/null
+++ b/perl/MANIFEST
@@ -0,0 +1,8 @@
+Changes
+Fuse.pm
+Fuse.xs
+Makefile.PL
+MANIFEST
+README
+test.pl
+example.pl
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
new file mode 100644
index 0000000..d495683
--- /dev/null
+++ b/perl/Makefile.PL
@@ -0,0 +1,17 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+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>') : ()),
+ 'LIBS' => [''], # e.g., '-lm'
+ 'DEFINE' => '-g -ggdb', # e.g., '-DHAVE_SOMETHING'
+ # Insert -I. if you add *.h files later:
+ 'INC' => '-I../include', # e.g., '-I/usr/include/other'
+ # Un-comment this if you add C files to link with later:
+ 'OBJECT' => 'Fuse.o ../lib/libfuse.a -lpthread', # link all the C files too
+);
diff --git a/perl/README b/perl/README
new file mode 100644
index 0000000..b22b87e
--- /dev/null
+++ b/perl/README
@@ -0,0 +1,26 @@
+Fuse version 0.01
+=================
+
+This is a test release. It seems to work thus far, but still has a few
+iffy areas, as well as a few rough edges. There will be future
+releases.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test # currently this just makes sure the lib can link
+ make install
+
+DEPENDENCIES
+
+This module requires the FUSE userspace library and the FUSE kernel module.
+
+COPYRIGHT AND LICENCE
+
+This is contributed to the FUSE project by Mark Glines <mark@glines.org>,
+and is therefore subject to the same license and copyright as FUSE itself.
+Please see the AUTHORS and COPYING files from the FUSE distribution for
+more information.
diff --git a/perl/example.pl b/perl/example.pl
new file mode 100755
index 0000000..257f2c9
--- /dev/null
+++ b/perl/example.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+use Fuse;
+use POSIX qw(ENOENT EISDIR EINVAL);
+
+my (%files) = (
+ '.' => {
+ type => 0040,
+ mode => 0755,
+ ctime => time()-1000
+ },
+ a => {
+ cont => "File 'a'.\n",
+ type => 0100,
+ mode => 0755,
+ ctime => time()-2000
+ },
+ b => {
+ cont => "This is file 'b'.\n",
+ type => 0100,
+ mode => 0644,
+ ctime => time()-1000
+ },
+);
+
+sub filename_fixup {
+ my ($file) = shift;
+ $file =~ s,^/,,;
+ $file = '.' unless length($file);
+ return $file;
+}
+
+sub e_getattr {
+ my ($file) = filename_fixup(shift);
+ $file =~ s,^/,,;
+ $file = '.' unless length($file);
+ return -ENOENT() unless exists($files{$file});
+ my ($size) = exists($files{$file}{cont}) ? length($files{$file}{cont}) : 0;
+ my ($modes) = ($files{$file}{type}<<9) + $files{$file}{mode};
+ my ($blocks, $gid, $uid, $nlink) = (1,0,0,1);
+ # 4 possible return values:
+ #return -ENOENT(); # or any other error you care to
+ return ($blocks,$size,$gid,$uid,$nlink,$modes,$files{$file}{ctime});
+ # return ($errno,$blocks,$size,$gid,$uid,$nlink,$modes,$time);
+ # return ($errno,$blksize,$blocks,$size,$gid,$uid,$nlink,$modes,$time);
+ # if omitted, errno defaults to 0, and blksize defaults to 1024.
+}
+
+sub e_getdir {
+ # return as many text filenames as you like, followed by the retval.
+ return (keys %files),0;
+}
+
+sub e_open {
+ # VFS sanity check; it keeps all the necessary state, not much to do here.
+ my ($file) = filename_fixup(shift);
+ return -ENOENT() unless exists($files{$file});
+ return -EISDIR() unless exists($files{$file}{cont});
+ return 0;
+}
+
+sub e_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) = filename_fixup(shift);
+ my ($buf,$off) = @_;
+ return -ENOENT() unless exists($files{$file});
+ return -EINVAL() if $off > length($files{$file}{cont});
+ return 0 if $off == length($files{$file}{cont});
+ return substr($files{$file}{cont},$off,$buf);
+}
+
+# If you run the script directly, it will run fusermount, which will in turn
+# re-run this script. Hence the funky semantics.
+my ($mountpoint) = "";
+$mountpoint = shift(@ARGV) if @ARGV;
+Fuse::main(
+ mountpoint=>$mountpoint,
+ getattr=>\&e_getattr,
+ getdir=>\&e_getdir,
+ open=>\&e_open,
+ read=>\&e_read,
+);
diff --git a/perl/test.pl b/perl/test.pl
new file mode 100644
index 0000000..eee3421
--- /dev/null
+++ b/perl/test.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { plan tests => 1 };
+use Fuse;
+ok(1); # If we made it this far, we're ok.
+#########################
+
+# Insert your test code below, the Test module is use()ed here so read
+# its man page ( perldoc Test ) for help writing this test script.
+
+# haven't written anything, because I don't want to require root