+++ /dev/null
--Fuse.bs Fuse.c Makefile blib pm_to_blib
+++ /dev/null
--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
--
--0.03 Wed Dec 5 02:17:52 2001
-- - changed getattr() to smell like perl's stat()
-- - fleshed out the documentation a bit
+++ /dev/null
--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,0);
-- my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink
-- rename link chmod chown truncate utime open read write statfs);
-- my ($tmp) = 0;
-- my (%mapping) = map { $_ => $tmp++ } (@names);
-- my (%otherargs) = (debug=>0, 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($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);".
--
--Every constant you need (file types, open() flags, error values,
--etc) can be imported either from POSIX or from Fcntl, often both.
--See their respective documentations, for more information.
--
--=head2 EXPORT
--
--None by default.
--
--=head2 EXPORTABLE CONSTANTS
--
--None.
--
--=head2 FUNCTIONS
--
--=head3 Fuse::main
--
--Takes arguments in the form of hash key=>value pairs. There are
--many valid keys. Most of them correspond with names of callback
--functions, as described in section 'FUNCTIONS YOUR FILESYSTEM MAY IMPLEMENT'.
--A few special keys also exist:
--
--
--debug => boolean
--
--=over 1
--
--This turns FUSE call tracing on and off. Default is 0 (which means off).
--
--=back
--
--mountpoint => string
--
--=over 1
--
--The point at which to mount this filesystem. There is no default, you must
--specify this. An example would be '/mnt'.
--
--=back
--
--unthreaded => boolean
--
--=over 1
--
--This turns FUSE multithreading off and on. NOTE: This perlmodule does not
--currently work properly in multithreaded mode! The author is unfortunately
--not familiar enough with perl-threads internals, and according to the
--documentation available at time of writing (2002-03-08), those internals are
--subject to changing anyway. Note that singlethreaded mode also means that
--you will not have to worry about reentrancy, though you will have to worry
--about recursive lookups (since the kernel holds a global lock on your
--filesystem and blocks waiting for one callback to complete before calling
--another).
--
--I hope to add full multithreading functionality later, but for now, I
--recommend you leave this option at the default, 1 (which means
--unthreaded, no threads will be used and no reentrancy is needed).
--
--=back
--
--=head2 FUNCTIONS YOUR FILESYSTEM MAY IMPLEMENT
--
--=head3 getattr
--
--Arguments: filename.
--Returns a list, very similar to the 'stat' function (see
--perlfunc). On error, simply return a single numeric scalar
--value (e.g. "return -ENOENT();").
--
--FIXME: the "ino" field is currently ignored. I tried setting it to 0
--in an example script, which consistently caused segfaults.
--
--Fields (the following was stolen from perlfunc(1) with apologies):
--
--($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
-- $atime,$mtime,$ctime,$blksize,$blocks)
-- = getattr($filename);
--
--Here are the meaning of the fields:
--
-- 0 dev device number of filesystem
-- 1 ino inode number
-- 2 mode file mode (type and permissions)
-- 3 nlink number of (hard) links to the file
-- 4 uid numeric user ID of file's owner
-- 5 gid numeric group ID of file's owner
-- 6 rdev the device identifier (special files only)
-- 7 size total size of file, in bytes
-- 8 atime last access time in seconds since the epoch
-- 9 mtime last modify time in seconds since the epoch
--10 ctime inode change time (NOT creation time!) in seconds
-- since the epoch
--11 blksize preferred block size for file system I/O
--12 blocks actual number of blocks allocated
--
--(The epoch was at 00:00 January 1, 1970 GMT.)
--
--=head3 readlink
--
--Arguments: link pathname.
--Returns a scalar: either a numeric constant, or a text string.
--
--This is called when dereferencing symbolic links, to learn the target.
--
--example rv: return "/proc/self/fd/stdin";
--
--=head3 getdir
--
--Arguments: Containing directory name.
--Returns a list: 0 or more text strings (the filenames), followed by a numeric errno (usually 0).
--
--This is used to obtain directory listings. Its opendir(), readdir(), filldir() and closedir() all in one call.
--
--example rv: return ('.', 'a', 'b', 0);
--
--=head3 mknod
--
--Arguments: Filename, numeric modes, numeric device
--Returns an errno (0 upon success, as usual).
--
--This function is called for all non-directory, non-symlink nodes,
--not just devices.
--
--=head3 mkdir
--
--Arguments: New directory pathname, numeric modes.
--Returns an errno.
--
--Called to create a directory.
--
--=head3 unlink
--
--Arguments: Filename.
--Returns an errno.
--
--Called to remove a file, device, or symlink.
--
--=head3 rmdir
--
--Arguments: Pathname.
--Returns an errno.
--
--Called to remove a directory.
--
--=head3 symlink
--
--Arguments: Existing filename, symlink name.
--Returns an errno.
--
--Called to create a symbolic link.
--
--=head3 rename
--
--Arguments: old filename, new filename.
--Returns an errno.
--
--Called to rename a file, and/or move a file from one directory to another.
--
--=head3 link
--
--Arguments: Existing filename, hardlink name.
--Returns an errno.
--
--Called to create hard links.
--
--=head3 chmod
--
--Arguments: Pathname, numeric modes.
--Returns an errno.
--
--Called to change permissions on a file/directory/device/symlink.
--
--=head3 chown
--
--Arguments: Pathname, numeric uid, numeric gid.
--Returns an errno.
--
--Called to change ownership of a file/directory/device/symlink.
--
--=head3 truncate
--
--Arguments: Pathname, numeric offset.
--Returns an errno.
--
--Called to truncate a file, at the given offset.
--
--=head3 utime
--
--Arguments: Pathname, numeric actime, numeric modtime.
--Returns an errno.
--
--Called to change access/modification times for a file/directory/device/symlink.
--
--=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.
--
--No creation, or trunctation flags (O_CREAT, O_EXCL, O_TRUNC) will be passed to open().
--Your open() method needs only check if the operation is permitted for the given flags, and return 0 for success.
--
--=head3 read
--
--Arguments: Pathname, numeric requestedsize, numeric offset.
--Returns a numeric errno, or a string scalar with up to $requestedsize bytes of data.
--
--Called in an attempt to fetch a portion of the file.
--
--=head3 write
--
--Arguments: Pathname, scalar buffer, numeric offset. You can use length($buffer) to
--find the buffersize.
--Returns an errno.
--
--Called in an attempt to write (or overwrite) a portion of the file. Be prepared because $buffer could contain random binary data with NULLs and all sorts of other wonderful stuff.
--
--=head3 statfs
--
--Arguments: none
--Returns any of the following:
--
---ENOANO()
--
--or
--
--$namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize
--
--or
--
---ENOANO(), $namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize
--
--=head1 AUTHOR
--
--Mark Glines, E<lt>mark@glines.orgE<gt>
--
--=head1 SEE ALSO
--
--L<perl>, the FUSE documentation.
--
--=cut
+++ /dev/null
--#include "EXTERN.h"
--#include "perl.h"
--#include "XSUB.h"
--
--#include <fuse.h>
--
--#undef DEBUGf
--#if 0
--#define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,PL_stack_sp-PL_stack_base ,##a )
--#else
--#define DEBUGf(a...)
--#endif
--
--SV *_PLfuse_callbacks[18];
--
--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 != 13) {
-- if(rv > 1) {
-- fprintf(stderr,"inappropriate number of returned values from getattr\n");
-- rv = -ENOSYS;
-- } else if(rv)
-- rv = POPi;
-- else
-- rv = -ENOENT;
-- } else {
-- result->st_blksize = POPi;
-- result->st_ctime = POPi;
-- result->st_mtime = POPi;
-- result->st_atime = POPi;
-- /* What the HELL? Perl says the blockcount is the last argument.
-- * Everything else says the blockcount is the last argument. So why
-- * was it folded into the middle of the list? */
-- result->st_blocks = POPi;
-- result->st_size = POPi;
-- result->st_rdev = POPi;
-- result->st_gid = POPi;
-- result->st_uid = POPi;
-- result->st_nlink = POPi;
-- result->st_mode = POPi;
-- /*result->st_ino =*/ POPi;
-- result->st_dev = POPi;
-- rv = 0;
-- }
-- FREETMPS;
-- LEAVE;
-- PUTBACK;
-- return rv;
--}
--
--int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
-- int rv;
-- char *rvstr;
-- dSP;
-- I32 ax;
-- if(buflen < 1)
-- return EINVAL;
-- 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 {
-- SV *mysv = POPs;
-- if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
-- rv = SvIV(mysv);
-- else {
-- strncpy(buf,SvPV_nolen(mysv),buflen);
-- rv = 0;
-- }
-- }
-- FREETMPS;
-- LEAVE;
-- buf[buflen-1] = 0;
-- PUTBACK;
-- return rv;
--}
--
--int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
-- int prv, rv;
-- dSP;
-- ENTER;
-- SAVETMPS;
-- PUSHMARK(SP);
-- XPUSHs(sv_2mortal(newSVpv(file,0)));
-- PUTBACK;
-- prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
-- SPAGAIN;
-- if(prv) {
-- rv = POPi;
-- while(--prv)
-- dirfil(dirh,POPp,0);
-- } else {
-- fprintf(stderr,"getdir() handler returned nothing!\n");
-- rv = -ENOSYS;
-- }
-- FREETMPS;
-- LEAVE;
-- PUTBACK;
-- 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;
-- PUTBACK;
-- return rv;
--}
--
--int _PLfuse_mkdir (const char *file, mode_t mode) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("mkdir begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("mkdir end: %i %i\n",sp-PL_stack_base,rv);
-- return rv;
--}
--
--
--int _PLfuse_unlink (const char *file) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("unlink begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("unlink end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_rmdir (const char *file) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("rmdir begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("rmdir end: %i %i\n",sp-PL_stack_base,rv);
-- return rv;
--}
--
--int _PLfuse_symlink (const char *file, const char *new) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("symlink begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("symlink end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_rename (const char *file, const char *new) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("rename begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("rename end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_link (const char *file, const char *new) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("link begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("link end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_chmod (const char *file, mode_t mode) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("chmod begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("chmod end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("chown begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("chown end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_truncate (const char *file, off_t off) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("truncate begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("truncate end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_utime (const char *file, struct utimbuf *uti) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("utime begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("utime end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_open (const char *file, int flags) {
-- int rv;
-- SV *rvsv;
-- char *rvstr;
-- dSP;
-- DEBUGf("open 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[14],G_SCALAR);
-- SPAGAIN;
-- if(rv)
-- rv = POPi;
-- else
-- rv = 0;
-- FREETMPS;
-- LEAVE;
-- PUTBACK;
-- DEBUGf("open end: %i %i\n",sp-PL_stack_base,rv);
-- return rv;
--}
--
--int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) {
-- int rv;
-- char *rvstr;
-- dSP;
-- DEBUGf("read begin: %i\n",sp-PL_stack_base);
-- 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 = POPs;
-- if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
-- rv = SvIV(mysv);
-- else {
-- if(SvPOK(mysv)) {
-- rv = SvCUR(mysv);
-- } else {
-- rv = 0;
-- }
-- if(rv > buflen)
-- croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
-- if(rv)
-- memcpy(buf,SvPV_nolen(mysv),rv);
-- }
-- }
-- FREETMPS;
-- LEAVE;
-- PUTBACK;
-- DEBUGf("read end: %i %i\n",sp-PL_stack_base,rv);
-- return rv;
--}
--
--int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) {
-- int rv;
-- char *rvstr;
-- dSP;
-- DEBUGf("write begin: %i\n",sp-PL_stack_base);
-- 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;
-- PUTBACK;
-- DEBUGf("write end: %i\n",sp-PL_stack_base);
-- return rv;
--}
--
--int _PLfuse_statfs (const char *file, struct statfs *st) {
-- int rv;
-- char *rvstr;
-- dSP;
-- DEBUGf("statfs begin: %i\n",sp-PL_stack_base);
-- ENTER;
-- SAVETMPS;
-- PUSHMARK(SP);
-- PUTBACK;
-- rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
-- SPAGAIN;
-- if(rv > 5) {
-- st->f_bsize = POPi;
-- st->f_bfree = POPi;
-- st->f_blocks = POPi;
-- st->f_ffree = POPi;
-- st->f_files = POPi;
-- st->f_namelen = POPi;
-- if(rv > 6)
-- rv = POPi;
-- else
-- rv = 0;
-- } else
-- if(rv > 1)
-- croak("inappropriate number of returned values from statfs");
-- else
-- if(rv)
-- rv = POPi;
-- else
-- rv = -ENOSYS;
-- FREETMPS;
-- LEAVE;
-- PUTBACK;
-- DEBUGf("statfs 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
--};
--
--MODULE = Fuse PACKAGE = Fuse
--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};
-- int i, fd, varnum = 0, debug, have_mnt;
-- char *mountpoint;
-- STRLEN n_a;
-- STRLEN l;
-- INIT:
-- if(items != 20) {
-- fprintf(stderr,"Perl<->C inconsistency or internal error\n");
-- XSRETURN_UNDEF;
-- }
-- CODE:
-- debug = SvIV(ST(0));
-- mountpoint = SvPV_nolen(ST(1));
-- /* FIXME: reevaluate multithreading support when perl6 arrives */
-- for(i=0;i<18;i++) {
-- SV *var = ST(i+2);
-- 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!");
-- }
-- }
-- /* FIXME: need to pass fusermount arguments */
-- fd = fuse_mount(mountpoint,NULL);
-- if(fd < 0)
-- croak("could not mount fuse filesystem!");
-- fuse_loop(fuse_new(fd,debug ? "debug" : NULL,&fops));
+++ /dev/null
--Changes
--Fuse.pm
--Fuse.xs
--Makefile.PL
--MANIFEST
--README
--test.pl
+++ /dev/null
--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/.libs/libfuse.a -lpthread', # link all the C files too
--);
+++ /dev/null
--Fuse version 0.03
--=================
--
--This is a test release. It seems to work quite well. In fact, I can't
--find any problems with it whatsoever. If you do, I want to know.
--
--
--INSTALLATION
--
--To install this module type the standard commands as root:
--
-- perl Makefile.PL
-- make
-- make test
-- 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.
--
--
--EXAMPLES
--
--There are a few example scripts. You can find them in the examples/
--subdirectory. These are:
--
--* example.pl, a simple "Hello world" type of script
--
--* loopback.pl, a filesystem loopback-device. like fusexmp from
-- the main FUSE dist, it simply recurses file operations
-- into the real filesystem. Unlike fusexmp, it only
-- re-shares files under the /tmp/test directory.
--
--* rmount.pl, an NFS-workalike which tunnels through SSH. It requires
-- an account on some ssh server (obviously), with public-key
-- authentication enabled. (if you have to type in a password,
-- you don't have this. man ssh_keygen.). Copy rmount_remote.pl
-- to your home directory on the remote machine, and create a
-- subdir somewhere, and then run it like:
-- ./rmount.pl host /remote/dir /local/dir
--
--* rmount_remote.pl, a ripoff of loopback.pl meant to be used as a backend
-- for rmount.pl.
--
--
--BUGS
--
--I've begun to build a formal testing framework. Currently it can mount
--and unmount loopback.pl, and all of the base-level functions have test
--scripts. These need to be fleshed out as problems are noticed.
--
--The current test framework seems to work well, but the underlying mount/
--unmount infrastructure is a crock. I am not pleased with that code.
--
--While most things work, I do still have a TODO list:
--* "du -sb" reports a couple orders of magnitude too large a size.
--* 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
--
+++ /dev/null
--#!/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 ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = (0,0,0,1,0,0,1,1024);
-- my ($atime, $ctime, $mtime);
-- $atime = $ctime = $mtime = $files{$file}{ctime};
-- # 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");
-- return ($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);
--}
--
--sub e_getdir {
-- # return as many text filenames as you like, followed by the retval.
-- print((scalar keys %files)."\n");
-- 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);
-- print("open called\n");
-- return -ENOENT() unless exists($files{$file});
-- return -EISDIR() unless exists($files{$file}{cont});
-- print("open ok\n");
-- 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);
--}
--
--sub e_statfs { return 255, 1, 1, 1, 1, 2 }
--
--# 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,
-- statfs=>\&e_statfs,
-- read=>\&e_read,
-- #debug=>1, threaded=>0
--);
+++ /dev/null
--#!/usr/bin/perl
--
--use strict;
--use Fuse;
--use IO::File;
--use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
--use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET);
--require 'syscall.ph'; # for SYS_mknod and SYS_lchown
--
--sub fixup { return "/tmp/fusetest" . shift }
--
--sub x_getattr {
-- my ($file) = fixup(shift);
-- my (@list) = lstat($file);
-- return -$! unless @list;
-- return @list;
--}
--
--sub x_getdir {
-- my ($dirname) = fixup(shift);
-- unless(opendir(DIRHANDLE,$dirname)) {
-- return -ENOENT();
-- }
-- my (@files) = readdir(DIRHANDLE);
-- closedir(DIRHANDLE);
-- return (@files, 0);
--}
--
--sub x_open {
-- my ($file) = fixup(shift);
-- my ($mode) = shift;
-- return -$! unless sysopen(FILE,$file,$mode);
-- close(FILE);
-- return 0;
--}
--
--sub x_read {
-- my ($file,$bufsize,$off) = @_;
-- my ($rv) = -ENOSYS();
-- my ($handle) = new IO::File;
-- return -ENOENT() unless -e ($file = fixup($file));
-- my ($fsize) = -s $file;
-- return -ENOSYS() unless open($handle,$file);
-- if(seek($handle,$off,SEEK_SET)) {
-- read($handle,$rv,$bufsize);
-- }
-- return $rv;
--}
--
--sub x_write {
-- my ($file,$buf,$off) = @_;
-- my ($rv);
-- return -ENOENT() unless -e ($file = fixup($file));
-- my ($fsize) = -s $file;
-- return -ENOSYS() unless open(FILE,'+<',$file);
-- if($rv = seek(FILE,$off,SEEK_SET)) {
-- $rv = print(FILE $buf);
-- }
-- $rv = -ENOSYS() unless $rv;
-- close(FILE);
-- return length($buf);
--}
--
--sub err { return (-shift || -$!) }
--
--sub x_readlink { return readlink(fixup(shift) ); }
--sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!; }
--sub x_rmdir { return err(rmdir(fixup(shift)) ); }
--
--sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
--
--sub x_rename {
-- my ($old) = fixup(shift);
-- my ($new) = fixup(shift);
-- my ($err) = rename($old,$new) ? 0 : -ENOENT();
-- return $err;
--}
--sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
--sub x_chown {
-- my ($fn) = fixup(shift);
-- print "nonexistent $fn\n" unless -e $fn;
-- my ($uid,$gid) = @_;
-- # perl's chown() does not chown symlinks, it chowns the symlink's
-- # target. it fails when the link's target doesn't exist, because
-- # the stat64() syscall fails.
-- # this causes error messages when unpacking symlinks in tarballs.
-- my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-- return $err;
--}
--sub x_chmod {
-- my ($fn) = fixup(shift);
-- my ($mode) = shift;
-- my ($err) = chmod($mode,$fn) ? 0 : -$!;
-- return $err;
--}
--sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
--sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
--
--sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
--sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
--
--sub x_mknod {
-- # since this is called for ALL files, not just devices, I'll do some checks
-- # and possibly run the real mknod command.
-- my ($file, $modes, $dev) = @_;
-- $file = fixup($file);
-- $! = 0;
-- syscall(&SYS_mknod,$file,$modes,$dev);
-- return -$!;
--}
--
--# kludge
--sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
--my ($mountpoint) = "";
--$mountpoint = shift(@ARGV) if @ARGV;
--Fuse::main(
-- mountpoint=>$mountpoint,
-- getattr=>\&x_getattr,
-- readlink=>\&x_readlink,
-- getdir=>\&x_getdir,
-- mknod=>\&x_mknod,
-- mkdir=>\&x_mkdir,
-- unlink=>\&x_unlink,
-- rmdir=>\&x_rmdir,
-- symlink=>\&x_symlink,
-- rename=>\&x_rename,
-- link=>\&x_link,
-- chmod=>\&x_chmod,
-- chown=>\&x_chown,
-- truncate=>\&x_truncate,
-- utime=>\&x_utime,
-- open=>\&x_open,
-- read=>\&x_read,
-- write=>\&x_write,
-- statfs=>\&x_statfs,
--);
+++ /dev/null
--#!/usr/bin/perl
--
--use strict;
--use Net::SSH 'sshopen2';
--use IPC::Open2;
--use Fuse;
--use Data::Dumper;
--
--my ($host, $dir, $mount) = @ARGV;
--if(!defined($mount)) {
-- $mount = $dir;
-- if($host =~ /^(.*):(.*)$/) {
-- ($host,$dir) = ($1,$2);
-- } else {
-- die "usage: $0 user\@host remotedir mountpoint\n".
-- "or : $0 user\@host:remotedir mountpoint\n";
-- }
--}
--
--`umount $mount` unless -d $mount;
--die "mountpoint $mount isn't a directory!\n" unless -d $mount;
--
--my (%args) = (mountpoint => $mount);
--
--map { my ($str) = $_; $args{$str} = sub { netlink($str,@_) } }
-- qw(getattr getdir open read write readlink unlink rmdir
-- symlink rename link chown chmod truncate utime mkdir
-- rmdir mknod statfs);
--
--sub connect_remote {
-- sshopen2($host, *READER, *WRITER, "./rmount_remote.pl $dir")
-- or die "ssh: $!\n";
-- select WRITER;
-- $| = 1;
-- select STDOUT;
--}
--
--$SIG{CHLD} = sub {
-- use POSIX ":sys_wait_h";
-- my $kid;
-- do {
-- $kid = waitpid(-1,WNOHANG);
-- } until $kid < 1;
--};
--
--connect_remote;
--
--sub netlink {
-- my ($str) = Dumper(\@_)."\n";
-- $str = sprintf("%08i\n%s",length($str),$str);
-- while(1) { # retry as necessary
-- my ($sig) = $SIG{ALRM};
-- my ($VAR1);
-- $VAR1 = undef;
-- eval {
-- $SIG{ALRM} = sub { die "timeout\n" };
-- alarm 10;
-- print WRITER $str;
-- my ($len, $data);
-- if(read(READER,$len,9) == 9) {
-- read(READER,$data,$len-length($data),length($data))
-- while(length($data) < $len);
-- eval $data;
-- }
-- };
-- alarm 0;
-- $SIG{ALRM} = $sig;
-- if(defined $VAR1) {
-- return wantarray ? @{$VAR1} : $$VAR1[0];
-- }
-- print STDERR "failed to send command; reconnecting ssh\n";
-- close(READER);
-- close(WRITER);
-- connect_remote();
-- }
--}
--
--Fuse::main(%args);
--
--netlink("bye");
--close(READER);
--close(WRITER);
+++ /dev/null
--#!/usr/bin/perl
--
--use strict;
--use IO::File;
--use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
--use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET);
--use Data::Dumper;
--require 'syscall.ph'; # for SYS_mknod and SYS_lchown
--
--my ($rootdir) = @ARGV;
--
--# strip leading and trailing slashes
--$rootdir = $1 if($rootdir =~ /^\/?(.*)\/?$/);
--
--sub fixup { return "/$rootdir" . shift }
--
--sub x_getattr {
-- my ($file) = fixup(shift);
-- my (@list) = lstat($file);
-- return -$! unless @list;
-- return @list;
--}
--
--sub x_getdir {
-- my ($dirname) = fixup(shift);
-- unless(opendir(DIRHANDLE,$dirname)) {
-- return -ENOENT();
-- }
-- my (@files) = readdir(DIRHANDLE);
-- closedir(DIRHANDLE);
-- return (@files, 0);
--}
--
--sub x_open {
-- my ($file) = fixup(shift);
-- my ($mode) = shift;
-- return -$! unless sysopen(FILE,$file,$mode);
-- close(FILE);
-- return 0;
--}
--
--sub x_read {
-- my ($file,$bufsize,$off) = @_;
-- my ($rv) = -ENOSYS();
-- my ($handle) = new IO::File;
-- return -ENOENT() unless -e ($file = fixup($file));
-- my ($fsize) = -s $file;
-- return -ENOSYS() unless open($handle,$file);
-- if(seek($handle,$off,SEEK_SET)) {
-- read($handle,$rv,$bufsize);
-- }
-- return $rv;
--}
--
--sub x_write {
-- my ($file,$buf,$off) = @_;
-- my ($rv);
-- return -ENOENT() unless -e ($file = fixup($file));
-- my ($fsize) = -s $file;
-- return -ENOSYS() unless open(FILE,'+<',$file);
-- if($rv = seek(FILE,$off,SEEK_SET)) {
-- $rv = print(FILE $buf);
-- }
-- $rv = -ENOSYS() unless $rv;
-- close(FILE);
-- return length($buf);
--}
--
--sub err { return (-shift || -$!) }
--
--sub x_readlink { return readlink(fixup(shift) ); }
--sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!; }
--sub x_rmdir { return err(rmdir(fixup(shift)) ); }
--
--sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
--
--sub x_rename {
-- my ($old) = fixup(shift);
-- my ($new) = fixup(shift);
-- my ($err) = rename($old,$new) ? 0 : -ENOENT();
-- return $err;
--}
--sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
--sub x_chown {
-- my ($fn) = fixup(shift);
-- print "nonexistent $fn\n" unless -e $fn;
-- my ($uid,$gid) = @_;
-- # perl's chown() does not chown symlinks, it chowns the symlink's
-- # target. it fails when the link's target doesn't exist, because
-- # the stat64() syscall fails.
-- # this causes error messages when unpacking symlinks in tarballs.
-- my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-- return $err;
--}
--sub x_chmod {
-- my ($fn) = fixup(shift);
-- my ($mode) = shift;
-- my ($err) = chmod($mode,$fn) ? 0 : -$!;
-- return $err;
--}
--sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
--sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
--
--sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
--sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
--
--sub x_mknod {
-- # since this is called for ALL files, not just devices, I'll do some checks
-- # and possibly run the real mknod command.
-- my ($file, $modes, $dev) = @_;
-- $file = fixup($file);
-- $! = 0;
-- syscall(&SYS_mknod,$file,$modes,$dev);
-- return -$!;
--}
--
--# kludge
--sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
--
--$| = 1;
--my ($len);
--while(read(STDIN,$len,9) == 9) {
-- chomp $len;
-- my ($data,$VAR1,@args);
-- eval {
-- $SIG{ALRM} = sub { die "timeout\n"};
-- $data = "";
-- alarm 5;
-- read(STDIN,$data,$len-length($data),length($data))
-- while(length($data) < $len);
-- alarm 0;
-- };
-- die $@ if $@;
-- eval $data;
-- @args = @{$VAR1};
-- my $cmd = shift(@args);
-- exit 0 if $cmd eq "bye";
-- die "cannot find command $cmd\n" unless exists($main::{"x_$cmd"});
-- @args = $main::{"x_$cmd"}(@args);
-- $cmd = Dumper(\@args)."\n";
-- $cmd = sprintf("%08i\n%s",length($cmd),$cmd);
-- print $cmd;
--}
+++ /dev/null
--#!/usr/bin/perl
--BEGIN { $ENV{HARNESS_IGNORE_EXITCODE} = 1; }
--
--use Test::Harness qw(&runtests $verbose);
--$verbose=0;
--die "cannot find test directory!" unless -d "test";
--my (@files) = <test/*.t>;
--runtests("test/s/mount.t",sort(@files),"test/s/umount.t");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 4;
--chdir($_point);
--system("echo frog >file");
--ok(chmod(0644,"file"),"set unexecutable");
--ok(!-x "file","unexecutable");
--ok(chmod(0755,"file"),"set executable");
--ok(-x "file","executable");
--unlink("file");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 4;
--my (@stat);
--chdir($_point);
--system("echo frog >file");
--ok(chown(0,0,"file"),"set 0,0");
--@stat = stat("file");
--ok($stat[4] == 0 && $stat[5] == 0,"0,0");
--ok(chown(1,1,"file"),"set 1,1");
--@stat = stat("file");
--ok($stat[4] == 1 && $stat[5] == 1,"1,1");
--unlink("file");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--use Data::Dumper;
--plan tests => 28;
--my ($a, $b) = ("$_real/wibble","$_point/wibble");
--`touch $b`;
--is(-A "$a", -A "$b", '-A'); # 1
--is(-B "$a", -B "$b", '-B'); # 2
--is(-C "$a", -C "$b", '-C'); # 3
--is(-M "$a", -M "$b", '-M'); # 4
--is(-O "$a", -O "$b", '-O'); # 5
--is(-R "$a", -R "$b", '-R'); # 6
--is(-S "$a", -S "$b", '-S'); # 7
--is(-T "$a", -T "$b", '-T'); # 8
--is(-W "$a", -W "$b", '-W'); # 9
--is(-X "$a", -X "$b", '-X'); # 10
--is(-b "$a", -b "$b", '-b'); # 11
--is(-c "$a", -c "$b", '-c'); # 12
--is(-d "$a", -d "$b", '-d'); # 13
--is(-e "$a", -e "$b", '-e'); # 14
--is(-f "$a", -f "$b", '-f'); # 15
--is(-g "$a", -g "$b", '-g'); # 16
--is(-k "$a", -k "$b", '-k'); # 17
--is(-l "$a", -l "$b", '-l'); # 18
--is(-o "$a", -o "$b", '-o'); # 19
--is(-p "$a", -p "$b", '-p'); # 20
--is(-r "$a", -r "$b", '-r'); # 21
--is(-s "$a", -s "$b", '-s'); # 22
--is(-t "$a", -t "$b", '-t'); # 23
--is(-u "$a", -u "$b", '-u'); # 24
--is(-w "$a", -w "$b", '-w'); # 25
--is(-x "$a", -x "$b", '-x'); # 26
--is(-z "$a", -z "$b", '-z'); # 27
--my (@astat, @bstat);
--@astat = stat("$a");
--@bstat = stat("$b");
--# dev and inode can legally change
--shift(@astat); shift(@astat);
--shift(@bstat); shift(@bstat);
--is(join(" ",@astat),join(" ",@bstat),"stat()");
--`rm -f $a`;
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--my (@names) = qw(abc def ghi jkl mno pqr stu jlk sfdaljk sdfakjlsdfa kjldsf kjl;sdf akjl;asdf klj;asdf lkjsdflkjsdfkjlsdfakjsdfakjlsadfkjl;asdfklj;asdfkjl;asdfklj;asdfkjl;asdfkjlasdflkj;sadf);
--@names = sort(@names);
--plan tests => 2 * scalar @names;
--chdir($_real);
--
--# create entries
--map { system("touch \"$_\"") } @names;
--
--# make sure they exist in real dir
--opendir(REAL,$_real);
--my (@ents) = readdir(REAL);
--closedir(REAL);
--@ents = sort(@ents);
--map {
-- shift(@ents) while($ents[0] eq '.' || $ents[0] eq '..');
-- is(shift(@ents),$_,"ent $_")
--} @names;
--
--# make sure they exist in fuse dir
--opendir(POINT,$_point);
--@ents = readdir(POINT);
--closedir(POINT);
--@ents = sort(@ents);
--map {
-- shift(@ents) while($ents[0] eq '.' || $ents[0] eq '..');
-- is(shift(@ents),$_,"ent $_")
--} @names;
--
--# remove them
--map { unlink } @names;
+++ /dev/null
--#!/usr/bin/perl
--package test::helper;
--use strict;
--use Exporter;
--our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
--@ISA = "Exporter";
--@EXPORT_OK = qw($_loop $_point $_pidfile $_real);
--our($_loop, $_point, $_pidfile, $_real) = ("examples/loopback.pl","/mnt","test/s/mounted.pid","/tmp/fusetest");
--if($0 !~ qr|s/u?mount\.t$|) {
-- my ($reject) = 1;
-- if(-f $_pidfile) {
-- unless(system("ps `cat $_pidfile` | grep \"$_loop $_point\" >/dev/null")>>8) {
-- if(`mount | grep "on $_point"`) {
-- $reject = 0;
-- } else {
-- system("kill `cat $_pidfile`");
-- }
-- }
-- }
-- $reject = 1 if (system("ls $_point >&/dev/null") >> 8);
-- die "not properly mounted\n" if $reject;
--}
--1;
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 8;
--chdir($_point);
--system("echo hippity >womble");
--ok(-f "womble","exists");
--ok(!-f "rabbit","target file doesn't exist");
--is(-s "womble",8,"right size");
--ok(link("womble","rabbit"),"link");
--ok(-f "womble","old file exists");
--ok(-f "rabbit","target file exists");
--is(-s "womble",8,"right size");
--is(-s "rabbit",8,"right size");
--unlink("womble");
--unlink("rabbit");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 3;
--chdir($_point);
--ok(mkdir("dir"),"mkdir");
--ok(-d "dir","dir exists");
--chdir($_real);
--ok(-d "dir","dir really exists");
--chdir($_point);
--rmdir("dir");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 24;
--my (@stat);
--chdir($_point);
--ok(!(system("touch reg" )>>8),"create normal file");
--ok(!(system("mknod chr c 2 3")>>8),"create chrdev");
--ok(!(system("mknod blk b 2 3")>>8),"create blkdev");
--ok(!(system("mknod fifo p" )>>8),"create fifo");
--chdir($_real);
--ok(-e "reg" ,"normal file exists");
--ok(-e "chr" ,"chrdev exists");
--ok(-e "blk" ,"blkdev exists");
--ok(-e "fifo","fifo exists");
--ok(-f "reg" ,"normal file is normal file");
--ok(-c "chr" ,"chrdev is chrdev");
--ok(-b "blk" ,"blkdev is blkdev");
--ok(-p "fifo","fifo is fifo");
--@stat = stat("chr");
--is($stat[6],3+(2<<8),"chrdev has right major,minor");
--@stat = stat("blk");
--is($stat[6],3+(2<<8),"blkdev has right major,minor");
--chdir($_point);
--ok(-e "reg" ,"normal file exists");
--ok(-e "chr" ,"chrdev exists");
--ok(-e "blk" ,"blkdev exists");
--ok(-e "fifo","fifo exists");
--ok(-f "reg" ,"normal file is normal file");
--ok(-c "chr" ,"chrdev is chrdev");
--ok(-b "blk" ,"blkdev is blkdev");
--ok(-p "fifo","fifo is fifo");
--@stat = stat("chr");
--is($stat[6],3+(2<<8),"chrdev has right major,minor");
--@stat = stat("blk");
--is($stat[6],3+(2<<8),"blkdev has right major,minor");
--map { unlink } qw(reg chr blk fifo);
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 1;
--chdir($_real);
--system("echo frog >file");
--chdir($_point);
--ok(open(FILE,"file"),"open");
--close(FILE);
--unlink("file");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 3;
--chdir($_real);
--system("echo frog >file");
--chdir($_point);
--ok(open(FILE,"file"),"open");
--my ($data) = <FILE>;
--close(FILE);
--is(length($data),5,"right amount read");
--is($data,"frog\n","right data read");
--unlink("file");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_point $_real);
--use Test::More;
--plan tests => 4;
--chdir($_real);
--ok(symlink("abc","def"),"OS supports symlinks");
--is(readlink("def"),"abc","OS supports symlinks");
--chdir($_point);
--ok(-l "def","symlink exists");
--is(readlink("def"),"abc","readlink");
--unlink("def");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 5;
--chdir($_point);
--system("echo hippity >frog");
--ok(-f "frog","exists");
--ok(!-f "toad","target file doesn't exist");
--ok(rename("frog","toad"),"rename");
--ok(!-f "frog","old file doesn't exist");
--ok(-f "toad","target file exists");
--unlink("toad");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 5;
--chdir($_real);
--ok(mkdir("dir"),"mkdir");
--ok(-d "dir","dir really exists");
--chdir($_point);
--ok(-d "dir","dir exists");
--rmdir("dir");
--ok(! -d "dir","dir removed");
--chdir($_real);
--ok(! -d "dir","dir really removed");
+++ /dev/null
--#!/usr/bin/perl -w
--use test::helper qw($_point $_loop $_real $_pidfile);
--use strict;
--use Test::More tests => 3;
--ok(!(scalar grep(/ on $_point /,`cat /proc/mounts`)),"already mounted");
--ok(-f $_loop,"loopback exists");
--
--if(!fork()) {
-- #close(STDIN);
-- close(STDOUT);
-- close(STDERR);
-- `echo $$ >test/s/mounted.pid`;
-- exec("perl $_loop $_point");
-- exit(1);
--}
--select(undef, undef, undef, 0.5);
--my ($success) = `cat /proc/mounts` =~ / $_point /;
--ok($success,"mount succeeded");
--system("rm -rf $_real");
--unless($success) {
-- kill('INT',`cat $_pidfile`);
-- unlink($_pidfile);
--} else {
-- mkdir($_real);
--}
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_point $_real $_pidfile);
--use strict;
--use Test::More tests => 1;
--system("umount $_point");
--ok(1,"unmount");
--system("rm -rf $_real $_pidfile");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--require 'syscall.ph'; # for SYS_statfs
--plan tests => 7;
--my ($statfs_data) = " " x 10;
--my ($tmp) = $_point;
--ok(!syscall(&SYS_statfs,$tmp,$statfs_data),"statfs");
--# FIXME: this is soooooo linux-centric. perhaps parse the output of /bin/df?
--my @list = unpack("LSSL8",$statfs_data);
--shift(@list);
--is(shift(@list),4096,"block size");
--shift(@list);
--is(shift(@list),1000000,"blocks");
--is(shift(@list),500000,"blocks free");
--shift(@list);
--is(shift(@list),1000000,"files");
--is(shift(@list),500000,"files free");
--shift(@list);
--shift(@list);
--is(shift(@list),255,"namelen");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_point $_real);
--use Test::More;
--plan tests => 6;
--chdir($_point);
--ok(symlink("abc","def"),"symlink created");
--ok(-l "def","symlink exists");
--is(readlink("def"),"abc","it worked");
--chdir($_real);
--ok(-l "def","symlink really exists");
--is(readlink("def"),"abc","really worked");
--unlink("def");
--
--# bug: doing a 'cp -a' on a directory which contains a symlink
--# reports an error
--mkdir("dira");
--system("cd dira; touch filea; ln -s filea fileb");
--is(system("cp -a dira dirb")>>8,0,"cp -a");
--system("rm -rf dira dirb");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 1;
--ok(1);
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 5;
--chdir($_point);
--system("echo hippity >womble");
--ok(-f "womble","exists");
--is(-s "womble",8,"right size");
--ok(truncate("womble",4),"truncate");
--ok(-f "womble","file exists");
--is(-s "womble",4,"right size");
--unlink("womble");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 4;
--chdir($_point);
--system("touch file");
--ok(-f "file","file exists");
--chdir($_real);
--ok(-f "file","file really exists");
--chdir($_point);
--unlink("file");
--ok(! -f "file","file unlinked");
--chdir($_real);
--ok(! -f "file","file really unlinked");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 3;
--my (@stat);
--chdir($_real);
--system("echo frog >file");
--chdir($_point);
--ok(utime(1,2,"file"),"set utime");
--@stat = stat("file");
--is($stat[8],1,"atime");
--is($stat[9],2,"mtime");
--unlink("file");
+++ /dev/null
--#!/usr/bin/perl
--use test::helper qw($_real $_point);
--use Test::More;
--plan tests => 15;
--my ($data);
--chdir($_point);
--undef $/; # slurp it all
--# create file
--system("echo frogbing >writefile");
--
--# fetch contents of file
--ok(open(FILE,"writefile"),"open");
--$data = <FILE>;
--close(FILE);
--is(length($data),9,"right amount read");
--is($data,"frogbing\n","right data read");
--
--# overwrite part
--ok(open(FILE,'+<',"writefile"),"open");
--ok(seek(FILE,2,0),"seek");
--ok(print(FILE "ib"),"print");
--close(FILE);
--
--# fetch contents of file
--ok(open(FILE,"writefile"),"open");
--$data = <FILE>;
--close(FILE);
--is(length($data),9,"right amount read");
--is($data,"fribbing\n","right data read");
--
--# overwrite part, append some
--ok(open(FILE,'+<',"writefile"),"open");
--ok(seek(FILE,7,0),"seek");
--ok(print(FILE "gle"),"print");
--close(FILE);
--
--# fetch contents of file
--ok(open(FILE,"writefile"),"open");
--$data = <FILE>;
--close(FILE);
--is(length($data),10,"right amount read");
--is($data,"fribbingle","right data read");
--
--# kill file
--unlink("writefile");
+++ /dev/null
--2004-09-27 Miklos Szeredi <miklos@szeredi.hu>
--
-- * Applied patch by Steven James. The Python binding in the CVS
-- version fell out of date and wouldn't compile. Fixed and added
-- FuseGetContext call.
--
+++ /dev/null
--The best way to install this python FUSE module is:
-- 1. make sure the rest of FUSE (incl libfuse.a) has built successfully
-- 2. type 'python setup.py build'
-- 3. if all has gone ok, become root and type 'python setup.py install'
--
--That way, the FUSE python modules will be built against the correct version
--of python and installed in your system-wide python directory. This will allow
--your filesystem script to find them, no matter where it's residing.
+++ /dev/null
--#@+leo-ver=4
--#@+node:@file Makefile
--# Makefile now uses distutils
--
--_fusemodule.so: _fusemodule.c
-- #gcc -g3 -I/usr/include/python2.1 _fusemodule.c -Wl,-shared -o _fusemodule.so -Wimplicit -lfuse && python -c 'import _fuse'
-- python setup.py build_ext --inplace
--
--install: _fusemodule.so
-- python setup.py install
--
--clean:
-- rm -rf _fusemodule.so *.pyc *.pyo *~ build
--#@-node:@file Makefile
--#@-leo
+++ /dev/null
--#@+leo-ver=4
--#@+node:@file README
--#@@language
--
--Refer to the INSTALL file for build/install instructions
--
--General Information
--===================
--
--This is a Python[1] interface to FUSE[2].
--
--FUSE (Filesystem in USErspace) is a simple interface for userspace
--programs to export a virtual filesystem to the linux kernel. FUSE
--also aims to provide a secure method for non privileged users to
--create and mount their own filesystem implementations.
--
--When run from the commandline, "fuse.py" simply reexports the root
--filesystem within the mount point as example/fusexmp does in the main
--FUSE distribution. It also offers a class, fuse.Fuse, which can be
--subclassed to create a filesystem. fuse.Xmp is the example filesystem
--implementation.
--
--In your subclass of fuse, add attributes with the expected names
--("getattr", "readlink", etc) and call signatures (refer to fuse.Xmp)
--then call main(). Make it runnable as a #! script, and mount with
-- fusermount <mount point> <script name>
--for some reason,
-- fusermount <mount point> python <script name>
--does not seem to work. (why?)
--
--Update
--======
--
--Updated 13-Dec-2003 by David McNab <david@rebirthing.co.nz>
--
-- - changed Makefile to use Pyton distutils
-- - added setup.py for distutils
--
-- - added 'code.leo' file for convenience of those who use the Leo
-- code editor (leo.sf.net)
--
-- - added support for 'statfs' and 'fsync' methods (refer xmp.py)
--
--Updated Dec 2003 by David McNab <david@rebirthing.co.nz>:
--
-- - added support for 'release' events (ie when file gets closed)
-- - added __init__ to base class, which picks off parameters and
-- stores them as instance attributes:
-- - self.mountpoint - the mountpoint as given in the mount command
-- - self.optlist - unnamed options (eg 'rw', 'exec' etc)
-- - self.optdict - named options (eg, '-o arg1=val1,arg2=val2...' from mount cmd)
-- - fixed incompatibility issues with recent pythons (original was broken
-- under python2.3)
--
--Limitations
--===========
--
--This is minimally tested, though I think I have exercised each function.
--There's no documentation, docstrings, or tests.
--
--Python's lstat() does not return some fields which must be filled in
--(st_blksize, st_blocks, st_ino), and _fusemodule assumes that the return
--value from the lstat() method is identical to Python's lstat(). This
--limitation should be lifted, and some standard order chosen for these
--three values. For now, though, default values are chosen and du returns a
--number similar to the "real" one.
--
--The Python Global Interpreter Lock is not handled, so using
--fuse.MULTITHREAD will not work. Modifying the PROLOGUE and EPILOGUE
--functions may take care of this. For now, just run without
--fuse.MULTITHREAD in flags.
--
--Author
--======
--
--I'm Jeff Epler <jepler@unpythonic.dhs.org>. I've been dabbling in
--Python for nearly 7 years now, and interested (despite the lack of a
--real practical use) in userspace filesystems ever since I couldn't get
--userfs to compile way back in '93 or so. FUSE is cool, but i'm still
--not sure what it's good for in practical terms.
--
--I don't know how high a level of interest I'll maintain in this project,
--so if you want to do something with it feel free to do so. Like FUSE,
--this software is distributed under the terms of the GNU General Public
--License, Version 2. Future versions, if any, will be available at [3].
--
--
--[1] http://www.python.org
--[2] http://sourceforge.net/projects/avf/
--[3] http://unpythonic.dhs.org/~jepler/fuse/
--#@-node:@file README
--#@-leo
+++ /dev/null
--//@+leo-ver=4
--//@+node:@file _fusemodule.c
--//@@language c
--/*
-- Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--
-- This program can be distributed under the terms of the GNU GPL.
-- See the file COPYING.
--
-- Updated for libfuse API changes
-- 2004 Steven James <pyro@linuxlabs.com> and
-- Linux Labs International, Inc. http://www.linuxlabs.com
--
--
--*/
--
--//@+others
--//@+node:includes
--#include <Python.h>
--#include "fuse.h"
--#include <time.h>
--//@-node:includes
--//@+node:globals
--
--static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL,
-- *mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL,
-- *symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL,
-- *chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL,
-- *open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL,
-- *statfs_cb=NULL, *fsync_cb=NULL
-- ;
--
--static int debuglevel=0;
--
--//@-node:globals
--//@+node:PROLOGUE
--#define PROLOGUE \
--int ret = -EINVAL; \
--if (!v) { PyErr_Print(); goto OUT; } \
--if(v == Py_None) { ret = 0; goto OUT_DECREF; } \
--if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; }
--
--//@-node:PROLOGUE
--//@+node:EPILOGUE
--#define EPILOGUE \
--OUT_DECREF: \
-- Py_DECREF(v); \
--OUT: \
-- return ret;
--//@-node:EPILOGUE
--//@+node:getattr_func
--
--/*
-- * Local Variables:
-- * indent-tabs-mode: t
-- * c-basic-offset: 8
-- * End:
-- * Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons.
-- * Namely, replacing PyTuple_* with PySequence_*, and checking numerical values
-- * with both PyInt_Check and PyLong_Check.
-- */
--
--static int getattr_func(const char *path, struct stat *st)
--{
--int i;
--PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
--PROLOGUE
--
--if(!PySequence_Check(v)) { goto OUT_DECREF; }
--if(PySequence_Size(v) < 10) { goto OUT_DECREF; }
--for(i=0; i<10; i++)
--{
-- PyObject *tmp = PySequence_GetItem(v, i);
-- if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF;
--}
--
--st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0));
--st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1));
--st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2));
--st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3));
--st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4));
--st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5));
--st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6));
--st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7));
--st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8));
--st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9));
--
--/* Fill in fields not provided by Python lstat() */
--st->st_blksize= 4096;
--st->st_blocks= (st->st_size + 511)/512;
--st->st_ino = 0;
--
--ret = 0;
--EPILOGUE
--}
--
--//@-node:getattr_func
--//@+node:readlink_func
--
--static int readlink_func(const char *path, char *link, size_t size)
--{
-- PyObject *v = PyObject_CallFunction(readlink_cb, "s", path);
-- char *s;
-- PROLOGUE
--
-- if(!PyString_Check(v)) { ret = -EINVAL; goto OUT_DECREF; }
-- s = PyString_AsString(v);
-- strncpy(link, s, size);
-- link[size-1] = '\0';
-- ret = 0;
--
-- EPILOGUE
--}
--//@-node:readlink_func
--//@+node:getdir_add_entry
--
--static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df)
--{
-- PyObject *o0;
-- PyObject *o1;
-- int ret = -EINVAL;
--
-- if(!PySequence_Check(w)) {
-- printf("getdir item not sequence\n");
-- goto out;
-- }
-- if(PySequence_Length(w) != 2) {
-- printf("getdir item not len 2\n");
-- goto out;
-- }
-- o0 = PySequence_GetItem(w, 0);
-- o1 = PySequence_GetItem(w, 1);
--
-- if(!PyString_Check(o0)) {
-- printf("getdir item[0] not string\n");
-- goto out_decref;
-- }
-- if(!PyInt_Check(o1)) {
-- printf("getdir item[1] not int\n");
-- goto out_decref;
-- }
--
-- ret = df(dh, PyString_AsString(o0), PyInt_AsLong(o1));
--
--out_decref:
-- Py_DECREF(o0);
-- Py_DECREF(o1);
--
--out:
-- return ret;
--}
--//@-node:getdir_add_entry
--//@+node:getdir_func
--
--static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
--{
-- PyObject *v = PyObject_CallFunction(getdir_cb, "s", path);
-- int i;
-- PROLOGUE
--
-- if(!PySequence_Check(v)) {
-- printf("getdir_func not sequence\n");
-- goto OUT_DECREF;
-- }
-- for(i=0; i < PySequence_Length(v); i++) {
-- PyObject *w = PySequence_GetItem(v, i);
-- ret = getdir_add_entry(w, dh, df);
-- Py_DECREF(w);
-- if(ret != 0)
-- goto OUT_DECREF;
-- }
-- ret = 0;
--
-- EPILOGUE
--}
--//@-node:getdir_func
--//@+node:mknod_func
--
--static int mknod_func(const char *path, mode_t m, dev_t d)
--{
-- PyObject *v = PyObject_CallFunction(mknod_cb, "sii", path, m, d);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:mknod_func
--//@+node:mkdir_func
--
--static int mkdir_func(const char *path, mode_t m)
--{
-- PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:mkdir_func
--//@+node:unlink_func
--
--static int unlink_func(const char *path)
--{
-- PyObject *v = PyObject_CallFunction(unlink_cb, "s", path);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:unlink_func
--//@+node:rmdir_func
--
--static int rmdir_func(const char *path)
--{
-- PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:rmdir_func
--//@+node:symlink_func
--
--static int symlink_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:symlink_func
--//@+node:rename_func
--
--static int rename_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:rename_func
--//@+node:link_func
--
--static int link_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:link_func
--//@+node:chmod_func
--
--static int chmod_func(const char *path, mode_t m)
--{
-- PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:chmod_func
--//@+node:chown_func
--
--static int chown_func(const char *path, uid_t u, gid_t g)
--{
-- PyObject *v = PyObject_CallFunction(chown_cb, "sii", path, u, g);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:chown_func
--//@+node:truncate_func
--
--static int truncate_func(const char *path, off_t o)
--{
-- PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:truncate_func
--//@+node:utime_func
--
--static int utime_func(const char *path, struct utimbuf *u) {
-- int actime = u ? u->actime : time(NULL);
-- int modtime = u ? u->modtime : actime;
-- PyObject *v = PyObject_CallFunction(utime_cb, "s(ii)",
-- path, actime, modtime);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:utime_func
--//@+node:read_func
--
--static int read_func(const char *path, char *buf, size_t s, off_t off)
--{
-- PyObject *v = PyObject_CallFunction(read_cb, "sii", path, s, off);
-- PROLOGUE
-- if(PyString_Check(v)) {
-- if(PyString_Size(v) > s) goto OUT_DECREF;
-- memcpy(buf, PyString_AsString(v), PyString_Size(v));
-- ret = PyString_Size(v);
-- }
-- EPILOGUE
--}
--//@-node:read_func
--//@+node:write_func
--
--static int write_func(const char *path, const char *buf, size_t t, off_t off)
--{
-- PyObject *v = PyObject_CallFunction(write_cb,"ss#i", path, buf, t, off);
-- PROLOGUE
-- EPILOGUE
--}
--//@-node:write_func
--//@+node:open_func
--
--static int open_func(const char *path, int mode)
--{
-- PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode);
-- PROLOGUE
-- printf("open_func: path=%s\n", path);
-- EPILOGUE
--}
--//@-node:open_func
--//@+node:release_func
--static int release_func(const char *path, int flags)
--{
-- PyObject *v = PyObject_CallFunction(release_cb, "si", path, flags);
-- PROLOGUE
-- //printf("release_func: path=%s flags=%d\n", path, flags);
-- EPILOGUE
--}
--//@-node:release_func
--//@+node:statfs_func
--static int statfs_func( const char *dummy, struct statfs *fst)
--{
-- int i;
-- long retvalues[6];
-- PyObject *v = PyObject_CallFunction(statfs_cb, "");
--PROLOGUE
--
-- if (!PySequence_Check(v))
-- { goto OUT_DECREF; }
-- if (PySequence_Size(v) < 6)
-- { goto OUT_DECREF; }
-- for(i=0; i<6; i++)
-- {
-- PyObject *tmp = PySequence_GetItem(v, i);
-- retvalues[i] = PyInt_Check(tmp)
-- ? PyInt_AsLong(tmp)
-- : (PyLong_Check(tmp)
-- ? PyLong_AsLong(tmp)
-- : 0);
-- }
--
-- fst->f_bsize = retvalues[0];
-- fst->f_blocks = retvalues[1];
-- fst->f_bfree = retvalues[2];
-- fst->f_files = retvalues[3];
-- fst->f_ffree = retvalues[4];
-- fst->f_namelen = retvalues[5];
--
-- ret = 0;
--
--#ifdef IGNORE_THIS
-- printf("block_size=%ld, blocks=%ld, blocks_free=%ld, files=%ld, files_free=%ld, namelen=%ld\n",
-- retvalues[0], retvalues[1], retvalues[2], retvalues[3], retvalues[4], retvalues[5]);
--#endif
--
--EPILOGUE
--
--}
--
--//@-node:statfs_func
--//@+node:fsync_func
--static int fsync_func(const char *path, int isfsyncfile)
--{
-- PyObject *v = PyObject_CallFunction(fsync_cb, "si", path, isfsyncfile);
-- PROLOGUE
-- EPILOGUE
--}
--
--//@-node:fsync_func
--//@+node:process_cmd
--
--static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
--{
-- PyInterpreterState *interp = (PyInterpreterState *) data;
-- PyThreadState *state;
--
-- PyEval_AcquireLock();
-- state = PyThreadState_New(interp);
-- PyThreadState_Swap(state);
-- __fuse_process_cmd(f, cmd);
-- PyThreadState_Clear(state);
-- PyThreadState_Swap(NULL);
-- PyThreadState_Delete(state);
-- PyEval_ReleaseLock();
--}
--//@-node:process_cmd
--//@+node:pyfuse_loop_mt
--
--static void pyfuse_loop_mt(struct fuse *f)
--{
-- PyInterpreterState *interp;
-- PyThreadState *save;
--
-- PyEval_InitThreads();
-- interp = PyThreadState_Get()->interp;
-- save = PyEval_SaveThread();
-- __fuse_loop_mt(f, process_cmd, interp);
-- /* Not yet reached: */
-- PyEval_RestoreThread(save);
--}
--//@-node:pyfuse_loop_mt
--//@+node:Fuse_main
--
--static struct fuse *fuse=NULL;
--
--static PyObject *
--Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
--{
-- int fd;
-- int multithreaded=0;
-- char *lopts=NULL;
-- char *kopts=NULL;
-- char *mountpoint;
--
-- struct fuse_operations op;
--
-- static char *kwlist[] = {
-- "getattr", "readlink", "getdir", "mknod",
-- "mkdir", "unlink", "rmdir", "symlink", "rename",
-- "link", "chmod", "chown", "truncate", "utime",
-- "open", "read", "write", "release", "statfs", "fsync",
-- "mountpoint", "kopts", "lopts", "multithreaded",
-- "debug", NULL};
--
-- memset(&op, 0, sizeof(op));
--
-- if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOsssii",
-- kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb,
-- &mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb,
-- &link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb,
-- &open_cb, &read_cb, &write_cb, &release_cb, &statfs_cb, &fsync_cb,
-- &mountpoint, &kopts, &lopts, &multithreaded, &debuglevel))
-- return NULL;
--
--#define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; }
--
-- DO_ONE_ATTR(getattr);
-- DO_ONE_ATTR(readlink);
-- DO_ONE_ATTR(getdir);
-- DO_ONE_ATTR(mknod);
-- DO_ONE_ATTR(mkdir);
-- DO_ONE_ATTR(unlink);
-- DO_ONE_ATTR(rmdir);
-- DO_ONE_ATTR(symlink);
-- DO_ONE_ATTR(rename);
-- DO_ONE_ATTR(link);
-- DO_ONE_ATTR(chmod);
-- DO_ONE_ATTR(chown);
-- DO_ONE_ATTR(truncate);
-- DO_ONE_ATTR(utime);
-- DO_ONE_ATTR(open);
-- DO_ONE_ATTR(read);
-- DO_ONE_ATTR(write);
-- DO_ONE_ATTR(release);
-- DO_ONE_ATTR(statfs);
-- DO_ONE_ATTR(fsync);
--
-- fd = fuse_mount(mountpoint, kopts);
-- fuse = fuse_new(fd, lopts, &op);
-- if(multithreaded)
-- pyfuse_loop_mt(fuse);
-- else
-- fuse_loop(fuse);
--
-- //printf("Fuse_main: called\n");
--
-- Py_INCREF(Py_None);
-- return Py_None;
--}
--//@-node:Fuse_main
--//@+node:DL_EXPORT
--//@+at
--//@nonl
--// List of functions defined in the module
--//@-at
--//@@c
--static char FuseInvalidate__doc__[] =
-- "Tell Fuse kernel module to explicitly invalidate a cached inode's contents\n";
--
--static PyObject *FuseInvalidate( PyObject *self, PyObject *args) {
-- char *path;
-- PyObject *ret;
-- int err;
--
-- PyString_Check(args);
--
-- path = PyString_AsString(args);
--
-- err = fuse_invalidate(fuse, path);
--
-- ret = PyInt_FromLong(err);
--
-- return(ret);
--}
--
--static char FuseGetContext__doc__[] =
-- "Return the context of a filesystem operation in a dict. uid, gid, pid\n";
--
--static PyObject *FuseGetContext( PyObject *self, PyObject *args) {
-- struct fuse_context *fc;
-- PyObject *ret;
-- PyObject *num;
--
-- fc = fuse_get_context();
-- ret = PyDict_New();
--
-- if(!ret)
-- return(NULL);
--
-- num = PyInt_FromLong( fc->uid);
-- PyDict_SetItemString( ret, "uid", num);
--
-- num = PyInt_FromLong( fc->gid);
-- PyDict_SetItemString( ret, "gid", num);
--
-- num = PyInt_FromLong( fc->pid);
-- PyDict_SetItemString( ret, "pid", num);
--
-- return(ret);
--
--}
--
--static PyMethodDef Fuse_methods[] = {
-- {"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS},
-- {"FuseGetContext", (PyCFunction)FuseGetContext, METH_VARARGS, FuseGetContext__doc__},
-- {"FuseInvalidate", (PyCFunction)FuseInvalidate, METH_VARARGS, FuseInvalidate__doc__},
-- {NULL, NULL} /* sentinel */
--};
--
--
--/* Initialization function for the module (*must* be called init_fuse) */
--
--DL_EXPORT(void)
--init_fuse(void)
--{
-- PyObject *m, *d;
-- static PyObject *ErrorObject;
--
-- /* Create the module and add the functions */
-- m = Py_InitModule("_fuse", Fuse_methods);
--
-- /* Add some symbolic constants to the module */
-- d = PyModule_GetDict(m);
-- ErrorObject = PyErr_NewException("fuse.error", NULL, NULL);
-- PyDict_SetItemString(d, "error", ErrorObject);
--// PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG));
--}
--//@-node:DL_EXPORT
--//@-others
--
--//@-node:@file _fusemodule.c
--//@-leo
+++ /dev/null
--<?xml version="1.0" encoding="UTF-8"?>
--<leo_file>
--<leo_header file_format="2" tnodes="0" max_tnode_index="69" clone_windows="0"/>
--<globals body_outline_ratio="0.2448559670781893">
-- <global_window_position top="129" left="90" height="631" width="1124"/>
-- <global_log_window_position top="0" left="0" height="0" width="0"/>
--</globals>
--<preferences>
--</preferences>
--<find_panel_settings>
-- <find_string></find_string>
-- <change_string></change_string>
--</find_panel_settings>
--<vnodes>
--<v t="davidmcnab.121303142957" a="E"><vh>fuse python bindings</vh>
--<v t="davidmcnab.121303142957.1" a="E" tnodeList="davidmcnab.121303142957.1,davidmcnab.121303142957.2,davidmcnab.121303142957.3,davidmcnab.121303142957.4,davidmcnab.121303142957.5,davidmcnab.121303142957.6,davidmcnab.121303142957.7,davidmcnab.121303142957.8,davidmcnab.121303142957.9,davidmcnab.121303142957.10,davidmcnab.121303142957.11,davidmcnab.121303142957.12,davidmcnab.121303142957.13,davidmcnab.121303142957.14,davidmcnab.121303142957.15,davidmcnab.121303142957.16,davidmcnab.121303142957.17,davidmcnab.121303142957.18,davidmcnab.121303142957.19,davidmcnab.121303142957.20,davidmcnab.121303142957.21,davidmcnab.121303142957.22,davidmcnab.121303142957.23,davidmcnab.121303142957.24,davidmcnab.121303144441,davidmcnab.121303144441.1,davidmcnab.121303142957.25,davidmcnab.121303142957.26,davidmcnab.121303142957.27,davidmcnab.121303142957.28"><vh>@file _fusemodule.c</vh>
--<v t="davidmcnab.121303142957.2"><vh>includes</vh></v>
--<v t="davidmcnab.121303142957.3" a="M"><vh>globals</vh></v>
--<v t="davidmcnab.121303142957.4"><vh>PROLOGUE</vh></v>
--<v t="davidmcnab.121303142957.5"><vh>EPILOGUE</vh></v>
--<v t="davidmcnab.121303142957.6"><vh>getattr_func</vh></v>
--<v t="davidmcnab.121303142957.7"><vh>readlink_func</vh></v>
--<v t="davidmcnab.121303142957.8"><vh>getdir_add_entry</vh></v>
--<v t="davidmcnab.121303142957.9"><vh>getdir_func</vh></v>
--<v t="davidmcnab.121303142957.10"><vh>mknod_func</vh></v>
--<v t="davidmcnab.121303142957.11"><vh>mkdir_func</vh></v>
--<v t="davidmcnab.121303142957.12"><vh>unlink_func</vh></v>
--<v t="davidmcnab.121303142957.13"><vh>rmdir_func</vh></v>
--<v t="davidmcnab.121303142957.14"><vh>symlink_func</vh></v>
--<v t="davidmcnab.121303142957.15"><vh>rename_func</vh></v>
--<v t="davidmcnab.121303142957.16"><vh>link_func</vh></v>
--<v t="davidmcnab.121303142957.17"><vh>chmod_func</vh></v>
--<v t="davidmcnab.121303142957.18"><vh>chown_func</vh></v>
--<v t="davidmcnab.121303142957.19"><vh>truncate_func</vh></v>
--<v t="davidmcnab.121303142957.20"><vh>utime_func</vh></v>
--<v t="davidmcnab.121303142957.21"><vh>read_func</vh></v>
--<v t="davidmcnab.121303142957.22"><vh>write_func</vh></v>
--<v t="davidmcnab.121303142957.23"><vh>open_func</vh></v>
--<v t="davidmcnab.121303142957.24" a="M"><vh>release_func</vh></v>
--<v t="davidmcnab.121303144441"><vh>statfs_func</vh></v>
--<v t="davidmcnab.121303144441.1"><vh>fsync_func</vh></v>
--<v t="davidmcnab.121303142957.25" a="M"><vh>process_cmd</vh></v>
--<v t="davidmcnab.121303142957.26"><vh>pyfuse_loop_mt</vh></v>
--<v t="davidmcnab.121303142957.27" a="M"><vh>Fuse_main</vh></v>
--<v t="davidmcnab.121303142957.28"><vh>DL_EXPORT</vh></v>
--</v>
--<v t="davidmcnab.121303142957.29" tnodeList="davidmcnab.121303142957.29,davidmcnab.121303142957.30,davidmcnab.121303142957.31,davidmcnab.121303142957.32,davidmcnab.121303142957.33,davidmcnab.121303142957.34,davidmcnab.121303142957.35,davidmcnab.121303142957.36,davidmcnab.121303142957.37"><vh>@file fuse.py</vh>
--<v t="davidmcnab.121303142957.30"><vh>imports</vh></v>
--<v t="davidmcnab.121303142957.31" a="E"><vh>class ErrnoWrapper</vh>
--<v t="davidmcnab.121303142957.32"><vh>__init__</vh></v>
--<v t="davidmcnab.121303142957.33"><vh>__call__</vh></v>
--</v>
--<v t="davidmcnab.121303142957.34" a="E"><vh>class Fuse</vh>
--<v t="davidmcnab.121303142957.35" a="M"><vh>attribs</vh></v>
--<v t="davidmcnab.121303142957.36"><vh>__init__</vh></v>
--<v t="davidmcnab.121303142957.37"><vh>main</vh></v>
--</v>
--</v>
--<v t="davidmcnab.121303142957.38" tnodeList="davidmcnab.121303142957.38"><vh>@file Makefile</vh></v>
--<v t="davidmcnab.121303142957.39" a="E" tnodeList="davidmcnab.121303142957.39,davidmcnab.121303142957.40,davidmcnab.121303142957.41,davidmcnab.121303142957.42,davidmcnab.121303142957.43,davidmcnab.121303142957.44,davidmcnab.121303142957.45,davidmcnab.121303142957.46,davidmcnab.121303142957.47,davidmcnab.121303142957.48,davidmcnab.121303142957.49,davidmcnab.121303142957.50,davidmcnab.121303142957.51,davidmcnab.121303142957.52,davidmcnab.121303142957.53,davidmcnab.121303142957.54,davidmcnab.121303142957.55,davidmcnab.121303142957.56,davidmcnab.121303142957.57,davidmcnab.121303142957.58,davidmcnab.121303142957.59,davidmcnab.121303142957.60,davidmcnab.121303142957.61,davidmcnab.121303142957.62,davidmcnab.121303144134,davidmcnab.121303144134.1,davidmcnab.121303142957.63"><vh>@file xmp.py</vh>
--<v t="davidmcnab.121303142957.40"><vh>imports</vh></v>
--<v t="davidmcnab.121303142957.41" a="E"><vh>class Xmp</vh>
--<v t="davidmcnab.121303142957.42"><vh>__init__</vh></v>
--<v t="davidmcnab.121303142957.43"><vh>mythread</vh></v>
--<v t="davidmcnab.121303142957.44"><vh>attribs</vh></v>
--<v t="davidmcnab.121303142957.45"><vh>getattr</vh></v>
--<v t="davidmcnab.121303142957.46"><vh>readlink</vh></v>
--<v t="davidmcnab.121303142957.47"><vh>getdir</vh></v>
--<v t="davidmcnab.121303142957.48"><vh>unlink</vh></v>
--<v t="davidmcnab.121303142957.49"><vh>rmdir</vh></v>
--<v t="davidmcnab.121303142957.50"><vh>symlink</vh></v>
--<v t="davidmcnab.121303142957.51"><vh>rename</vh></v>
--<v t="davidmcnab.121303142957.52"><vh>link</vh></v>
--<v t="davidmcnab.121303142957.53"><vh>chmod</vh></v>
--<v t="davidmcnab.121303142957.54"><vh>chown</vh></v>
--<v t="davidmcnab.121303142957.55"><vh>truncate</vh></v>
--<v t="davidmcnab.121303142957.56"><vh>mknod</vh></v>
--<v t="davidmcnab.121303142957.57"><vh>mkdir</vh></v>
--<v t="davidmcnab.121303142957.58"><vh>utime</vh></v>
--<v t="davidmcnab.121303142957.59"><vh>open</vh></v>
--<v t="davidmcnab.121303142957.60"><vh>read</vh></v>
--<v t="davidmcnab.121303142957.61"><vh>write</vh></v>
--<v t="davidmcnab.121303142957.62" a="M"><vh>release</vh></v>
--<v t="davidmcnab.121303144134"><vh>statfs</vh></v>
--<v t="davidmcnab.121303144134.1"><vh>fsync</vh></v>
--</v>
--<v t="davidmcnab.121303142957.63"><vh>mainline</vh></v>
--</v>
--<v t="davidmcnab.121303142957.64" tnodeList="davidmcnab.121303142957.64"><vh>@file setup.py</vh></v>
--<v t="davidmcnab.121303142957.65" tnodeList="davidmcnab.121303142957.65"><vh>@file README</vh></v>
--<v t="davidmcnab.121303142957.67" a="E" tnodeList="davidmcnab.121303142957.67"><vh>@file mount.fuse</vh></v>
--<v t="davidmcnab.121403050157" a="E"><vh>@file fuse.py</vh>
--<v t="davidmcnab.121403050157.1"><vh><< fuse declarations >></vh></v>
--<v t="davidmcnab.121403050157.2" a="E"><vh>class ErrnoWrapper</vh>
--<v t="davidmcnab.121403050157.3"><vh><< class ErrnoWrapper declarations >></vh></v>
--<v t="davidmcnab.121403050157.4"><vh>__init__</vh></v>
--<v t="davidmcnab.121403050157.5" a="V"><vh>__call__</vh></v>
--</v>
--<v t="davidmcnab.121403050157.6" a="E"><vh>class Fuse</vh>
--<v t="davidmcnab.121403050157.7"><vh><< class Fuse declarations >></vh></v>
--<v t="davidmcnab.121403050157.8"><vh>__init__</vh></v>
--<v t="davidmcnab.121403050157.9"><vh>main</vh></v>
--</v>
--</v>
--</v>
--</vnodes>
--<tnodes>
--<t tx="davidmcnab.121303142957"></t>
--<t tx="davidmcnab.121303142957.1">@language c
--/*
-- Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--
-- This program can be distributed under the terms of the GNU GPL.
-- See the file COPYING.
--*/
--
--@others
--
--</t>
--<t tx="davidmcnab.121303142957.2">#include <Python.h>
--#include <fuse.h>
--#include <time.h>
--</t>
--<t tx="davidmcnab.121303142957.3">
--static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL,
-- *mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL,
-- *symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL,
-- *chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL,
-- *open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL,
-- *statfs_cb=NULL, *fsync_cb=NULL
-- ;
--</t>
--<t tx="davidmcnab.121303142957.4">#define PROLOGUE \
--int ret = -EINVAL; \
--if (!v) { PyErr_Print(); goto OUT; } \
--if(v == Py_None) { ret = 0; goto OUT_DECREF; } \
--if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; }
--
--</t>
--<t tx="davidmcnab.121303142957.5">#define EPILOGUE \
--OUT_DECREF: \
-- Py_DECREF(v); \
--OUT: \
-- return ret;
--</t>
--<t tx="davidmcnab.121303142957.6">
--/*
-- * Local Variables:
-- * indent-tabs-mode: t
-- * c-basic-offset: 8
-- * End:
-- * Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons.
-- * Namely, replacing PyTuple_* with PySequence_*, and checking numerical values
-- * with both PyInt_Check and PyLong_Check.
-- */
--
--static int getattr_func(const char *path, struct stat *st)
--{
--int i;
--PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
--PROLOGUE
--
--if(!PySequence_Check(v)) { goto OUT_DECREF; }
--if(PySequence_Size(v) < 10) { goto OUT_DECREF; }
--for(i=0; i<10; i++)
--{
-- PyObject *tmp = PySequence_GetItem(v, i);
-- if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF;
--}
--
--st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0));
--st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1));
--st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2));
--st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3));
--st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4));
--st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5));
--st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6));
--st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7));
--st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8));
--st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9));
--
--/* Fill in fields not provided by Python lstat() */
--st->st_blksize= 4096;
--st->st_blocks= (st->st_size + 511)/512;
--st->st_ino = 0;
--
--ret = 0;
--EPILOGUE
--}
--
--</t>
--<t tx="davidmcnab.121303142957.7">
--static int readlink_func(const char *path, char *link, size_t size)
--{
-- PyObject *v = PyObject_CallFunction(readlink_cb, "s", path);
-- char *s;
-- PROLOGUE
--
-- if(!PyString_Check(v)) { ret = -EINVAL; goto OUT_DECREF; }
-- s = PyString_AsString(v);
-- strncpy(link, s, size);
-- link[size-1] = '\0';
-- ret = 0;
--
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.8">
--static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df)
--{
-- PyObject *o0;
-- PyObject *o1;
-- int ret = -EINVAL;
--
-- if(!PySequence_Check(w)) {
-- printf("getdir item not sequence\n");
-- goto out;
-- }
-- if(PySequence_Length(w) != 2) {
-- printf("getdir item not len 2\n");
-- goto out;
-- }
-- o0 = PySequence_GetItem(w, 0);
-- o1 = PySequence_GetItem(w, 1);
--
-- if(!PyString_Check(o0)) {
-- printf("getdir item[0] not string\n");
-- goto out_decref;
-- }
-- if(!PyInt_Check(o1)) {
-- printf("getdir item[1] not int\n");
-- goto out_decref;
-- }
--
-- ret = df(dh, PyString_AsString(o0), PyInt_AsLong(o1));
--
--out_decref:
-- Py_DECREF(o0);
-- Py_DECREF(o1);
--
--out:
-- return ret;
--}
--</t>
--<t tx="davidmcnab.121303142957.9">
--static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
--{
-- PyObject *v = PyObject_CallFunction(getdir_cb, "s", path);
-- int i;
-- PROLOGUE
--
-- if(!PySequence_Check(v)) {
-- printf("getdir_func not sequence\n");
-- goto OUT_DECREF;
-- }
-- for(i=0; i < PySequence_Length(v); i++) {
-- PyObject *w = PySequence_GetItem(v, i);
-- ret = getdir_add_entry(w, dh, df);
-- Py_DECREF(w);
-- if(ret != 0)
-- goto OUT_DECREF;
-- }
-- ret = 0;
--
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.10">
--static int mknod_func(const char *path, mode_t m, dev_t d)
--{
-- PyObject *v = PyObject_CallFunction(mknod_cb, "sii", path, m, d);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.11">
--static int mkdir_func(const char *path, mode_t m)
--{
-- PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.12">
--static int unlink_func(const char *path)
--{
-- PyObject *v = PyObject_CallFunction(unlink_cb, "s", path);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.13">
--static int rmdir_func(const char *path)
--{
-- PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.14">
--static int symlink_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.15">
--static int rename_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.16">
--static int link_func(const char *path, const char *path1)
--{
-- PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.17">
--static int chmod_func(const char *path, mode_t m)
--{
-- PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.18">
--static int chown_func(const char *path, uid_t u, gid_t g)
--{
-- PyObject *v = PyObject_CallFunction(chown_cb, "sii", path, u, g);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.19">
--static int truncate_func(const char *path, off_t o)
--{
-- PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.20">
--static int utime_func(const char *path, struct utimbuf *u) {
-- int actime = u ? u->actime : time(NULL);
-- int modtime = u ? u->modtime : actime;
-- PyObject *v = PyObject_CallFunction(utime_cb, "s(ii)",
-- path, actime, modtime);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.21">
--static int read_func(const char *path, char *buf, size_t s, off_t off)
--{
-- PyObject *v = PyObject_CallFunction(read_cb, "sii", path, s, off);
-- PROLOGUE
-- if(PyString_Check(v)) {
-- if(PyString_Size(v) > s) goto OUT_DECREF;
-- memcpy(buf, PyString_AsString(v), PyString_Size(v));
-- ret = PyString_Size(v);
-- }
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.22">
--static int write_func(const char *path, const char *buf, size_t t, off_t off)
--{
-- PyObject *v = PyObject_CallFunction(write_cb,"ss#i", path, buf, t, off);
-- PROLOGUE
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.23">
--static int open_func(const char *path, int mode)
--{
-- PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode);
-- PROLOGUE
-- printf("open_func: path=%s\n", path);
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.24">static int release_func(const char *path, int flags)
--{
-- PyObject *v = PyObject_CallFunction(release_cb, "si", path, flags);
-- PROLOGUE
-- //printf("release_func: path=%s flags=%d\n", path, flags);
-- EPILOGUE
--}
--</t>
--<t tx="davidmcnab.121303142957.25">
--static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
--{
-- PyInterpreterState *interp = (PyInterpreterState *) data;
-- PyThreadState *state;
--
-- PyEval_AcquireLock();
-- state = PyThreadState_New(interp);
-- PyThreadState_Swap(state);
-- __fuse_process_cmd(f, cmd);
-- PyThreadState_Clear(state);
-- PyThreadState_Swap(NULL);
-- PyThreadState_Delete(state);
-- PyEval_ReleaseLock();
--}
--</t>
--<t tx="davidmcnab.121303142957.26">
--static void pyfuse_loop_mt(struct fuse *f)
--{
-- PyInterpreterState *interp;
-- PyThreadState *save;
--
-- PyEval_InitThreads();
-- interp = PyThreadState_Get()->interp;
-- save = PyEval_SaveThread();
-- __fuse_loop_mt(f, process_cmd, interp);
-- /* Not yet reached: */
-- PyEval_RestoreThread(save);
--}
--</t>
--<t tx="davidmcnab.121303142957.27">
--
--static PyObject *
--Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
--{
-- int flags=0;
-- int multithreaded=0;
-- static struct fuse *fuse=NULL;
--
-- struct fuse_operations op;
--
-- static char *kwlist[] = {
-- "getattr", "readlink", "getdir", "mknod",
-- "mkdir", "unlink", "rmdir", "symlink", "rename",
-- "link", "chmod", "chown", "truncate", "utime",
-- "open", "read", "write", "release", "statfs", "fsync",
-- "flags", "multithreaded", NULL};
--
-- memset(&op, 0, sizeof(op));
--
-- if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOii",
-- kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb,
-- &mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb,
-- &link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb,
-- &open_cb, &read_cb, &write_cb, &release_cb, &statfs_cb, &fsync_cb,
-- &flags, &multithreaded))
-- return NULL;
--
-- #define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; }
--
-- DO_ONE_ATTR(getattr);
-- DO_ONE_ATTR(readlink);
-- DO_ONE_ATTR(getdir);
-- DO_ONE_ATTR(mknod);
-- DO_ONE_ATTR(mkdir);
-- DO_ONE_ATTR(unlink);
-- DO_ONE_ATTR(rmdir);
-- DO_ONE_ATTR(symlink);
-- DO_ONE_ATTR(rename);
-- DO_ONE_ATTR(link);
-- DO_ONE_ATTR(chmod);
-- DO_ONE_ATTR(chown);
-- DO_ONE_ATTR(truncate);
-- DO_ONE_ATTR(utime);
-- DO_ONE_ATTR(open);
-- DO_ONE_ATTR(read);
-- DO_ONE_ATTR(write);
-- DO_ONE_ATTR(release);
-- DO_ONE_ATTR(statfs);
-- DO_ONE_ATTR(fsync);
--
-- fuse = fuse_new(0, flags, &op);
-- if(multithreaded)
-- pyfuse_loop_mt(fuse);
-- else
-- fuse_loop(fuse);
--
-- //printf("Fuse_main: called\n");
--
-- Py_INCREF(Py_None);
-- return Py_None;
--}
--</t>
--<t tx="davidmcnab.121303142957.28">@ List of functions defined in the module
--@c
--
--static PyMethodDef Fuse_methods[] = {
-- {"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS},
-- {NULL, NULL} /* sentinel */
--};
--
--
--/* Initialization function for the module (*must* be called init_fuse) */
--
--DL_EXPORT(void)
--init_fuse(void)
--{
-- PyObject *m, *d;
-- static PyObject *ErrorObject;
--
-- /* Create the module and add the functions */
-- m = Py_InitModule("_fuse", Fuse_methods);
--
-- /* Add some symbolic constants to the module */
-- d = PyModule_GetDict(m);
-- ErrorObject = PyErr_NewException("fuse.error", NULL, NULL);
-- PyDict_SetItemString(d, "error", ErrorObject);
-- PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG));
--}
--</t>
--<t tx="davidmcnab.121303142957.29">#
--# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--#
--# This program can be distributed under the terms of the GNU GPL.
--# See the file COPYING.
--#
--
--
--@language python
--@others
--</t>
--<t tx="davidmcnab.121303142957.30"># suppress version mismatch warnings
--try:
-- import warnings
-- warnings.filterwarnings('ignore',
-- 'Python C API version mismatch',
-- RuntimeWarning,
-- )
--except:
-- pass
--
--from _fuse import main, DEBUG
--import os, sys
--from errno import *
--
--</t>
--<t tx="davidmcnab.121303142957.31">class ErrnoWrapper:
-- @others
--</t>
--<t tx="davidmcnab.121303142957.32">def __init__(self, func):
-- self.func = func
--</t>
--<t tx="davidmcnab.121303142957.33">def __call__(self, *args, **kw):
-- try:
-- return apply(self.func, args, kw)
-- except (IOError, OSError), detail:
-- # Sometimes this is an int, sometimes an instance...
-- if hasattr(detail, "errno"): detail = detail.errno
-- return -detail
--</t>
--<t tx="davidmcnab.121303142957.34">class Fuse:
--
-- @others
--</t>
--<t tx="davidmcnab.121303142957.35">_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
-- 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
-- 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
-- 'statfs', 'fsync']
--
--flags = 0
--multithreaded = 0
--
--</t>
--<t tx="davidmcnab.121303142957.36">def __init__(self, *args, **kw):
--
-- # default attributes
-- self.optlist = []
-- self.optdict = {}
-- self.mountpoint = None
--
-- # grab arguments, if any
-- argv = sys.argv
-- argc = len(argv)
-- if argc > 1:
-- # we've been given the mountpoint
-- self.mountpoint = argv[1]
-- if argc > 2:
-- # we've received mount args
-- optstr = argv[2]
-- opts = optstr.split(",")
-- for o in opts:
-- try:
-- k, v = o.split("=", 1)
-- self.optdict[k] = v
-- except:
-- self.optlist.append(o)
--</t>
--<t tx="davidmcnab.121303142957.37">def main(self):
-- d = {'flags': self.flags}
-- d['multithreaded'] = self.multithreaded
-- for a in self._attrs:
-- if hasattr(self,a):
-- d[a] = ErrnoWrapper(getattr(self, a))
-- apply(main, (), d)
--</t>
--<t tx="davidmcnab.121303142957.38"># Makefile now uses distutils
--
--_fusemodule.so: _fusemodule.c
-- #gcc -g3 -I/usr/include/python2.1 _fusemodule.c -Wl,-shared -o _fusemodule.so -Wimplicit -lfuse && python -c 'import _fuse'
-- python setup.py build_ext --inplace
--
--install: _fusemodule.so
-- python setup.py install
--
--clean:
-- rm -rf _fusemodule.so *.pyc *.pyo *~ build
--</t>
--<t tx="davidmcnab.121303142957.39">@first #!/usr/bin/env python
--#
--# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--#
--# This program can be distributed under the terms of the GNU GPL.
--# See the file COPYING.
--#
--
--@others
--</t>
--<t tx="davidmcnab.121303142957.40">
--from fuse import Fuse
--import os
--from errno import *
--from stat import *
--
--import thread
--</t>
--<t tx="davidmcnab.121303142957.41">class Xmp(Fuse):
--
-- @others
--</t>
--<t tx="davidmcnab.121303142957.42">def __init__(self, *args, **kw):
--
-- Fuse.__init__(self, *args, **kw)
--
-- if 0:
-- print "xmp.py:Xmp:mountpoint: %s" % repr(self.mountpoint)
-- print "xmp.py:Xmp:unnamed mount options: %s" % self.optlist
-- print "xmp.py:Xmp:named mount options: %s" % self.optdict
--
-- # do stuff to set up your filesystem here, if you want
-- #thread.start_new_thread(self.mythread, ())
-- pass
--</t>
--<t tx="davidmcnab.121303142957.43">def mythread(self):
--
-- """
-- The beauty of the FUSE python implementation is that with the python interp
-- running in foreground, you can have threads
-- """
-- print "mythread: started"
-- #while 1:
-- # time.sleep(120)
-- # print "mythread: ticking"
--
--</t>
--<t tx="davidmcnab.121303142957.44">flags = 1
--
--</t>
--<t tx="davidmcnab.121303142957.45">def getattr(self, path):
-- return os.lstat(path)
--</t>
--<t tx="davidmcnab.121303142957.46">def readlink(self, path):
-- return os.readlink(path)
--</t>
--<t tx="davidmcnab.121303142957.47">def getdir(self, path):
-- return map(lambda x: (x,0), os.listdir(path))
--</t>
--<t tx="davidmcnab.121303142957.48">def unlink(self, path):
-- return os.unlink(path)
--</t>
--<t tx="davidmcnab.121303142957.49">def rmdir(self, path):
-- return os.rmdir(path)
--</t>
--<t tx="davidmcnab.121303142957.50">def symlink(self, path, path1):
-- return os.symlink(path, path1)
--</t>
--<t tx="davidmcnab.121303142957.51">def rename(self, path, path1):
-- return os.rename(path, path1)
--</t>
--<t tx="davidmcnab.121303142957.52">def link(self, path, path1):
-- return os.link(path, path1)
--</t>
--<t tx="davidmcnab.121303142957.53">def chmod(self, path, mode):
-- return os.chmod(path, mode)
--</t>
--<t tx="davidmcnab.121303142957.54">def chown(self, path, user, group):
-- return os.chown(path, user, group)
--</t>
--<t tx="davidmcnab.121303142957.55">def truncate(self, path, size):
-- f = open(path, "w+")
-- return f.truncate(size)
--</t>
--<t tx="davidmcnab.121303142957.56">def mknod(self, path, mode, dev):
-- """ Python has no os.mknod, so we can only do some things """
-- if S_ISREG(mode):
-- open(path, "w")
-- else:
-- return -EINVAL
--</t>
--<t tx="davidmcnab.121303142957.57">def mkdir(self, path, mode):
-- return os.mkdir(path, mode)
--</t>
--<t tx="davidmcnab.121303142957.58">def utime(self, path, times):
-- return os.utime(path, times)
--</t>
--<t tx="davidmcnab.121303142957.59">def open(self, path, flags):
-- #print "xmp.py:Xmp:open: %s" % path
-- os.close(os.open(path, flags))
-- return 0
--
--</t>
--<t tx="davidmcnab.121303142957.60">def read(self, path, len, offset):
-- #print "xmp.py:Xmp:read: %s" % path
-- f = open(path, "r")
-- f.seek(offset)
-- return f.read(len)
--
--</t>
--<t tx="davidmcnab.121303142957.61">def write(self, path, buf, off):
-- #print "xmp.py:Xmp:write: %s" % path
-- f = open(path, "r+")
-- f.seek(off)
-- f.write(buf)
-- return len(buf)
--
--</t>
--<t tx="davidmcnab.121303142957.62">def release(self, path, flags):
-- print "xmp.py:Xmp:release: %s %s" % (path, flags)
-- return 0
--</t>
--<t tx="davidmcnab.121303142957.63">
--if __name__ == '__main__':
--
-- server = Xmp()
-- server.flags = 0
-- server.multithreaded = 1;
-- server.main()
--</t>
--<t tx="davidmcnab.121303142957.64">"""
--distutils script for FUSE python module
--"""
--
--from distutils.core import setup, Extension
--
--setup(name="fuse",
-- version="0.1",
-- ext_modules=[Extension("_fusemodule", ["_fusemodule.c"],
-- library_dirs=["../lib",],
-- libraries=["fuse",],
-- ),
-- ],
-- py_modules=["fuse"],
-- )
--
--</t>
--<t tx="davidmcnab.121303142957.65">@language
--
--Refer to the INSTALL file for build/install instructions
--
--General Information
--===================
--
--This is a Python[1] interface to FUSE[2].
--
--FUSE (Filesystem in USErspace) is a simple interface for userspace
--programs to export a virtual filesystem to the linux kernel. FUSE
--also aims to provide a secure method for non privileged users to
--create and mount their own filesystem implementations.
--
--When run from the commandline, "fuse.py" simply reexports the root
--filesystem within the mount point as example/fusexmp does in the main
--FUSE distribution. It also offers a class, fuse.Fuse, which can be
--subclassed to create a filesystem. fuse.Xmp is the example filesystem
--implementation.
--
--In your subclass of fuse, add attributes with the expected names
--("getattr", "readlink", etc) and call signatures (refer to fuse.Xmp)
--then call main(). Make it runnable as a #! script, and mount with
-- fusermount <mount point> <script name>
--for some reason,
-- fusermount <mount point> python <script name>
--does not seem to work. (why?)
--
--Update
--======
--
--Updated 13-Dec-2003 by David McNab <david@rebirthing.co.nz>
--
-- - changed Makefile to use Pyton distutils
-- - added setup.py for distutils
--
-- - added 'code.leo' file for convenience of those who use the Leo
-- code editor (leo.sf.net)
--
-- - added support for 'statfs' and 'fsync' methods (refer xmp.py)
--
--Updated Dec 2003 by David McNab <david@rebirthing.co.nz>:
--
-- - added support for 'release' events (ie when file gets closed)
-- - added __init__ to base class, which picks off parameters and
-- stores them as instance attributes:
-- - self.mountpoint - the mountpoint as given in the mount command
-- - self.optlist - unnamed options (eg 'rw', 'exec' etc)
-- - self.optdict - named options (eg, '-o arg1=val1,arg2=val2...' from mount cmd)
-- - fixed incompatibility issues with recent pythons (original was broken
-- under python2.3)
--
--Limitations
--===========
--
--This is minimally tested, though I think I have exercised each function.
--There's no documentation, docstrings, or tests.
--
--Python's lstat() does not return some fields which must be filled in
--(st_blksize, st_blocks, st_ino), and _fusemodule assumes that the return
--value from the lstat() method is identical to Python's lstat(). This
--limitation should be lifted, and some standard order chosen for these
--three values. For now, though, default values are chosen and du returns a
--number similar to the "real" one.
--
--The Python Global Interpreter Lock is not handled, so using
--fuse.MULTITHREAD will not work. Modifying the PROLOGUE and EPILOGUE
--functions may take care of this. For now, just run without
--fuse.MULTITHREAD in flags.
--
--Author
--======
--
--I'm Jeff Epler <jepler@unpythonic.dhs.org>. I've been dabbling in
--Python for nearly 7 years now, and interested (despite the lack of a
--real practical use) in userspace filesystems ever since I couldn't get
--userfs to compile way back in '93 or so. FUSE is cool, but i'm still
--not sure what it's good for in practical terms.
--
--I don't know how high a level of interest I'll maintain in this project,
--so if you want to do something with it feel free to do so. Like FUSE,
--this software is distributed under the terms of the GNU General Public
--License, Version 2. Future versions, if any, will be available at [3].
--
--
--[1] http://www.python.org
--[2] http://sourceforge.net/projects/avf/
--[3] http://unpythonic.dhs.org/~jepler/fuse/
--</t>
--<t tx="davidmcnab.121303142957.67">@first #!/usr/bin/env python
--
--"""
--This utility allows FUSE filesystems to be mounted with the regular *nix
--'mount' command, or even be listed in /etc/fstab
--
--To enable this, you need to:
-- 1. set execute-permission on this script
-- 2. symlink this script into /sbin/mount.fuse
--
--Usage:
--
-- You can use this in 3 ways:
-- 1. mount -t fuse /path/to/script/or/program /path/of/mount/point [options]
-- 2. mount -t fuse none /path/of/mount/point -o fs=/path/to/script/or/prog[,opt=val...]
-- 3. in /etc/fstab, add:
-- /path/to/script/or/prog /path/of/mount/point fuse noauto[,...]
--"""
--
--import sys, os, time
--
--progname = sys.argv[0]
--
--def usage(ret):
-- print "Usage: %s /path/to/fuse/fs /path/of/mountpoint [-o options]" % progname
-- print "or: %s none /path/of/mountpoint [-o fs=/path/to/fuse/fs[,...]]" % progname
-- sys.exit(ret)
--
--def main():
--
-- # initial sanity check
-- argc = len(sys.argv)
-- if argc < 3 or sys.argv[3] != "-o":
-- usage(1)
--
-- dev = sys.argv[1]
-- mountpoint = sys.argv[2]
--
-- # grab options, if any
-- optdict = {}
-- optlist = []
-- if argc > 4:
-- odata = sys.argv[4]
-- opts = odata.split(",")
-- #print opts
-- for o in opts:
-- try:
-- k, v = o.split("=", 1)
-- optdict[k] = v
-- except:
-- optlist.append(o)
-- else:
-- odata = ""
--
-- #print sys.argv
-- if dev == 'none':
-- if not optdict.has_key("fs"):
-- print "%s: Must specify python file with 'fs' option\n" % progname
-- usage(1)
-- pyfile = optdict['fs']
-- else:
-- pyfile = dev
--
-- if not os.path.isfile(pyfile):
-- print "%s: file %s doesn't exist, or is not a file" % (progname, pyfile)
-- sys.exit(1)
-- pypath = os.path.abspath(pyfile)
--
-- #print optdict, optlist
--
-- # all seems ok - run our fuse fs as a child
-- if os.fork() == 0:
-- os.system("fusermount -c -x %s %s %s %s" % (mountpoint, pypath, mountpoint, odata))
-- else:
-- #print "parent exiting..."
-- pass
--
--if __name__ == '__main__':
-- main()
--
--</t>
--<t tx="davidmcnab.121303144134">def statfs(self):
-- """
-- Should return a tuple with the following 6 elements:
-- - blocksize - size of file blocks, in bytes
-- - totalblocks - total number of blocks in the filesystem
-- - freeblocks - number of free blocks
-- - totalfiles - total number of file inodes
-- - freefiles - nunber of free file inodes
--
-- Feel free to set any of the above values to 0, which tells
-- the kernel that the info is not available.
-- """
-- print "xmp.py:Xmp:statfs: returning fictitious values"
-- blocks_size = 1024
-- blocks = 100000
-- blocks_free = 25000
-- files = 100000
-- files_free = 60000
-- namelen = 80
-- return (blocks_size, blocks, blocks_free, files, files_free, namelen)
--</t>
--<t tx="davidmcnab.121303144134.1">def fsync(self, path, isfsyncfile):
-- print "xmp.py:Xmp:fsync: path=%s, isfsyncfile=%s" % (path, isfsyncfile)
-- return 0
--
--</t>
--<t tx="davidmcnab.121303144441">static int statfs_func(struct fuse_statfs *fst)
--{
-- int i;
-- long retvalues[6];
-- PyObject *v = PyObject_CallFunction(statfs_cb, "");
--PROLOGUE
--
-- if (!PySequence_Check(v))
-- { goto OUT_DECREF; }
-- if (PySequence_Size(v) < 6)
-- { goto OUT_DECREF; }
-- for(i=0; i<6; i++)
-- {
-- PyObject *tmp = PySequence_GetItem(v, i);
-- retvalues[i] = PyInt_Check(tmp)
-- ? PyInt_AsLong(tmp)
-- : (PyLong_Check(tmp)
-- ? PyLong_AsLong(tmp)
-- : 0);
-- }
--
-- fst->block_size = retvalues[0];
-- fst->blocks = retvalues[1];
-- fst->blocks_free = retvalues[2];
-- fst->files = retvalues[3];
-- fst->files_free = retvalues[4];
-- fst->namelen = retvalues[5];
-- ret = 0;
--
--#ifdef IGNORE_THIS
-- printf("block_size=%ld, blocks=%ld, blocks_free=%ld, files=%ld, files_free=%ld, namelen=%ld\n",
-- retvalues[0], retvalues[1], retvalues[2], retvalues[3], retvalues[4], retvalues[5]);
--#endif
--
--EPILOGUE
--
--}
--
--</t>
--<t tx="davidmcnab.121303144441.1">static int fsync_func(const char *path, int isfsyncfile)
--{
-- PyObject *v = PyObject_CallFunction(fsync_cb, "si", path, isfsyncfile);
-- PROLOGUE
-- EPILOGUE
--}
--
--</t>
--<t tx="davidmcnab.121403050157">@ignore
--@language python
--<< fuse declarations >>
--@others
-- #@-node:main
-- #@-others
--#@-node:class Fuse
--#@-others
--#@-node:@file fuse.py
--#@-leo
--</t>
--<t tx="davidmcnab.121403050157.1">#@+leo-ver=4
--#@+node:@file fuse.py
--#
--# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--#
--# This program can be distributed under the terms of the GNU GPL.
--# See the file COPYING.
--#
--
--
--#@@language python
--#@+others
--#@+node:imports
--# suppress version mismatch warnings
--try:
-- import warnings
-- warnings.filterwarnings('ignore',
-- 'Python C API version mismatch',
-- RuntimeWarning,
-- )
--except:
-- pass
--
--from _fuse import main, DEBUG
--import os, sys
--from errno import *
--
--#@-node:imports
--#@+node:class ErrnoWrapper
--</t>
--<t tx="davidmcnab.121403050157.2">class ErrnoWrapper:
-- << class ErrnoWrapper declarations >>
-- @others
--</t>
--<t tx="davidmcnab.121403050157.3"> #@ @+others
-- #@+node:__init__
--</t>
--<t tx="davidmcnab.121403050157.4">def __init__(self, func):
-- self.func = func
--</t>
--<t tx="davidmcnab.121403050157.5">#@-node:__init__
--#@+node:__call__
--def __call__(self, *args, **kw):
-- try:
-- return apply(self.func, args, kw)
-- except (IOError, OSError), detail:
-- # Sometimes this is an int, sometimes an instance...
-- if hasattr(detail, "errno"): detail = detail.errno
-- return -detail
--</t>
--<t tx="davidmcnab.121403050157.6"> #@-node:__call__
-- #@-others
--#@-node:class ErrnoWrapper
--#@+node:class Fuse
--class Fuse:
-- << class Fuse declarations >>
-- @others
--</t>
--<t tx="davidmcnab.121403050157.7">#@ @+others
--#@+node:attribs
--_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
-- 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
-- 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
-- 'statfs', 'fsync']
--
--flags = 0
--multithreaded = 0
--
--#@-node:attribs
--#@+node:__init__
--</t>
--<t tx="davidmcnab.121403050157.8">def __init__(self, *args, **kw):
--
-- # default attributes
-- self.optlist = []
-- self.optdict = {}
-- self.mountpoint = None
--
-- # grab arguments, if any
-- argv = sys.argv
-- argc = len(argv)
-- if argc > 1:
-- # we've been given the mountpoint
-- self.mountpoint = argv[1]
-- if argc > 2:
-- # we've received mount args
-- optstr = argv[2]
-- opts = optstr.split(",")
-- for o in opts:
-- try:
-- k, v = o.split("=", 1)
-- self.optdict[k] = v
-- except:
-- self.optlist.append(o)
--</t>
--<t tx="davidmcnab.121403050157.9">#@-node:__init__
--#@+node:main
--def main(self):
-- d = {'flags': self.flags}
-- d['multithreaded'] = self.multithreaded
-- for a in self._attrs:
-- if hasattr(self,a):
-- d[a] = ErrnoWrapper(getattr(self, a))
-- apply(main, (), d)
--</t>
--</tnodes>
--</leo_file>
+++ /dev/null
--#@+leo-ver=4
--#@+node:@file fuse.py
--#
--# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--#
--# This program can be distributed under the terms of the GNU GPL.
--# See the file COPYING.
--#
--
--
--#@@language python
--#@+others
--#@+node:imports
--# suppress version mismatch warnings
--try:
-- import warnings
-- warnings.filterwarnings('ignore',
-- 'Python C API version mismatch',
-- RuntimeWarning,
-- )
--except:
-- pass
--
--from _fuse import main, FuseGetContext, FuseInvalidate
--from string import join
--import os, sys
--from errno import *
--
--#@-node:imports
--#@+node:class ErrnoWrapper
--class ErrnoWrapper:
-- #@ @+others
-- #@+node:__init__
-- def __init__(self, func):
-- self.func = func
-- #@-node:__init__
-- #@+node:__call__
-- def __call__(self, *args, **kw):
-- try:
-- return apply(self.func, args, kw)
-- except (IOError, OSError), detail:
-- # Sometimes this is an int, sometimes an instance...
-- if hasattr(detail, "errno"): detail = detail.errno
-- return -detail
-- #@-node:__call__
-- #@-others
--#@-node:class ErrnoWrapper
--#@+node:class Fuse
--class Fuse:
--
-- #@ @+others
-- #@+node:attribs
-- _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
-- 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
-- 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
-- 'statfs', 'fsync']
--
-- flags = 0
-- multithreaded = 0
--
-- #@-node:attribs
-- #@+node:__init__
-- def __init__(self, *args, **kw):
--
-- # default attributes
-- self.optlist = []
-- self.optdict = {}
-- self.mountpoint = None
--
-- # grab arguments, if any
-- argv = sys.argv
-- argc = len(argv)
-- if argc > 1:
-- # we've been given the mountpoint
-- self.mountpoint = argv[1]
-- if argc > 2:
-- # we've received mount args
-- optstr = argv[2]
-- opts = optstr.split(",")
-- for o in opts:
-- try:
-- k, v = o.split("=", 1)
-- self.optdict[k] = v
-- except:
-- self.optlist.append(o)
--
-- def GetContext(self):
-- return FuseGetContext(self)
--
-- def Invalidate(self, path):
-- return FuseInvalidate(self, path)
--
-- #@-node:__init__
-- #@+node:main
-- def main(self):
--
-- d = {'mountpoint': self.mountpoint}
-- d['multithreaded'] = self.multithreaded
-- if hasattr( self, 'debug'):
-- d['lopts'] = 'debug';
--
-- k=[]
-- if hasattr(self,'allow_other'):
-- k.append('allow_other')
--
-- if hasattr(self,'kernel_cache'):
-- k.append('kernel_cache')
--
-- if len(k):
-- d['kopts'] = join(k,',')
--
-- for a in self._attrs:
-- if hasattr(self,a):
-- d[a] = ErrnoWrapper(getattr(self, a))
-- apply(main, (), d)
-- #@-node:main
-- #@-others
--#@-node:class Fuse
--#@-others
--#@-node:@file fuse.py
--#@-leo
+++ /dev/null
--#@+leo-ver=4
--#@+node:@file setup.py
--"""
--distutils script for FUSE python module
--"""
--
--from distutils.core import setup, Extension
--
--setup(name="fuse",
-- version="0.1",
-- ext_modules=[Extension("_fusemodule", ["_fusemodule.c"],
-- library_dirs=["../lib/.libs",],
-- include_dirs=["../include",],
-- libraries=["fuse",],
-- ),
-- ],
-- py_modules=["fuse"],
-- )
--
--#@-node:@file setup.py
--#@-leo
+++ /dev/null
--#!/usr/bin/env python
--#@+leo-ver=4
--#@+node:@file xmp.py
--#@@first
--#
--# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
--#
--# This program can be distributed under the terms of the GNU GPL.
--# See the file COPYING.
--#
--
--#@+others
--#@+node:imports
--
--from fuse import Fuse
--import os
--from errno import *
--from stat import *
--
--import thread
--#@-node:imports
--#@+node:class Xmp
--class Xmp(Fuse):
--
-- #@ @+others
-- #@+node:__init__
-- def __init__(self, *args, **kw):
--
-- Fuse.__init__(self, *args, **kw)
--
-- if 0:
-- print "xmp.py:Xmp:mountpoint: %s" % repr(self.mountpoint)
-- print "xmp.py:Xmp:unnamed mount options: %s" % self.optlist
-- print "xmp.py:Xmp:named mount options: %s" % self.optdict
--
-- # do stuff to set up your filesystem here, if you want
-- #thread.start_new_thread(self.mythread, ())
-- pass
-- #@-node:__init__
-- #@+node:mythread
-- def mythread(self):
--
-- """
-- The beauty of the FUSE python implementation is that with the python interp
-- running in foreground, you can have threads
-- """
-- print "mythread: started"
-- #while 1:
-- # time.sleep(120)
-- # print "mythread: ticking"
--
-- #@-node:mythread
-- #@+node:attribs
-- flags = 1
--
-- #@-node:attribs
-- #@+node:getattr
-- def getattr(self, path):
-- return os.lstat(path)
-- #@-node:getattr
-- #@+node:readlink
-- def readlink(self, path):
-- return os.readlink(path)
-- #@-node:readlink
-- #@+node:getdir
-- def getdir(self, path):
-- return map(lambda x: (x,0), os.listdir(path))
-- #@-node:getdir
-- #@+node:unlink
-- def unlink(self, path):
-- return os.unlink(path)
-- #@-node:unlink
-- #@+node:rmdir
-- def rmdir(self, path):
-- return os.rmdir(path)
-- #@-node:rmdir
-- #@+node:symlink
-- def symlink(self, path, path1):
-- return os.symlink(path, path1)
-- #@-node:symlink
-- #@+node:rename
-- def rename(self, path, path1):
-- return os.rename(path, path1)
-- #@-node:rename
-- #@+node:link
-- def link(self, path, path1):
-- return os.link(path, path1)
-- #@-node:link
-- #@+node:chmod
-- def chmod(self, path, mode):
-- return os.chmod(path, mode)
-- #@-node:chmod
-- #@+node:chown
-- def chown(self, path, user, group):
-- return os.chown(path, user, group)
-- #@-node:chown
-- #@+node:truncate
-- def truncate(self, path, size):
-- f = open(path, "w+")
-- return f.truncate(size)
-- #@-node:truncate
-- #@+node:mknod
-- def mknod(self, path, mode, dev):
-- """ Python has no os.mknod, so we can only do some things """
-- if S_ISREG(mode):
-- open(path, "w")
-- else:
-- return -EINVAL
-- #@-node:mknod
-- #@+node:mkdir
-- def mkdir(self, path, mode):
-- return os.mkdir(path, mode)
-- #@-node:mkdir
-- #@+node:utime
-- def utime(self, path, times):
-- return os.utime(path, times)
-- #@-node:utime
-- #@+node:open
-- def open(self, path, flags):
-- #print "xmp.py:Xmp:open: %s" % path
-- os.close(os.open(path, flags))
-- return 0
--
-- #@-node:open
-- #@+node:read
-- def read(self, path, len, offset):
-- #print "xmp.py:Xmp:read: %s" % path
-- f = open(path, "r")
-- f.seek(offset)
-- return f.read(len)
--
-- #@-node:read
-- #@+node:write
-- def write(self, path, buf, off):
-- #print "xmp.py:Xmp:write: %s" % path
-- f = open(path, "r+")
-- f.seek(off)
-- f.write(buf)
-- return len(buf)
--
-- #@-node:write
-- #@+node:release
-- def release(self, path, flags):
-- print "xmp.py:Xmp:release: %s %s" % (path, flags)
-- return 0
-- #@-node:release
-- #@+node:statfs
-- def statfs(self):
-- """
-- Should return a tuple with the following 6 elements:
-- - blocksize - size of file blocks, in bytes
-- - totalblocks - total number of blocks in the filesystem
-- - freeblocks - number of free blocks
-- - totalfiles - total number of file inodes
-- - freefiles - nunber of free file inodes
--
-- Feel free to set any of the above values to 0, which tells
-- the kernel that the info is not available.
-- """
-- print "xmp.py:Xmp:statfs: returning fictitious values"
-- blocks_size = 1024
-- blocks = 100000
-- blocks_free = 25000
-- files = 100000
-- files_free = 60000
-- namelen = 80
-- return (blocks_size, blocks, blocks_free, files, files_free, namelen)
-- #@-node:statfs
-- #@+node:fsync
-- def fsync(self, path, isfsyncfile):
-- print "xmp.py:Xmp:fsync: path=%s, isfsyncfile=%s" % (path, isfsyncfile)
-- return 0
--
-- #@-node:fsync
-- #@-others
--#@-node:class Xmp
--#@+node:mainline
--
--if __name__ == '__main__':
--
-- server = Xmp()
-- server.multithreaded = 1;
-- server.main()
--#@-node:mainline
--#@-others
--#@-node:@file xmp.py
--#@-leo