libfuse/perl/Fuse.xs

573 lines
11 KiB
Plaintext
Raw Normal View History

2001-12-03 16:35:41 +08:00
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <fuse.h>
2001-12-13 18:55:07 +08:00
#undef DEBUGf
2002-04-19 13:37:54 +08:00
#if 0
2002-02-06 23:20:11 +08:00
#define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,PL_stack_sp-PL_stack_base ,##a )
2001-12-13 18:55:07 +08:00
#else
#define DEBUGf(a...)
#endif
2001-12-03 16:35:41 +08:00
SV *_PLfuse_callbacks[18];
2001-12-03 16:35:41 +08:00
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;
2001-12-13 18:55:07 +08:00
if(rv != 13) {
if(rv > 1) {
fprintf(stderr,"inappropriate number of returned values from getattr\n");
rv = -ENOSYS;
} else if(rv)
2001-12-03 16:35:41 +08:00
rv = POPi;
else
2001-12-13 18:55:07 +08:00
rv = -ENOENT;
2001-12-03 16:35:41 +08:00
} else {
2001-12-13 18:55:07 +08:00
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;
2001-12-13 18:55:07 +08:00
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;
2001-12-13 18:55:07 +08:00
result->st_dev = POPi;
rv = 0;
2001-12-03 16:35:41 +08:00
}
FREETMPS;
LEAVE;
2002-02-06 23:20:11 +08:00
PUTBACK;
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
int rv;
char *rvstr;
2002-02-06 23:20:11 +08:00
dSP;
I32 ax;
2001-12-13 18:55:07 +08:00
if(buflen < 1)
return EINVAL;
2001-12-03 16:35:41 +08:00
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(file,0)));
PUTBACK;
rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
SPAGAIN;
if(!rv)
rv = -ENOENT;
2002-02-06 23:20:11 +08:00
else {
SV *mysv = POPs;
if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
rv = SvIV(mysv);
2001-12-03 16:35:41 +08:00
else {
2002-02-06 23:20:11 +08:00
strncpy(buf,SvPV_nolen(mysv),buflen);
2001-12-03 16:35:41 +08:00
rv = 0;
}
2002-02-06 23:20:11 +08:00
}
2001-12-03 16:35:41 +08:00
FREETMPS;
LEAVE;
2001-12-13 18:55:07 +08:00
buf[buflen-1] = 0;
2002-02-06 23:20:11 +08:00
PUTBACK;
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
int prv, rv;
2002-02-06 23:20:11 +08:00
dSP;
2001-12-03 16:35:41 +08:00
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(file,0)));
PUTBACK;
prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
SPAGAIN;
if(prv) {
2002-02-06 23:20:11 +08:00
rv = POPi;
while(--prv)
dirfil(dirh,POPp,0);
2001-12-03 16:35:41 +08:00
} else {
fprintf(stderr,"getdir() handler returned nothing!\n");
rv = -ENOSYS;
}
FREETMPS;
LEAVE;
2002-02-06 23:20:11 +08:00
PUTBACK;
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_mkdir (const char *file, mode_t mode) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("mkdir begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("mkdir end: %i %i\n",sp-PL_stack_base,rv);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_unlink (const char *file) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("unlink begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("unlink end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_rmdir (const char *file) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("rmdir begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("rmdir end: %i %i\n",sp-PL_stack_base,rv);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_symlink (const char *file, const char *new) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("symlink begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("symlink end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_rename (const char *file, const char *new) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("rename begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("rename end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_link (const char *file, const char *new) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("link begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("link end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_chmod (const char *file, mode_t mode) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("chmod begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("chmod end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("chown begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("chown end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_truncate (const char *file, off_t off) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("truncate begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("truncate end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_utime (const char *file, struct utimbuf *uti) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("utime begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("utime end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_open (const char *file, int flags) {
int rv;
SV *rvsv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("open begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("open end: %i %i\n",sp-PL_stack_base,rv);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) {
int rv;
char *rvstr;
2002-02-15 14:18:29 +08:00
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("read begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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 {
2002-02-06 23:20:11 +08:00
SV *mysv = POPs;
if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
2001-12-03 16:35:41 +08:00
rv = SvIV(mysv);
else {
2002-02-15 14:18:29 +08:00
if(SvPOK(mysv)) {
rv = SvCUR(mysv);
} else {
rv = 0;
}
if(rv > buflen)
2001-12-13 18:55:07 +08:00
croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
2001-12-03 16:35:41 +08:00
if(rv)
memcpy(buf,SvPV_nolen(mysv),rv);
}
}
2002-02-06 23:20:11 +08:00
FREETMPS;
LEAVE;
PUTBACK;
DEBUGf("read end: %i %i\n",sp-PL_stack_base,rv);
2001-12-03 16:35:41 +08:00
return rv;
}
int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) {
int rv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
DEBUGf("write begin: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("write end: %i\n",sp-PL_stack_base);
2001-12-03 16:35:41 +08:00
return rv;
}
2004-10-10 16:04:55 +08:00
int _PLfuse_statfs (const char *file, struct statfs *st) {
int rv;
char *rvstr;
dSP;
2002-02-06 23:20:11 +08:00
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) {
2004-07-14 14:24:50 +08:00
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;
2002-02-06 23:20:11 +08:00
PUTBACK;
DEBUGf("statfs end: %i\n",sp-PL_stack_base);
return rv;
}
2001-12-03 16:35:41 +08:00
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
2001-12-03 16:35:41 +08:00
};
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;
2001-12-03 16:35:41 +08:00
STRLEN n_a;
STRLEN l;
INIT:
if(items != 20) {
2001-12-03 16:35:41 +08:00
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);
2001-12-03 16:35:41 +08:00
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!");
2004-07-24 01:35:27 +08:00
fuse_loop(fuse_new(fd,debug ? "debug" : NULL,&fops));