? Fuse-0.04.tar.gz
? Fuse-0.05.tar
? Fuse-0.05.tar.gz
? Fuse-0.06.tar.gz
? attrtest.img
? fuse-perl-manifest-include-tests.diff
? fuse-perl-tests-2.2.1-as-user.diff
? fuse-perl-tests-2.2.1-as-user.lst
? fuse-perl-tests-x86_64.diff
? fuse-perl-tests-x86_64.lst
? fuse-perl-xattr-20050330.diff
? fuse-perl-xattr-20050403-submitted.diff
? fuse-perl-xattr-20050403.diff
? mkrpm
? examples/example
Index: Changes
===================================================================
RCS file: /cvsroot/fuse/perl/Changes,v
retrieving revision 1.2
diff -p -u -r1.2 Changes
--- Changes	18 Nov 2004 13:09:10 -0000	1.2
+++ Changes	3 Apr 2005 15:22:29 -0000
@@ -15,3 +15,6 @@ Revision history for Perl extension Fuse
     - new maintainer, Dobrica Pavlinusic <dpavlin@rot13.org>
     - updated to work with current CVS version of fuse
 
+0.06 Sun Apr 03 16:15:00 BST 2005
+    - Add support for operations supported by FUSE 2.2.1
+      (flush, release, fsync, extended attributes)
Index: Fuse.pm
===================================================================
RCS file: /cvsroot/fuse/perl/Fuse.pm,v
retrieving revision 1.3
diff -p -u -r1.3 Fuse.pm
--- Fuse.pm	20 Mar 2005 01:41:27 -0000	1.3
+++ Fuse.pm	3 Apr 2005 15:22:29 -0000
@@ -19,16 +19,18 @@ our @ISA = qw(Exporter DynaLoader);
 # 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_TAGS = (
+		    'all' => [ qw(FUSE_DEBUG XATTR_CREATE XATTR_REPLACE) ],
+		    'debug' => [ qw(FUSE_DEBUG) ],
+		    'xattr' => [ qw(XATTR_CREATE XATTR_REPLACE) ]
+		    );
 
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
 
 our @EXPORT = qw(
 	FUSE_DEBUG
 );
-our $VERSION = '0.05';
+our $VERSION = '0.06';
 
 sub AUTOLOAD {
     # This AUTOLOAD is used to 'autoload' constants from the constant()
@@ -62,12 +64,23 @@ sub AUTOLOAD {
     goto &$AUTOLOAD;
 }
 
+sub XATTR_CREATE {
+    # See <sys/xattr.h>.
+    return 1;
+}
+
+sub XATTR_REPLACE {
+    # See <sys/xattr.h>.
+    return 2;
+}
+
 bootstrap Fuse $VERSION;
 
 sub main {
-	my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+	my (@subs) = (0,0,0,0,0,0,0,0,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 statfs);
+			 rename link chmod chown truncate utime open read write statfs
+			 flush release fsync setxattr getxattr listxattr removexattr);
 	my ($tmp) = 0;
 	my (%mapping) = map { $_ => $tmp++ } (@names);
 	my (%otherargs) = (debug=>0, mountpoint=>"");
@@ -122,13 +135,17 @@ Every constant you need (file types, ope
 etc) can be imported either from POSIX or from Fcntl, often both.
 See their respective documentations, for more information.
 
-=head2 EXPORT
+=head2 EXPORTED SYMBOLS
+
+FUSE_DEBUG by default.
 
-None by default.
+You can request all exportable symbols by using the tag ":all".
 
-=head2 EXPORTABLE CONSTANTS
+You can request all debug symbols by using the tag ":debug".
+This will export FUSE_DEBUG.
 
-None.
+You can request the extended attribute symbols by using the tag ":xattr".
+This will export XATTR_CREATE and XATTR_REPLACE.
 
 =head2 FUNCTIONS
 
@@ -349,6 +366,70 @@ or
 
 -ENOANO(), $namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize
 
+=head3 flush
+
+Arguments: Pathname
+Returns an errno or 0 on success.
+
+Called to synchronise any cached data. This is called before the file
+is closed. It may be called multiple times before a file is closed.
+
+=head3 release
+
+Arguments: Pathname, numeric flags passed to open
+Returns an errno or 0 on success.
+
+Called to indicate that there are no more references to the file. Called once
+for every file with the same pathname and flags as were passed to open.
+
+=head3 fsync
+
+Arguments: Pathname, numeric flags
+Returns an errno or 0 on success.
+
+Called to synchronise the file's contents. If flags is non-zero,
+only synchronise the user data. Otherwise synchronise the user and meta data.
+
+=head3 setxattr
+
+Arguments: Pathname, extended attribute's name, extended attribute's value, numeric flags (which is an OR-ing of XATTR_CREATE and XATTR_REPLACE 
+Returns an errno or 0 on success.
+
+Called to set the value of the named extended attribute.
+
+If you wish to reject setting of a particular form of extended attribute name
+(e.g.: regexps matching user\..* or security\..*), then return - EOPNOTSUPP.
+
+If flags is set to XATTR_CREATE and the extended attribute already exists,
+this should fail with - EEXIST. If flags is set to XATTR_REPLACE
+and the extended attribute doesn't exist, this should fail with - ENOATTR.
+
+XATTR_CREATE and XATTR_REPLACE are provided by this module, but not exported
+by default. To import them:
+
+    use Fuse ':xattr';
+
+or:
+
+    use Fuse ':all';
+
+=head3 getxattr
+
+Arguments: Pathname, extended attribute's name
+Returns an errno, 0 if there was no value, or the extended attribute's value.
+
+Called to get the value of the named extended attribute.
+
+=head3 listxattr
+
+Arguments: Pathname
+Returns a list: 0 or more text strings (the extended attribute names), followed by a numeric errno (usually 0).
+
+=head3 removexattr
+
+Arguments: Pathname, extended attribute's name
+Returns an errno or 0 on success.
+
 =head1 AUTHOR
 
 Mark Glines, E<lt>mark@glines.orgE<gt>
Index: Fuse.xs
===================================================================
RCS file: /cvsroot/fuse/perl/Fuse.xs,v
retrieving revision 1.4
diff -p -u -r1.4 Fuse.xs
--- Fuse.xs	8 Jan 2005 00:38:41 -0000	1.4
+++ Fuse.xs	3 Apr 2005 15:22:30 -0000
@@ -11,7 +11,8 @@
 #define DEBUGf(a...)
 #endif
 
-SV *_PLfuse_callbacks[18];
+#define N_CALLBACKS 25
+SV *_PLfuse_callbacks[N_CALLBACKS];
 
 int _PLfuse_getattr(const char *file, struct stat *result) {
 	dSP;
@@ -510,25 +511,261 @@ int _PLfuse_statfs (const char *file, st
 	return rv;
 }
 
+int _PLfuse_flush (const char *file) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("flush begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[18],G_SCALAR);
+	SPAGAIN;
+	if(rv)
+		rv = POPi;
+	else
+		rv = 0;
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("flush end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_release (const char *file, int flags) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("release begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	XPUSHs(sv_2mortal(newSViv(flags)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[19],G_SCALAR);
+	SPAGAIN;
+	if(rv)
+		rv = POPi;
+	else
+		rv = 0;
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("release end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_fsync (const char *file, int flags) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("fsync begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	XPUSHs(sv_2mortal(newSViv(flags)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[20],G_SCALAR);
+	SPAGAIN;
+	if(rv)
+		rv = POPi;
+	else
+		rv = 0;
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("fsync end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("setxattr begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	XPUSHs(sv_2mortal(newSVpv(name,0)));
+	XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
+	XPUSHs(sv_2mortal(newSViv(flags)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[21],G_SCALAR);
+	SPAGAIN;
+	if(rv)
+		rv = POPi;
+	else
+		rv = 0;
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("setxattr end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("getxattr begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	XPUSHs(sv_2mortal(newSVpv(name,0)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[22],G_SCALAR);
+	SPAGAIN;
+	if(!rv)
+		rv = -ENOENT;
+	else {
+		SV *mysv = POPs;
+
+		rv = 0;
+		if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
+			rv = SvIV(mysv);
+		else {
+			if(SvPOK(mysv)) {
+				rv = SvCUR(mysv);
+			} else {
+				rv = 0;
+			}
+			if ((rv > 0) && (buflen > 0))
+			{
+				if(rv > buflen)
+					rv = -ERANGE;
+				else
+					memcpy(buf,SvPV_nolen(mysv),rv);
+			}
+		}
+	}
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("getxattr end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_listxattr (const char *file, char *list, size_t size) {
+	int prv, rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("listxattr begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	PUTBACK;
+	prv = call_sv(_PLfuse_callbacks[23],G_ARRAY);
+	SPAGAIN;
+	if(!prv)
+		rv = -ENOENT;
+	else {
+
+		char *p = list;
+		int spc = size;
+		int total_len = 0;
+		int i;
+
+		rv = POPi;
+		prv--;
+
+		/* Always nul terminate */
+		if (list && (size > 0))
+			list[0] = '\0';
+
+		while (prv > 0)
+		{
+			SV *mysv = POPs;
+			prv--;
+
+			if (SvPOK(mysv)) {
+				/* Copy nul too */
+				int s = SvCUR(mysv) + 1;
+				total_len += s;
+
+				if (p && (size > 0) && (spc >= s))
+				{
+					memcpy(p,SvPV_nolen(mysv),s);
+					p += s;
+					spc -= s;
+				}
+			}
+		}
+
+		/*
+		 * If the Perl returned an error, return that.
+		 * Otherwise check that the buffer was big enough.
+		 */
+		if (rv == 0)
+		{
+			rv = total_len;
+			if ((size > 0) && (size < total_len))
+				rv = -ERANGE;
+		}
+	}
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("listxattr end: %i\n",sp-PL_stack_base);
+	return rv;
+}
+
+int _PLfuse_removexattr (const char *file, const char *name) {
+	int rv;
+	char *rvstr;
+	dSP;
+	DEBUGf("removexattr begin: %i\n",sp-PL_stack_base);
+	ENTER;
+	SAVETMPS;
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSVpv(file,0)));
+	XPUSHs(sv_2mortal(newSVpv(name,0)));
+	PUTBACK;
+	rv = call_sv(_PLfuse_callbacks[24],G_SCALAR);
+	SPAGAIN;
+	if(rv)
+		rv = POPi;
+	else
+		rv = 0;
+	FREETMPS;
+	LEAVE;
+	PUTBACK;
+	DEBUGf("removexattr end: %i\n",sp-PL_stack_base);
+	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,
-			_PLfuse_statfs
+getattr:		_PLfuse_getattr,
+readlink:		_PLfuse_readlink,
+getdir:			_PLfuse_getdir,
+mknod:			_PLfuse_mknod,
+mkdir:			_PLfuse_mkdir,
+unlink:			_PLfuse_unlink,
+rmdir:			_PLfuse_rmdir,
+symlink:		_PLfuse_symlink,
+rename:			_PLfuse_rename,
+link:			_PLfuse_link,
+chmod:			_PLfuse_chmod,
+chown:			_PLfuse_chown,
+truncate:		_PLfuse_truncate,
+utime:			_PLfuse_utime,
+open:			_PLfuse_open,
+read:			_PLfuse_read,
+write:			_PLfuse_write,
+statfs:			_PLfuse_statfs,
+flush:			_PLfuse_flush,
+release:		_PLfuse_release,
+fsync:			_PLfuse_fsync,
+setxattr:		_PLfuse_setxattr,
+getxattr:		_PLfuse_getxattr,
+listxattr:		_PLfuse_listxattr,
+removexattr:		_PLfuse_removexattr,
 };
 
 MODULE = Fuse		PACKAGE = Fuse
@@ -537,13 +774,13 @@ PROTOTYPES: DISABLE
 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,NULL};
+	struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 	int i, fd, varnum = 0, debug, have_mnt;
 	char *mountpoint;
 	STRLEN n_a;
 	STRLEN l;
 	INIT:
-	if(items != 20) {
+	if(items != 27) {
 		fprintf(stderr,"Perl<->C inconsistency or internal error\n");
 		XSRETURN_UNDEF;
 	}
@@ -551,7 +788,7 @@ perl_fuse_main(...)
 	debug = SvIV(ST(0));
 	mountpoint = SvPV_nolen(ST(1));
 	/* FIXME: reevaluate multithreading support when perl6 arrives */
-	for(i=0;i<18;i++) {
+	for(i=0;i<N_CALLBACKS;i++) {
 		SV *var = ST(i+2);
 		if((var != &PL_sv_undef) && SvROK(var)) {
 			if(SvTYPE(SvRV(var)) == SVt_PVCV) {
Index: META.yml
===================================================================
RCS file: /cvsroot/fuse/perl/META.yml,v
retrieving revision 1.1
diff -p -u -r1.1 META.yml
--- META.yml	22 Mar 2005 11:21:12 -0000	1.1
+++ META.yml	3 Apr 2005 15:22:30 -0000
@@ -1,7 +1,7 @@
 # http://module-build.sourceforge.net/META-spec.html
 #XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
 name:         Fuse
-version:      0.05
+version:      0.06
 version_from: Fuse.pm
 installdirs:  site
 requires:
Index: README
===================================================================
RCS file: /cvsroot/fuse/perl/README,v
retrieving revision 1.3
diff -p -u -r1.3 README
--- README	20 Mar 2005 01:41:27 -0000	1.3
+++ README	3 Apr 2005 15:22:30 -0000
@@ -67,4 +67,5 @@ While most things work, I do still have 
 * need to sort out cleaner mount semantics for the test framework
 * figure out how to un-linuxcentrify the statfs tests
 * test everything on other architectures and OS's
+* Switch from the FUSE 2.1 compatibility API to the 2.2 API?
 
Index: examples/loopback.pl
===================================================================
RCS file: /cvsroot/fuse/perl/examples/loopback.pl,v
retrieving revision 1.2
diff -p -u -r1.2 loopback.pl
--- examples/loopback.pl	20 Mar 2005 01:36:05 -0000	1.2
+++ examples/loopback.pl	3 Apr 2005 15:22:30 -0000
@@ -109,6 +109,26 @@ sub x_mknod {
 	return -$!;
 }
 
+sub x_setxattr
+{
+    my ($file, $name, $value) = @_;
+    $file = fixup($file);
+    $! = 0;
+#    syscall(&SYS_setxattr,$file,);
+}
+
+sub x_getxattr
+{
+}
+
+sub x_listxattr
+{
+}
+
+sub x_removexattr
+{
+}
+
 # kludge
 sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
 my ($mountpoint) = "";
