7 /* perl implements threads with pthread. So, we use the pthread API for
8 * handling thread-local storage. */
10 PerlInterpreter *master_interp = NULL;
11 static inline void create_perl_context() {
13 PerlInterpreter *me = PERL_GET_CONTEXT;
15 PERL_SET_CONTEXT(master_interp);
16 me = perl_clone(master_interp, CLONEf_CLONE_HOST);
20 # define FUSE_CONTEXT_PRE create_perl_context(); { dSP
21 # define FUSE_CONTEXT_POST }
22 # define FUSE_USE_ITHREADS
24 # error "Sorry, I don't know how to handle ithreads on this architecture."
27 # define FUSE_CONTEXT_PRE dSP
28 # define FUSE_CONTEXT_POST
34 #define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,sp-PL_stack_base ,##a )
39 #define N_CALLBACKS 29
40 SV *_PLfuse_callbacks[N_CALLBACKS];
42 int _PLfuse_getattr(const char *file, struct stat *result) {
45 DEBUGf("getattr begin: %s\n",file);
49 XPUSHs(sv_2mortal(newSVpv(file,strlen(file))));
51 rv = call_sv(_PLfuse_callbacks[0],G_ARRAY);
55 fprintf(stderr,"inappropriate number of returned values from getattr\n");
62 result->st_blocks = POPi;
63 result->st_blksize = POPi;
64 result->st_ctime = POPi;
65 result->st_mtime = POPi;
66 result->st_atime = POPi;
67 result->st_size = POPi;
68 result->st_rdev = POPi;
69 result->st_gid = POPi;
70 result->st_uid = POPi;
71 result->st_nlink = POPi;
72 result->st_mode = POPi;
73 result->st_ino = POPi;
74 result->st_dev = POPi;
80 DEBUGf("getattr end: %i\n",rv);
85 int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
90 DEBUGf("readlink begin\n");
94 XPUSHs(sv_2mortal(newSVpv(file,0)));
96 rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
102 if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
105 strncpy(buf,SvPV_nolen(mysv),buflen);
113 DEBUGf("readlink end: %i\n",rv);
118 int _PLfuse_opendir(const char *file, struct fuse_file_info *info) {
119 croak("opendir NOT IMPLEMENTED");
121 int _PLfuse_releasedir(const char *file, struct fuse_file_info *info) {
122 croak("releasedir NOT IMPLEMENTED");
124 int _PLfuse_fsyncdir(const char *file, struct fuse_file_info *info) {
125 croak("fsyncdir NOT IMPLEMENTED");
128 int _PLfuse_readdir(const char *file, void *dirh, fuse_fill_dir_t dirfil, off_t off, struct fuse_file_info *fi) {
132 DEBUGf("readdir begin\n");
136 XPUSHs(sv_2mortal(newSVpv(file,0)));
137 XPUSHs(sv_2mortal(newSViv(off)));
139 prv = call_sv(_PLfuse_callbacks[26],G_ARRAY);
146 dirfil(dirh,SvPV_nolen(entry),NULL,offset);
148 fprintf(stderr,"readdir() handler didn't return 2 values!\n");
154 DEBUGf("readdir end: %i\n",rv);
159 int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
162 DEBUGf("getdir begin\n");
166 XPUSHs(sv_2mortal(newSVpv(file,0)));
168 prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
173 dirfil(dirh,POPp,0,0);
175 fprintf(stderr,"getdir() handler returned nothing!\n");
181 DEBUGf("getdir end: %i\n",rv);
186 int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) {
189 DEBUGf("mknod begin\n");
193 XPUSHs(sv_2mortal(newSVpv(file,0)));
194 XPUSHs(sv_2mortal(newSViv(mode)));
195 XPUSHs(sv_2mortal(newSViv(dev)));
197 rv = call_sv(_PLfuse_callbacks[3],G_SCALAR);
206 DEBUGf("mknod end: %i\n",rv);
211 int _PLfuse_mkdir (const char *file, mode_t mode) {
214 DEBUGf("mkdir begin\n");
218 XPUSHs(sv_2mortal(newSVpv(file,0)));
219 XPUSHs(sv_2mortal(newSViv(mode)));
221 rv = call_sv(_PLfuse_callbacks[4],G_SCALAR);
230 DEBUGf("mkdir end: %i\n",rv);
236 int _PLfuse_unlink (const char *file) {
239 DEBUGf("unlink begin\n");
243 XPUSHs(sv_2mortal(newSVpv(file,0)));
245 rv = call_sv(_PLfuse_callbacks[5],G_SCALAR);
254 DEBUGf("unlink end: %i\n",rv);
259 int _PLfuse_rmdir (const char *file) {
262 DEBUGf("rmdir begin\n");
266 XPUSHs(sv_2mortal(newSVpv(file,0)));
268 rv = call_sv(_PLfuse_callbacks[6],G_SCALAR);
277 DEBUGf("rmdir end: %i\n",rv);
282 int _PLfuse_symlink (const char *file, const char *new) {
285 DEBUGf("symlink begin\n");
289 XPUSHs(sv_2mortal(newSVpv(file,0)));
290 XPUSHs(sv_2mortal(newSVpv(new,0)));
292 rv = call_sv(_PLfuse_callbacks[7],G_SCALAR);
301 DEBUGf("symlink end: %i\n",rv);
306 int _PLfuse_rename (const char *file, const char *new) {
309 DEBUGf("rename begin\n");
313 XPUSHs(sv_2mortal(newSVpv(file,0)));
314 XPUSHs(sv_2mortal(newSVpv(new,0)));
316 rv = call_sv(_PLfuse_callbacks[8],G_SCALAR);
325 DEBUGf("rename end: %i\n",rv);
330 int _PLfuse_link (const char *file, const char *new) {
333 DEBUGf("link begin\n");
337 XPUSHs(sv_2mortal(newSVpv(file,0)));
338 XPUSHs(sv_2mortal(newSVpv(new,0)));
340 rv = call_sv(_PLfuse_callbacks[9],G_SCALAR);
349 DEBUGf("link end: %i\n",rv);
354 int _PLfuse_chmod (const char *file, mode_t mode) {
357 DEBUGf("chmod begin\n");
361 XPUSHs(sv_2mortal(newSVpv(file,0)));
362 XPUSHs(sv_2mortal(newSViv(mode)));
364 rv = call_sv(_PLfuse_callbacks[10],G_SCALAR);
373 DEBUGf("chmod end: %i\n",rv);
378 int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
381 DEBUGf("chown begin\n");
385 XPUSHs(sv_2mortal(newSVpv(file,0)));
386 XPUSHs(sv_2mortal(newSViv(uid)));
387 XPUSHs(sv_2mortal(newSViv(gid)));
389 rv = call_sv(_PLfuse_callbacks[11],G_SCALAR);
398 DEBUGf("chown end: %i\n",rv);
403 int _PLfuse_truncate (const char *file, off_t off) {
406 DEBUGf("truncate begin\n");
410 XPUSHs(sv_2mortal(newSVpv(file,0)));
411 XPUSHs(sv_2mortal(newSViv(off)));
413 rv = call_sv(_PLfuse_callbacks[12],G_SCALAR);
422 DEBUGf("truncate end: %i\n",rv);
427 int _PLfuse_utime (const char *file, struct utimbuf *uti) {
430 DEBUGf("utime begin\n");
434 XPUSHs(sv_2mortal(newSVpv(file,0)));
435 XPUSHs(sv_2mortal(newSViv(uti->actime)));
436 XPUSHs(sv_2mortal(newSViv(uti->modtime)));
438 rv = call_sv(_PLfuse_callbacks[13],G_SCALAR);
447 DEBUGf("utime end: %i\n",rv);
452 int _PLfuse_open (const char *file, struct fuse_file_info *fi) {
454 int flags = fi->flags;
456 DEBUGf("open begin\n");
460 XPUSHs(sv_2mortal(newSVpv(file,0)));
461 XPUSHs(sv_2mortal(newSViv(flags)));
463 rv = call_sv(_PLfuse_callbacks[14],G_SCALAR);
472 DEBUGf("open end: %i\n",rv);
477 int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) {
480 DEBUGf("read begin\n");
484 XPUSHs(sv_2mortal(newSVpv(file,0)));
485 XPUSHs(sv_2mortal(newSViv(buflen)));
486 XPUSHs(sv_2mortal(newSViv(off)));
488 rv = call_sv(_PLfuse_callbacks[15],G_SCALAR);
494 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
503 croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
505 memcpy(buf,SvPV_nolen(mysv),rv);
511 DEBUGf("read end: %i\n",rv);
516 int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off, struct fuse_file_info *fi) {
519 DEBUGf("write begin\n");
523 XPUSHs(sv_2mortal(newSVpv(file,0)));
524 XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
525 XPUSHs(sv_2mortal(newSViv(off)));
527 rv = call_sv(_PLfuse_callbacks[16],G_SCALAR);
536 DEBUGf("write end: %i\n",rv);
541 int _PLfuse_statfs (const char *file, struct statvfs *st) {
544 DEBUGf("statfs begin\n");
549 rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
551 DEBUGf("statfs got %i params\n",rv);
552 if(rv == 6 || rv == 7) {
558 st->f_namemax = POPi;
559 /* zero and fill-in other */
563 st->f_bavail = st->f_bfree;
564 st->f_favail = st->f_ffree;
572 croak("inappropriate number of returned values from statfs");
581 DEBUGf("statfs end: %i\n",rv);
586 int _PLfuse_flush (const char *file, struct fuse_file_info *fi) {
589 DEBUGf("flush begin\n");
593 XPUSHs(sv_2mortal(newSVpv(file,0)));
595 rv = call_sv(_PLfuse_callbacks[18],G_SCALAR);
604 DEBUGf("flush end: %i\n",rv);
609 int _PLfuse_release (const char *file, struct fuse_file_info *fi) {
611 int flags = fi->flags;
613 DEBUGf("release begin\n");
617 XPUSHs(sv_2mortal(newSVpv(file,0)));
618 XPUSHs(sv_2mortal(newSViv(flags)));
620 rv = call_sv(_PLfuse_callbacks[19],G_SCALAR);
629 DEBUGf("release end: %i\n",rv);
634 int _PLfuse_fsync (const char *file, int datasync, struct fuse_file_info *fi) {
636 int flags = fi->flags;
638 DEBUGf("fsync begin\n");
642 XPUSHs(sv_2mortal(newSVpv(file,0)));
643 XPUSHs(sv_2mortal(newSViv(flags)));
645 rv = call_sv(_PLfuse_callbacks[20],G_SCALAR);
654 DEBUGf("fsync end: %i\n",rv);
659 int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) {
662 DEBUGf("setxattr begin\n");
666 XPUSHs(sv_2mortal(newSVpv(file,0)));
667 XPUSHs(sv_2mortal(newSVpv(name,0)));
668 XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
669 XPUSHs(sv_2mortal(newSViv(flags)));
671 rv = call_sv(_PLfuse_callbacks[21],G_SCALAR);
680 DEBUGf("setxattr end: %i\n",rv);
685 int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) {
688 DEBUGf("getxattr begin\n");
692 XPUSHs(sv_2mortal(newSVpv(file,0)));
693 XPUSHs(sv_2mortal(newSVpv(name,0)));
695 rv = call_sv(_PLfuse_callbacks[22],G_SCALAR);
703 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
711 if ((rv > 0) && (buflen > 0))
716 memcpy(buf,SvPV_nolen(mysv),rv);
723 DEBUGf("getxattr end: %i\n",rv);
728 int _PLfuse_listxattr (const char *file, char *list, size_t size) {
731 DEBUGf("listxattr begin\n");
735 XPUSHs(sv_2mortal(newSVpv(file,0)));
737 prv = call_sv(_PLfuse_callbacks[23],G_ARRAY);
750 /* Always nul terminate */
751 if (list && (size > 0))
761 int s = SvCUR(mysv) + 1;
764 if (p && (size > 0) && (spc >= s))
766 memcpy(p,SvPV_nolen(mysv),s);
774 * If the Perl returned an error, return that.
775 * Otherwise check that the buffer was big enough.
780 if ((size > 0) && (size < total_len))
787 DEBUGf("listxattr end: %i\n",rv);
792 int _PLfuse_removexattr (const char *file, const char *name) {
795 DEBUGf("removexattr begin\n");
799 XPUSHs(sv_2mortal(newSVpv(file,0)));
800 XPUSHs(sv_2mortal(newSVpv(name,0)));
802 rv = call_sv(_PLfuse_callbacks[24],G_SCALAR);
811 DEBUGf("removexattr end: %i\n",rv);
816 struct fuse_operations _available_ops = {
817 getattr: _PLfuse_getattr,
818 readlink: _PLfuse_readlink,
819 getdir: _PLfuse_getdir,
820 mknod: _PLfuse_mknod,
821 mkdir: _PLfuse_mkdir,
822 unlink: _PLfuse_unlink,
823 rmdir: _PLfuse_rmdir,
824 symlink: _PLfuse_symlink,
825 rename: _PLfuse_rename,
827 chmod: _PLfuse_chmod,
828 chown: _PLfuse_chown,
829 truncate: _PLfuse_truncate,
830 utime: _PLfuse_utime,
833 write: _PLfuse_write,
834 statfs: _PLfuse_statfs,
835 flush: _PLfuse_flush,
836 release: _PLfuse_release,
837 fsync: _PLfuse_fsync,
838 setxattr: _PLfuse_setxattr,
839 getxattr: _PLfuse_getxattr,
840 listxattr: _PLfuse_listxattr,
841 removexattr: _PLfuse_removexattr,
842 opendir: _PLfuse_opendir,
843 readdir: _PLfuse_readdir,
844 releasedir: _PLfuse_releasedir,
845 fsyncdir: _PLfuse_fsyncdir,
848 MODULE = Fuse PACKAGE = Fuse
854 struct fuse_context *fc;
856 fc = fuse_get_context();
859 hv_store(hash, "uid", 3, newSViv(fc->uid), 0);
860 hv_store(hash, "gid", 3, newSViv(fc->gid), 0);
861 hv_store(hash, "pid", 3, newSViv(fc->pid), 0);
862 RETVAL = newRV_noinc((SV*)hash);
872 struct fuse_operations fops =
873 {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
874 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
875 int i, fd, debug, threaded;
878 struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
879 struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL);
881 if(items != 4+N_CALLBACKS) {
882 fprintf(stderr,"Perl<->C inconsistency or internal error\n");
887 threaded = SvIV(ST(1));
889 #ifdef FUSE_USE_ITHREADS
890 master_interp = PERL_GET_CONTEXT;
892 fprintf(stderr,"FUSE warning: Your script has requested multithreaded "
893 "mode, but your perl was not built with -Dusethreads. "
894 "Threads are disabled.\n");
898 mountpoint = SvPV_nolen(ST(2));
899 mountopts = SvPV_nolen(ST(3));
900 for(i=0;i<N_CALLBACKS;i++) {
902 /* allow symbolic references, or real code references. */
903 if(SvOK(var) && (SvPOK(var) || (SvROK(var) && SvTYPE(SvRV(var)) == SVt_PVCV))) {
904 void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops;
906 #ifdef FUSE_USE_ITHREADS
908 /* note: under 5.8.7, this croaks for code references. */
911 _PLfuse_callbacks[i] = var;
914 croak("invalid callback passed to perl_fuse_main "
915 "(%s is not a string, code ref, or undef).\n",
916 i+4,SvPVbyte_nolen(var));
920 * XXX: What comes here is just a ridiculous use of the option parsing API
921 * to hack on compatibility with other parts of the new API. First and
922 * foremost, real C argc/argv would be good to get at...
925 (fuse_opt_add_arg(&margs, "") == -1 ||
926 fuse_opt_add_arg(&margs, "-o") == -1 ||
927 fuse_opt_add_arg(&margs, mountopts) == -1)) {
928 fuse_opt_free_args(&margs);
929 croak("out of memory\n");
931 fd = fuse_mount(mountpoint,&margs);
932 fuse_opt_free_args(&margs);
934 croak("could not mount fuse filesystem!\n");
936 if ( fuse_opt_add_arg(&fargs, "") == -1 ||
937 fuse_opt_add_arg(&fargs, "-d") == -1) {
938 fuse_opt_free_args(&fargs);
939 croak("out of memory\n");
942 if (fuse_opt_add_arg(&fargs, "") == -1)
943 croak("out of memory\n");
947 fuse_loop_mt(fuse_new(fd,&fargs,&fops,sizeof(fops)));
949 fuse_loop(fuse_new(fd,&fargs,&fops,sizeof(fops)));
950 fuse_opt_free_args(&fargs);