# 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()
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=>"");
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
-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>
#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;
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
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;
}
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) {