mirror of
https://github.com/libfuse/libfuse.git
synced 2024-12-02 16:44:15 +08:00
573 lines
11 KiB
Plaintext
573 lines
11 KiB
Plaintext
#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 (struct fuse_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->block_size = POPi;
|
|
st->blocks_free = POPi;
|
|
st->blocks = POPi;
|
|
st->files_free = POPi;
|
|
st->files = POPi;
|
|
st->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 ? FUSE_DEBUG : 0,&fops));
|