11 /* perl implements threads with pthread. So, we use the pthread API for
12 * handling thread-local storage. */
14 PerlInterpreter *master_interp = NULL;
15 static inline void create_perl_context() {
17 PerlInterpreter *me = PERL_GET_CONTEXT;
19 PERL_SET_CONTEXT(master_interp);
20 me = perl_clone(master_interp, CLONEf_CLONE_HOST);
24 # define FUSE_CONTEXT_PRE create_perl_context(); { dSP
25 # define FUSE_CONTEXT_POST }
26 # define FUSE_USE_ITHREADS
28 # error "Sorry, I don't know how to handle ithreads on this architecture."
31 # define FUSE_CONTEXT_PRE dSP
32 # define FUSE_CONTEXT_POST
38 #define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,sp-PL_stack_base ,##a )
43 #define N_CALLBACKS 25
44 SV *_PLfuse_callbacks[N_CALLBACKS];
46 int _PLfuse_getattr(const char *file, struct stat *result) {
49 DEBUGf("getattr begin: %s\n",file);
53 XPUSHs(sv_2mortal(newSVpv(file,strlen(file))));
55 rv = call_sv(_PLfuse_callbacks[0],G_ARRAY);
59 fprintf(stderr,"inappropriate number of returned values from getattr\n");
66 result->st_blocks = POPi;
67 result->st_blksize = POPi;
68 result->st_ctime = POPi;
69 result->st_mtime = POPi;
70 result->st_atime = POPi;
71 result->st_size = POPn; // we pop double here to support files larger than 4Gb (long limit)
72 result->st_rdev = POPi;
73 result->st_gid = POPi;
74 result->st_uid = POPi;
75 result->st_nlink = POPi;
76 result->st_mode = POPi;
77 result->st_ino = POPi;
78 result->st_dev = POPi;
84 DEBUGf("getattr end: %i\n",rv);
89 int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
94 DEBUGf("readlink begin\n");
98 XPUSHs(sv_2mortal(newSVpv(file,0)));
100 rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
106 if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
109 strncpy(buf,SvPV_nolen(mysv),buflen);
117 DEBUGf("readlink end: %i\n",rv);
124 * This doesn't yet work... we alwas get ENOSYS when trying to use readdir().
125 * Well, of course, getdir() is fine as well.
127 int _PLfuse_readdir(const char *file, void *dirh, fuse_fill_dir_t dirfil, off_t off, struct fuse_file_info *fi) {
129 int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
132 DEBUGf("getdir begin\n");
136 XPUSHs(sv_2mortal(newSVpv(file,0)));
138 prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
143 dirfil(dirh,POPp,0,0);
145 fprintf(stderr,"getdir() handler returned nothing!\n");
151 DEBUGf("getdir end: %i\n",rv);
156 int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) {
159 DEBUGf("mknod begin\n");
163 XPUSHs(sv_2mortal(newSVpv(file,0)));
164 XPUSHs(sv_2mortal(newSViv(mode)));
165 XPUSHs(sv_2mortal(newSViv(dev)));
167 rv = call_sv(_PLfuse_callbacks[3],G_SCALAR);
176 DEBUGf("mknod end: %i\n",rv);
181 int _PLfuse_mkdir (const char *file, mode_t mode) {
184 DEBUGf("mkdir begin\n");
188 XPUSHs(sv_2mortal(newSVpv(file,0)));
189 XPUSHs(sv_2mortal(newSViv(mode)));
191 rv = call_sv(_PLfuse_callbacks[4],G_SCALAR);
200 DEBUGf("mkdir end: %i\n",rv);
206 int _PLfuse_unlink (const char *file) {
209 DEBUGf("unlink begin\n");
213 XPUSHs(sv_2mortal(newSVpv(file,0)));
215 rv = call_sv(_PLfuse_callbacks[5],G_SCALAR);
224 DEBUGf("unlink end: %i\n",rv);
229 int _PLfuse_rmdir (const char *file) {
232 DEBUGf("rmdir begin\n");
236 XPUSHs(sv_2mortal(newSVpv(file,0)));
238 rv = call_sv(_PLfuse_callbacks[6],G_SCALAR);
247 DEBUGf("rmdir end: %i\n",rv);
252 int _PLfuse_symlink (const char *file, const char *new) {
255 DEBUGf("symlink begin\n");
259 XPUSHs(sv_2mortal(newSVpv(file,0)));
260 XPUSHs(sv_2mortal(newSVpv(new,0)));
262 rv = call_sv(_PLfuse_callbacks[7],G_SCALAR);
271 DEBUGf("symlink end: %i\n",rv);
276 int _PLfuse_rename (const char *file, const char *new) {
279 DEBUGf("rename begin\n");
283 XPUSHs(sv_2mortal(newSVpv(file,0)));
284 XPUSHs(sv_2mortal(newSVpv(new,0)));
286 rv = call_sv(_PLfuse_callbacks[8],G_SCALAR);
295 DEBUGf("rename end: %i\n",rv);
300 int _PLfuse_link (const char *file, const char *new) {
303 DEBUGf("link begin\n");
307 XPUSHs(sv_2mortal(newSVpv(file,0)));
308 XPUSHs(sv_2mortal(newSVpv(new,0)));
310 rv = call_sv(_PLfuse_callbacks[9],G_SCALAR);
319 DEBUGf("link end: %i\n",rv);
324 int _PLfuse_chmod (const char *file, mode_t mode) {
327 DEBUGf("chmod begin\n");
331 XPUSHs(sv_2mortal(newSVpv(file,0)));
332 XPUSHs(sv_2mortal(newSViv(mode)));
334 rv = call_sv(_PLfuse_callbacks[10],G_SCALAR);
343 DEBUGf("chmod end: %i\n",rv);
348 int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
351 DEBUGf("chown begin\n");
355 XPUSHs(sv_2mortal(newSVpv(file,0)));
356 XPUSHs(sv_2mortal(newSViv(uid)));
357 XPUSHs(sv_2mortal(newSViv(gid)));
359 rv = call_sv(_PLfuse_callbacks[11],G_SCALAR);
368 DEBUGf("chown end: %i\n",rv);
373 int _PLfuse_truncate (const char *file, off_t off) {
376 DEBUGf("truncate begin\n");
380 XPUSHs(sv_2mortal(newSVpv(file,0)));
381 XPUSHs(sv_2mortal(newSViv(off)));
383 rv = call_sv(_PLfuse_callbacks[12],G_SCALAR);
392 DEBUGf("truncate end: %i\n",rv);
397 int _PLfuse_utime (const char *file, struct utimbuf *uti) {
400 DEBUGf("utime begin\n");
404 XPUSHs(sv_2mortal(newSVpv(file,0)));
405 XPUSHs(sv_2mortal(newSViv(uti->actime)));
406 XPUSHs(sv_2mortal(newSViv(uti->modtime)));
408 rv = call_sv(_PLfuse_callbacks[13],G_SCALAR);
417 DEBUGf("utime end: %i\n",rv);
422 int _PLfuse_open (const char *file, struct fuse_file_info *fi) {
424 int flags = fi->flags;
427 DEBUGf("open begin\n");
431 XPUSHs(sv_2mortal(newSVpv(file,0)));
432 XPUSHs(sv_2mortal(newSViv(flags)));
433 /* Create a hashref containing the details from fi
434 * which we can look at or modify.
436 fi->fh = 0; /* Ensure it starts with 0 - important if they don't set it */
438 #if FUSE_VERSION >= 24
439 hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0);
440 hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0);
442 #if FUSE_VERSION >= 29
443 hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0);
445 XPUSHs(sv_2mortal(newRV_noinc((SV*) fihash)));
446 /* All hashref things done */
449 /* Open called with filename, flags */
450 rv = call_sv(_PLfuse_callbacks[14],G_ARRAY);
460 /* We're holding on to the sv reference until
461 * after exit of this function, so we need to
462 * increment its reference count
464 fi->fh = SvREFCNT_inc(sv);
473 /* Success, so copy the file handle which they returned */
474 #if FUSE_VERSION >= 24
476 svp = hv_fetch(fihash, "direct_io", 9, 0);
479 fi->direct_io = SvIV(*svp);
481 svp = hv_fetch(fihash, "keep_cache", 10, 0);
484 fi->keep_cache = SvIV(*svp);
487 #if FUSE_VERSION >= 29
488 svp = hv_fetch(fihash, "nonseekable", 11, 0);
491 fi->nonseekable = SvIV(*svp);
498 DEBUGf("open end: %i\n",rv);
503 int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) {
506 DEBUGf("read begin\n");
510 XPUSHs(sv_2mortal(newSVpv(file,0)));
511 XPUSHs(sv_2mortal(newSViv(buflen)));
512 XPUSHs(sv_2mortal(newSViv(off)));
513 XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh);
515 rv = call_sv(_PLfuse_callbacks[15],G_SCALAR);
521 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
530 croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
532 memcpy(buf,SvPV_nolen(mysv),rv);
538 DEBUGf("read end: %i\n",rv);
543 int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) {
546 DEBUGf("write begin\n");
550 XPUSHs(sv_2mortal(newSVpv(file,0)));
551 XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
552 XPUSHs(sv_2mortal(newSViv(off)));
553 XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh);
555 rv = call_sv(_PLfuse_callbacks[16],G_SCALAR);
564 DEBUGf("write end: %i\n",rv);
569 int _PLfuse_statfs (const char *file, struct statvfs *st) {
572 DEBUGf("statfs begin\n");
577 rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
579 DEBUGf("statfs got %i params\n",rv);
580 if(rv == 6 || rv == 7) {
586 st->f_namemax = POPi;
587 /* zero and fill-in other */
591 st->f_bavail = st->f_bfree;
592 st->f_favail = st->f_ffree;
600 croak("inappropriate number of returned values from statfs");
609 DEBUGf("statfs end: %i\n",rv);
614 int _PLfuse_flush (const char *file, struct fuse_file_info *fi) {
617 DEBUGf("flush begin\n");
621 XPUSHs(sv_2mortal(newSVpv(file,0)));
622 XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh);
624 rv = call_sv(_PLfuse_callbacks[18],G_SCALAR);
633 DEBUGf("flush end: %i\n",rv);
638 int _PLfuse_release (const char *file, struct fuse_file_info *fi) {
640 int flags = fi->flags;
642 DEBUGf("release begin\n");
646 XPUSHs(sv_2mortal(newSVpv(file,0)));
647 XPUSHs(sv_2mortal(newSViv(flags)));
648 XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh);
650 rv = call_sv(_PLfuse_callbacks[19],G_SCALAR);
656 /* We're now finished with the handle that we were given, so
657 * we should decrement its count so that it can be freed.
661 SvREFCNT_dec((SV *)fi->fh);
667 DEBUGf("release end: %i\n",rv);
672 int _PLfuse_fsync (const char *file, int datasync, struct fuse_file_info *fi) {
674 int flags = fi->flags;
676 DEBUGf("fsync begin\n");
680 XPUSHs(sv_2mortal(newSVpv(file,0)));
681 XPUSHs(sv_2mortal(newSViv(flags)));
682 XPUSHs(fi->fh==0 ? &PL_sv_undef : (SV *)fi->fh);
684 rv = call_sv(_PLfuse_callbacks[20],G_SCALAR);
693 DEBUGf("fsync end: %i\n",rv);
698 int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) {
701 DEBUGf("setxattr begin\n");
705 XPUSHs(sv_2mortal(newSVpv(file,0)));
706 XPUSHs(sv_2mortal(newSVpv(name,0)));
707 XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
708 XPUSHs(sv_2mortal(newSViv(flags)));
710 rv = call_sv(_PLfuse_callbacks[21],G_SCALAR);
719 DEBUGf("setxattr end: %i\n",rv);
724 int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) {
727 DEBUGf("getxattr begin\n");
731 XPUSHs(sv_2mortal(newSVpv(file,0)));
732 XPUSHs(sv_2mortal(newSVpv(name,0)));
734 rv = call_sv(_PLfuse_callbacks[22],G_SCALAR);
742 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
750 if ((rv > 0) && (buflen > 0))
755 memcpy(buf,SvPV_nolen(mysv),rv);
762 DEBUGf("getxattr end: %i\n",rv);
767 int _PLfuse_listxattr (const char *file, char *list, size_t size) {
770 DEBUGf("listxattr begin\n");
774 XPUSHs(sv_2mortal(newSVpv(file,0)));
776 prv = call_sv(_PLfuse_callbacks[23],G_ARRAY);
789 /* Always nul terminate */
790 if (list && (size > 0))
800 int s = SvCUR(mysv) + 1;
803 if (p && (size > 0) && (spc >= s))
805 memcpy(p,SvPV_nolen(mysv),s);
813 * If the Perl returned an error, return that.
814 * Otherwise check that the buffer was big enough.
819 if ((size > 0) && (size < total_len))
826 DEBUGf("listxattr end: %i\n",rv);
831 int _PLfuse_removexattr (const char *file, const char *name) {
834 DEBUGf("removexattr begin\n");
838 XPUSHs(sv_2mortal(newSVpv(file,0)));
839 XPUSHs(sv_2mortal(newSVpv(name,0)));
841 rv = call_sv(_PLfuse_callbacks[24],G_SCALAR);
850 DEBUGf("removexattr end: %i\n",rv);
855 struct fuse_operations _available_ops = {
856 getattr: _PLfuse_getattr,
857 readlink: _PLfuse_readlink,
858 getdir: _PLfuse_getdir,
860 readdir: _PLfuse_readdir,
862 mknod: _PLfuse_mknod,
863 mkdir: _PLfuse_mkdir,
864 unlink: _PLfuse_unlink,
865 rmdir: _PLfuse_rmdir,
866 symlink: _PLfuse_symlink,
867 rename: _PLfuse_rename,
869 chmod: _PLfuse_chmod,
870 chown: _PLfuse_chown,
871 truncate: _PLfuse_truncate,
872 utime: _PLfuse_utime,
875 write: _PLfuse_write,
876 statfs: _PLfuse_statfs,
877 flush: _PLfuse_flush,
878 release: _PLfuse_release,
879 fsync: _PLfuse_fsync,
880 setxattr: _PLfuse_setxattr,
881 getxattr: _PLfuse_getxattr,
882 listxattr: _PLfuse_listxattr,
883 removexattr: _PLfuse_removexattr,
886 MODULE = Fuse PACKAGE = Fuse
892 struct fuse_context *fc;
894 fc = fuse_get_context();
897 hv_store(hash, "uid", 3, newSViv(fc->uid), 0);
898 hv_store(hash, "gid", 3, newSViv(fc->gid), 0);
899 hv_store(hash, "pid", 3, newSViv(fc->pid), 0);
900 RETVAL = newRV_noinc((SV*)hash);
910 struct fuse_operations fops =
911 {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
912 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
913 int i, fd, debug, threaded;
916 char *fuseopts = NULL;
917 struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
918 struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL);
921 fprintf(stderr,"Perl<->C inconsistency or internal error\n");
926 threaded = SvIV(ST(1));
928 #ifdef FUSE_USE_ITHREADS
929 master_interp = PERL_GET_CONTEXT;
931 fprintf(stderr,"FUSE warning: Your script has requested multithreaded "
932 "mode, but your perl was not built with -Dusethreads. "
933 "Threads are disabled.\n");
937 mountpoint = SvPV_nolen(ST(2));
938 mountopts = SvPV_nolen(ST(3));
939 if (SvCUR(ST(4))) fuseopts = SvPV_nolen(ST(4));
940 for(i=0;i<N_CALLBACKS;i++) {
942 /* allow symbolic references, or real code references. */
943 if(SvOK(var) && (SvPOK(var) || (SvROK(var) && SvTYPE(SvRV(var)) == SVt_PVCV))) {
944 void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops;
946 #ifdef FUSE_USE_ITHREADS
948 /* note: under 5.8.7, this croaks for code references. */
951 _PLfuse_callbacks[i] = var;
954 croak("invalid callback (%i) passed to perl_fuse_main "
955 "(%s is not a string, code ref, or undef).\n",
956 i+4,SvPVbyte_nolen(var));
960 * XXX: What comes here is just a ridiculous use of the option parsing API
961 * to hack on compatibility with other parts of the new API. First and
962 * foremost, real C argc/argv would be good to get at...
965 (fuse_opt_add_arg(&margs, "") == -1 ||
966 fuse_opt_add_arg(&margs, "-o") == -1 ||
967 fuse_opt_add_arg(&margs, mountopts) == -1)) {
968 fuse_opt_free_args(&margs);
969 croak("out of memory\n");
971 if (fuse_opt_add_arg(&fargs, "") == -1) {
972 fuse_opt_free_args(&fargs);
973 croak("out of memory\n");
976 (fuse_opt_add_arg(&fargs, "-o") == -1 ||
977 fuse_opt_add_arg(&fargs, fuseopts) == -1)) {
978 fuse_opt_free_args(&fargs);
979 croak("out of memory\n");
981 if (debug && (fuse_opt_add_arg(&fargs, "-d") == -1)) {
982 fuse_opt_free_args(&fargs);
983 croak("out of memory\n");
986 fd = fuse_mount(mountpoint,&margs);
987 fuse_opt_free_args(&margs);
989 croak("could not mount fuse filesystem!\n");
992 fuse_loop_mt(fuse_new(fd,&fargs,&fops,sizeof(fops)));
994 fuse_loop(fuse_new(fd,&fargs,&fops,sizeof(fops)));
995 fuse_opt_free_args(&fargs);