r72@llin (orig r72): dpavlin | 2006-01-03 16:43:12 +0100
[perl-fuse.git] / Fuse.xs
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #ifdef USE_ITHREADS
6 # ifdef I_PTHREAD
7 /* perl implements threads with pthread.  So, we use the pthread API for
8  * handling thread-local storage. */
9 #  include <pthread.h>
10 PerlInterpreter *master_interp = NULL;
11 static inline void create_perl_context() {
12         if(master_interp) {
13                 PerlInterpreter *me = PERL_GET_CONTEXT;
14                 if(!me) {
15                         PERL_SET_CONTEXT(master_interp);
16                         me = perl_clone(master_interp, CLONEf_CLONE_HOST);
17                 }
18         }
19 }
20 #  define FUSE_CONTEXT_PRE create_perl_context(); {
21 #  define FUSE_CONTEXT_POST }
22 #  define FUSE_USE_ITHREADS
23 # else
24 #  error "Sorry, I don't know how to handle ithreads on this architecture."
25 # endif
26 #else
27 # define FUSE_CONTEXT_PRE
28 # define FUSE_CONTEXT_POST
29 #endif
30 #include <fuse/fuse.h>
31
32 #undef DEBUGf
33 #if 0
34 #define DEBUGf(f, a...) fprintf(stderr, "%s:%d (%i): " f,__BASE_FILE__,__LINE__,sp-PL_stack_base ,##a )
35 #else
36 #define DEBUGf(a...)
37 #endif
38
39 #define N_CALLBACKS 25
40 SV *_PLfuse_callbacks[N_CALLBACKS];
41
42 int _PLfuse_getattr(const char *file, struct stat *result) {
43         int rv, statcount;
44         FUSE_CONTEXT_PRE;
45         dSP;
46         DEBUGf("getattr begin: %s\n",file);
47         ENTER;
48         SAVETMPS;
49         PUSHMARK(SP);
50         XPUSHs(sv_2mortal(newSVpv(file,strlen(file))));
51         PUTBACK;
52         rv = call_sv(_PLfuse_callbacks[0],G_ARRAY);
53         SPAGAIN;
54         if(rv != 13) {
55                 if(rv > 1) {
56                         fprintf(stderr,"inappropriate number of returned values from getattr\n");
57                         rv = -ENOSYS;
58                 } else if(rv)
59                         rv = POPi;
60                 else
61                         rv = -ENOENT;
62         } else {
63                 result->st_blocks = POPi;
64                 result->st_blksize = POPi;
65                 result->st_ctime = POPi;
66                 result->st_mtime = POPi;
67                 result->st_atime = POPi;
68                 result->st_size = POPi;
69                 result->st_rdev = POPi;
70                 result->st_gid = POPi;
71                 result->st_uid = POPi;
72                 result->st_nlink = POPi;
73                 result->st_mode = POPi;
74                 /*result->st_ino =*/ POPi;
75                 result->st_dev = POPi;
76                 rv = 0;
77         }
78         FREETMPS;
79         LEAVE;
80         PUTBACK;
81         DEBUGf("getattr end: %i\n",rv);
82         FUSE_CONTEXT_POST;
83         return rv;
84 }
85
86 int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
87         int rv;
88         char *rvstr;
89         I32 ax;
90         FUSE_CONTEXT_PRE;
91         dSP;
92         if(buflen < 1)
93                 return EINVAL;
94         DEBUGf("readlink begin\n");
95         ENTER;
96         SAVETMPS;
97         PUSHMARK(SP);
98         XPUSHs(sv_2mortal(newSVpv(file,0)));
99         PUTBACK;
100         rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
101         SPAGAIN;
102         if(!rv)
103                 rv = -ENOENT;
104         else {
105                 SV *mysv = POPs;
106                 if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
107                         rv = SvIV(mysv);
108                 else {
109                         strncpy(buf,SvPV_nolen(mysv),buflen);
110                         rv = 0;
111                 }
112         }
113         FREETMPS;
114         LEAVE;
115         buf[buflen-1] = 0;
116         PUTBACK;
117         DEBUGf("readlink end: %i\n",rv);
118         FUSE_CONTEXT_POST;
119         return rv;
120 }
121
122 int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
123         int prv, rv;
124         FUSE_CONTEXT_PRE;
125         dSP;
126         DEBUGf("getdir begin\n");
127         ENTER;
128         SAVETMPS;
129         PUSHMARK(SP);
130         XPUSHs(sv_2mortal(newSVpv(file,0)));
131         PUTBACK;
132         prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
133         SPAGAIN;
134         if(prv) {
135                 rv = POPi;
136                 while(--prv)
137                         dirfil(dirh,POPp,0);
138         } else {
139                 fprintf(stderr,"getdir() handler returned nothing!\n");
140                 rv = -ENOSYS;
141         }
142         FREETMPS;
143         LEAVE;
144         PUTBACK;
145         DEBUGf("getdir end: %i\n",rv);
146         FUSE_CONTEXT_POST;
147         return rv;
148 }
149
150 int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) {
151         int rv;
152         SV *rvsv;
153         char *rvstr;
154         FUSE_CONTEXT_PRE;
155         dSP;
156         DEBUGf("mknod begin\n");
157         ENTER;
158         SAVETMPS;
159         PUSHMARK(SP);
160         XPUSHs(sv_2mortal(newSVpv(file,0)));
161         XPUSHs(sv_2mortal(newSViv(mode)));
162         XPUSHs(sv_2mortal(newSViv(dev)));
163         PUTBACK;
164         rv = call_sv(_PLfuse_callbacks[3],G_SCALAR);
165         SPAGAIN;
166         if(rv)
167                 rv = POPi;
168         else
169                 rv = 0;
170         FREETMPS;
171         LEAVE;
172         PUTBACK;
173         DEBUGf("mknod end: %i\n",rv);
174         FUSE_CONTEXT_POST;
175         return rv;
176 }
177
178 int _PLfuse_mkdir (const char *file, mode_t mode) {
179         int rv;
180         SV *rvsv;
181         char *rvstr;
182         FUSE_CONTEXT_PRE;
183         dSP;
184         DEBUGf("mkdir begin\n");
185         ENTER;
186         SAVETMPS;
187         PUSHMARK(SP);
188         XPUSHs(sv_2mortal(newSVpv(file,0)));
189         XPUSHs(sv_2mortal(newSViv(mode)));
190         PUTBACK;
191         rv = call_sv(_PLfuse_callbacks[4],G_SCALAR);
192         SPAGAIN;
193         if(rv)
194                 rv = POPi;
195         else
196                 rv = 0;
197         FREETMPS;
198         LEAVE;
199         PUTBACK;
200         DEBUGf("mkdir end: %i\n",rv);
201         FUSE_CONTEXT_POST;
202         return rv;
203 }
204
205
206 int _PLfuse_unlink (const char *file) {
207         int rv;
208         SV *rvsv;
209         char *rvstr;
210         FUSE_CONTEXT_PRE;
211         dSP;
212         DEBUGf("unlink begin\n");
213         ENTER;
214         SAVETMPS;
215         PUSHMARK(SP);
216         XPUSHs(sv_2mortal(newSVpv(file,0)));
217         PUTBACK;
218         rv = call_sv(_PLfuse_callbacks[5],G_SCALAR);
219         SPAGAIN;
220         if(rv)
221                 rv = POPi;
222         else
223                 rv = 0;
224         FREETMPS;
225         LEAVE;
226         PUTBACK;
227         DEBUGf("unlink end: %i\n",rv);
228         FUSE_CONTEXT_POST;
229         return rv;
230 }
231
232 int _PLfuse_rmdir (const char *file) {
233         int rv;
234         SV *rvsv;
235         char *rvstr;
236         FUSE_CONTEXT_PRE;
237         dSP;
238         DEBUGf("rmdir begin\n");
239         ENTER;
240         SAVETMPS;
241         PUSHMARK(SP);
242         XPUSHs(sv_2mortal(newSVpv(file,0)));
243         PUTBACK;
244         rv = call_sv(_PLfuse_callbacks[6],G_SCALAR);
245         SPAGAIN;
246         if(rv)
247                 rv = POPi;
248         else
249                 rv = 0;
250         FREETMPS;
251         LEAVE;
252         PUTBACK;
253         DEBUGf("rmdir end: %i\n",rv);
254         FUSE_CONTEXT_POST;
255         return rv;
256 }
257
258 int _PLfuse_symlink (const char *file, const char *new) {
259         int rv;
260         SV *rvsv;
261         char *rvstr;
262         FUSE_CONTEXT_PRE;
263         dSP;
264         DEBUGf("symlink begin\n");
265         ENTER;
266         SAVETMPS;
267         PUSHMARK(SP);
268         XPUSHs(sv_2mortal(newSVpv(file,0)));
269         XPUSHs(sv_2mortal(newSVpv(new,0)));
270         PUTBACK;
271         rv = call_sv(_PLfuse_callbacks[7],G_SCALAR);
272         SPAGAIN;
273         if(rv)
274                 rv = POPi;
275         else
276                 rv = 0;
277         FREETMPS;
278         LEAVE;
279         PUTBACK;
280         DEBUGf("symlink end: %i\n",rv);
281         FUSE_CONTEXT_POST;
282         return rv;
283 }
284
285 int _PLfuse_rename (const char *file, const char *new) {
286         int rv;
287         SV *rvsv;
288         char *rvstr;
289         FUSE_CONTEXT_PRE;
290         dSP;
291         DEBUGf("rename begin\n");
292         ENTER;
293         SAVETMPS;
294         PUSHMARK(SP);
295         XPUSHs(sv_2mortal(newSVpv(file,0)));
296         XPUSHs(sv_2mortal(newSVpv(new,0)));
297         PUTBACK;
298         rv = call_sv(_PLfuse_callbacks[8],G_SCALAR);
299         SPAGAIN;
300         if(rv)
301                 rv = POPi;
302         else
303                 rv = 0;
304         FREETMPS;
305         LEAVE;
306         PUTBACK;
307         DEBUGf("rename end: %i\n",rv);
308         FUSE_CONTEXT_POST;
309         return rv;
310 }
311
312 int _PLfuse_link (const char *file, const char *new) {
313         int rv;
314         SV *rvsv;
315         char *rvstr;
316         FUSE_CONTEXT_PRE;
317         dSP;
318         DEBUGf("link begin\n");
319         ENTER;
320         SAVETMPS;
321         PUSHMARK(SP);
322         XPUSHs(sv_2mortal(newSVpv(file,0)));
323         XPUSHs(sv_2mortal(newSVpv(new,0)));
324         PUTBACK;
325         rv = call_sv(_PLfuse_callbacks[9],G_SCALAR);
326         SPAGAIN;
327         if(rv)
328                 rv = POPi;
329         else
330                 rv = 0;
331         FREETMPS;
332         LEAVE;
333         PUTBACK;
334         DEBUGf("link end: %i\n",rv);
335         FUSE_CONTEXT_POST;
336         return rv;
337 }
338
339 int _PLfuse_chmod (const char *file, mode_t mode) {
340         int rv;
341         SV *rvsv;
342         char *rvstr;
343         FUSE_CONTEXT_PRE;
344         dSP;
345         DEBUGf("chmod begin\n");
346         ENTER;
347         SAVETMPS;
348         PUSHMARK(SP);
349         XPUSHs(sv_2mortal(newSVpv(file,0)));
350         XPUSHs(sv_2mortal(newSViv(mode)));
351         PUTBACK;
352         rv = call_sv(_PLfuse_callbacks[10],G_SCALAR);
353         SPAGAIN;
354         if(rv)
355                 rv = POPi;
356         else
357                 rv = 0;
358         FREETMPS;
359         LEAVE;
360         PUTBACK;
361         DEBUGf("chmod end: %i\n",rv);
362         FUSE_CONTEXT_POST;
363         return rv;
364 }
365
366 int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
367         int rv;
368         SV *rvsv;
369         char *rvstr;
370         FUSE_CONTEXT_PRE;
371         dSP;
372         DEBUGf("chown begin\n");
373         ENTER;
374         SAVETMPS;
375         PUSHMARK(SP);
376         XPUSHs(sv_2mortal(newSVpv(file,0)));
377         XPUSHs(sv_2mortal(newSViv(uid)));
378         XPUSHs(sv_2mortal(newSViv(gid)));
379         PUTBACK;
380         rv = call_sv(_PLfuse_callbacks[11],G_SCALAR);
381         SPAGAIN;
382         if(rv)
383                 rv = POPi;
384         else
385                 rv = 0;
386         FREETMPS;
387         LEAVE;
388         PUTBACK;
389         DEBUGf("chown end: %i\n",rv);
390         FUSE_CONTEXT_POST;
391         return rv;
392 }
393
394 int _PLfuse_truncate (const char *file, off_t off) {
395         int rv;
396         SV *rvsv;
397         char *rvstr;
398         FUSE_CONTEXT_PRE;
399         dSP;
400         DEBUGf("truncate begin\n");
401         ENTER;
402         SAVETMPS;
403         PUSHMARK(SP);
404         XPUSHs(sv_2mortal(newSVpv(file,0)));
405         XPUSHs(sv_2mortal(newSViv(off)));
406         PUTBACK;
407         rv = call_sv(_PLfuse_callbacks[12],G_SCALAR);
408         SPAGAIN;
409         if(rv)
410                 rv = POPi;
411         else
412                 rv = 0;
413         FREETMPS;
414         LEAVE;
415         PUTBACK;
416         DEBUGf("truncate end: %i\n",rv);
417         FUSE_CONTEXT_POST;
418         return rv;
419 }
420
421 int _PLfuse_utime (const char *file, struct utimbuf *uti) {
422         int rv;
423         SV *rvsv;
424         char *rvstr;
425         FUSE_CONTEXT_PRE;
426         dSP;
427         DEBUGf("utime begin\n");
428         ENTER;
429         SAVETMPS;
430         PUSHMARK(SP);
431         XPUSHs(sv_2mortal(newSVpv(file,0)));
432         XPUSHs(sv_2mortal(newSViv(uti->actime)));
433         XPUSHs(sv_2mortal(newSViv(uti->modtime)));
434         PUTBACK;
435         rv = call_sv(_PLfuse_callbacks[13],G_SCALAR);
436         SPAGAIN;
437         if(rv)
438                 rv = POPi;
439         else
440                 rv = 0;
441         FREETMPS;
442         LEAVE;
443         PUTBACK;
444         DEBUGf("utime end: %i\n",rv);
445         FUSE_CONTEXT_POST;
446         return rv;
447 }
448
449 int _PLfuse_open (const char *file, int flags) {
450         int rv;
451         SV *rvsv;
452         char *rvstr;
453         FUSE_CONTEXT_PRE;
454         dSP;
455         DEBUGf("open begin\n");
456         ENTER;
457         SAVETMPS;
458         PUSHMARK(SP);
459         XPUSHs(sv_2mortal(newSVpv(file,0)));
460         XPUSHs(sv_2mortal(newSViv(flags)));
461         PUTBACK;
462         rv = call_sv(_PLfuse_callbacks[14],G_SCALAR);
463         SPAGAIN;
464         if(rv)
465                 rv = POPi;
466         else
467                 rv = 0;
468         FREETMPS;
469         LEAVE;
470         PUTBACK;
471         DEBUGf("open end: %i\n",rv);
472         FUSE_CONTEXT_POST;
473         return rv;
474 }
475
476 int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) {
477         int rv;
478         char *rvstr;
479         FUSE_CONTEXT_PRE;
480         dSP;
481         DEBUGf("read begin\n");
482         ENTER;
483         SAVETMPS;
484         PUSHMARK(SP);
485         XPUSHs(sv_2mortal(newSVpv(file,0)));
486         XPUSHs(sv_2mortal(newSViv(buflen)));
487         XPUSHs(sv_2mortal(newSViv(off)));
488         PUTBACK;
489         rv = call_sv(_PLfuse_callbacks[15],G_SCALAR);
490         SPAGAIN;
491         if(!rv)
492                 rv = -ENOENT;
493         else {
494                 SV *mysv = POPs;
495                 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
496                         rv = SvIV(mysv);
497                 else {
498                         if(SvPOK(mysv)) {
499                                 rv = SvCUR(mysv);
500                         } else {
501                                 rv = 0;
502                         }
503                         if(rv > buflen)
504                                 croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
505                         if(rv)
506                                 memcpy(buf,SvPV_nolen(mysv),rv);
507                 }
508         }
509         FREETMPS;
510         LEAVE;
511         PUTBACK;
512         DEBUGf("read end: %i\n",rv);
513         FUSE_CONTEXT_POST;
514         return rv;
515 }
516
517 int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) {
518         int rv;
519         char *rvstr;
520         FUSE_CONTEXT_PRE;
521         dSP;
522         DEBUGf("write begin\n");
523         ENTER;
524         SAVETMPS;
525         PUSHMARK(SP);
526         XPUSHs(sv_2mortal(newSVpv(file,0)));
527         XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
528         XPUSHs(sv_2mortal(newSViv(off)));
529         PUTBACK;
530         rv = call_sv(_PLfuse_callbacks[16],G_SCALAR);
531         SPAGAIN;
532         if(rv)
533                 rv = POPi;
534         else
535                 rv = 0;
536         FREETMPS;
537         LEAVE;
538         PUTBACK;
539         DEBUGf("write end: %i\n",rv);
540         FUSE_CONTEXT_POST;
541         return rv;
542 }
543
544 /* FIXME check for old fuse API (< 21?) and use statfs here */
545 #ifdef __FreeBSD__
546  #define _fuse_statvfs statfs
547 #else
548  #define _fuse_statvfs statvfs
549 #endif
550 int _PLfuse_statfs (const char *file, struct _fuse_statvfs *st) {
551
552         int rv;
553         char *rvstr;
554         FUSE_CONTEXT_PRE;
555         dSP;
556         DEBUGf("statfs begin\n");
557         ENTER;
558         SAVETMPS;
559         PUSHMARK(SP);
560         PUTBACK;
561         rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
562         SPAGAIN;
563         DEBUGf("statfs got %i params\n",rv);
564         if(rv == 6 || rv == 7) {
565                 st->f_bsize     = POPi;
566                 st->f_bfree     = POPi;
567                 st->f_blocks    = POPi;
568                 st->f_ffree     = POPi;
569                 st->f_files     = POPi;
570                 st->f_namemax   = POPi;
571 #ifndef __FreeBSD__
572                 /* zero and fill-in other */
573                 st->f_fsid = 0;
574                 st->f_frsize = 4096;
575                 st->f_flag = 0;
576                 st->f_bavail = st->f_bfree;
577                 st->f_favail = st->f_ffree;
578 #endif
579
580                 if(rv == 7)
581                         rv = POPi;
582                 else
583                         rv = 0;
584         } else
585         if(rv > 1)
586                 croak("inappropriate number of returned values from statfs");
587         else
588         if(rv)
589                 rv = POPi;
590         else
591                 rv = -ENOSYS;
592         FREETMPS;
593         LEAVE;
594         PUTBACK;
595         DEBUGf("statfs end: %i\n",rv);
596         FUSE_CONTEXT_POST;
597         return rv;
598 }
599
600 int _PLfuse_flush (const char *file) {
601         int rv;
602         char *rvstr;
603         FUSE_CONTEXT_PRE;
604         dSP;
605         DEBUGf("flush begin\n");
606         ENTER;
607         SAVETMPS;
608         PUSHMARK(SP);
609         XPUSHs(sv_2mortal(newSVpv(file,0)));
610         PUTBACK;
611         rv = call_sv(_PLfuse_callbacks[18],G_SCALAR);
612         SPAGAIN;
613         if(rv)
614                 rv = POPi;
615         else
616                 rv = 0;
617         FREETMPS;
618         LEAVE;
619         PUTBACK;
620         DEBUGf("flush end: %i\n",rv);
621         FUSE_CONTEXT_POST;
622         return rv;
623 }
624
625 int _PLfuse_release (const char *file, int flags) {
626         int rv;
627         char *rvstr;
628         FUSE_CONTEXT_PRE;
629         dSP;
630         DEBUGf("release begin\n");
631         ENTER;
632         SAVETMPS;
633         PUSHMARK(SP);
634         XPUSHs(sv_2mortal(newSVpv(file,0)));
635         XPUSHs(sv_2mortal(newSViv(flags)));
636         PUTBACK;
637         rv = call_sv(_PLfuse_callbacks[19],G_SCALAR);
638         SPAGAIN;
639         if(rv)
640                 rv = POPi;
641         else
642                 rv = 0;
643         FREETMPS;
644         LEAVE;
645         PUTBACK;
646         DEBUGf("release end: %i\n",rv);
647         FUSE_CONTEXT_POST;
648         return rv;
649 }
650
651 int _PLfuse_fsync (const char *file, int flags) {
652         int rv;
653         char *rvstr;
654         FUSE_CONTEXT_PRE;
655         dSP;
656         DEBUGf("fsync begin\n");
657         ENTER;
658         SAVETMPS;
659         PUSHMARK(SP);
660         XPUSHs(sv_2mortal(newSVpv(file,0)));
661         XPUSHs(sv_2mortal(newSViv(flags)));
662         PUTBACK;
663         rv = call_sv(_PLfuse_callbacks[20],G_SCALAR);
664         SPAGAIN;
665         if(rv)
666                 rv = POPi;
667         else
668                 rv = 0;
669         FREETMPS;
670         LEAVE;
671         PUTBACK;
672         DEBUGf("fsync end: %i\n",rv);
673         FUSE_CONTEXT_POST;
674         return rv;
675 }
676
677 int _PLfuse_setxattr (const char *file, const char *name, const char *buf, size_t buflen, int flags) {
678         int rv;
679         char *rvstr;
680         FUSE_CONTEXT_PRE;
681         dSP;
682         DEBUGf("setxattr begin\n");
683         ENTER;
684         SAVETMPS;
685         PUSHMARK(SP);
686         XPUSHs(sv_2mortal(newSVpv(file,0)));
687         XPUSHs(sv_2mortal(newSVpv(name,0)));
688         XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
689         XPUSHs(sv_2mortal(newSViv(flags)));
690         PUTBACK;
691         rv = call_sv(_PLfuse_callbacks[21],G_SCALAR);
692         SPAGAIN;
693         if(rv)
694                 rv = POPi;
695         else
696                 rv = 0;
697         FREETMPS;
698         LEAVE;
699         PUTBACK;
700         DEBUGf("setxattr end: %i\n",rv);
701         FUSE_CONTEXT_POST;
702         return rv;
703 }
704
705 int _PLfuse_getxattr (const char *file, const char *name, char *buf, size_t buflen) {
706         int rv;
707         char *rvstr;
708         FUSE_CONTEXT_PRE;
709         dSP;
710         DEBUGf("getxattr begin\n");
711         ENTER;
712         SAVETMPS;
713         PUSHMARK(SP);
714         XPUSHs(sv_2mortal(newSVpv(file,0)));
715         XPUSHs(sv_2mortal(newSVpv(name,0)));
716         PUTBACK;
717         rv = call_sv(_PLfuse_callbacks[22],G_SCALAR);
718         SPAGAIN;
719         if(!rv)
720                 rv = -ENOENT;
721         else {
722                 SV *mysv = POPs;
723
724                 rv = 0;
725                 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
726                         rv = SvIV(mysv);
727                 else {
728                         if(SvPOK(mysv)) {
729                                 rv = SvCUR(mysv);
730                         } else {
731                                 rv = 0;
732                         }
733                         if ((rv > 0) && (buflen > 0))
734                         {
735                                 if(rv > buflen)
736                                         rv = -ERANGE;
737                                 else
738                                         memcpy(buf,SvPV_nolen(mysv),rv);
739                         }
740                 }
741         }
742         FREETMPS;
743         LEAVE;
744         PUTBACK;
745         DEBUGf("getxattr end: %i\n",rv);
746         FUSE_CONTEXT_POST;
747         return rv;
748 }
749
750 int _PLfuse_listxattr (const char *file, char *list, size_t size) {
751         int prv, rv;
752         char *rvstr;
753         FUSE_CONTEXT_PRE;
754         dSP;
755         DEBUGf("listxattr begin\n");
756         ENTER;
757         SAVETMPS;
758         PUSHMARK(SP);
759         XPUSHs(sv_2mortal(newSVpv(file,0)));
760         PUTBACK;
761         prv = call_sv(_PLfuse_callbacks[23],G_ARRAY);
762         SPAGAIN;
763         if(!prv)
764                 rv = -ENOENT;
765         else {
766
767                 char *p = list;
768                 int spc = size;
769                 int total_len = 0;
770                 int i;
771
772                 rv = POPi;
773                 prv--;
774
775                 /* Always nul terminate */
776                 if (list && (size > 0))
777                         list[0] = '\0';
778
779                 while (prv > 0)
780                 {
781                         SV *mysv = POPs;
782                         prv--;
783
784                         if (SvPOK(mysv)) {
785                                 /* Copy nul too */
786                                 int s = SvCUR(mysv) + 1;
787                                 total_len += s;
788
789                                 if (p && (size > 0) && (spc >= s))
790                                 {
791                                         memcpy(p,SvPV_nolen(mysv),s);
792                                         p += s;
793                                         spc -= s;
794                                 }
795                         }
796                 }
797
798                 /*
799                  * If the Perl returned an error, return that.
800                  * Otherwise check that the buffer was big enough.
801                  */
802                 if (rv == 0)
803                 {
804                         rv = total_len;
805                         if ((size > 0) && (size < total_len))
806                                 rv = -ERANGE;
807                 }
808         }
809         FREETMPS;
810         LEAVE;
811         PUTBACK;
812         DEBUGf("listxattr end: %i\n",rv);
813         FUSE_CONTEXT_POST;
814         return rv;
815 }
816
817 int _PLfuse_removexattr (const char *file, const char *name) {
818         int rv;
819         char *rvstr;
820         FUSE_CONTEXT_PRE;
821         dSP;
822         DEBUGf("removexattr begin\n");
823         ENTER;
824         SAVETMPS;
825         PUSHMARK(SP);
826         XPUSHs(sv_2mortal(newSVpv(file,0)));
827         XPUSHs(sv_2mortal(newSVpv(name,0)));
828         PUTBACK;
829         rv = call_sv(_PLfuse_callbacks[24],G_SCALAR);
830         SPAGAIN;
831         if(rv)
832                 rv = POPi;
833         else
834                 rv = 0;
835         FREETMPS;
836         LEAVE;
837         PUTBACK;
838         DEBUGf("removexattr end: %i\n",rv);
839         FUSE_CONTEXT_POST;
840         return rv;
841 }
842
843 struct fuse_operations _available_ops = {
844 getattr:                _PLfuse_getattr,
845 readlink:               _PLfuse_readlink,
846 getdir:                 _PLfuse_getdir,
847 mknod:                  _PLfuse_mknod,
848 mkdir:                  _PLfuse_mkdir,
849 unlink:                 _PLfuse_unlink,
850 rmdir:                  _PLfuse_rmdir,
851 symlink:                _PLfuse_symlink,
852 rename:                 _PLfuse_rename,
853 link:                   _PLfuse_link,
854 chmod:                  _PLfuse_chmod,
855 chown:                  _PLfuse_chown,
856 truncate:               _PLfuse_truncate,
857 utime:                  _PLfuse_utime,
858 open:                   _PLfuse_open,
859 read:                   _PLfuse_read,
860 write:                  _PLfuse_write,
861 statfs:                 _PLfuse_statfs,
862 flush:                  _PLfuse_flush,
863 release:                _PLfuse_release,
864 fsync:                  _PLfuse_fsync,
865 setxattr:               _PLfuse_setxattr,
866 getxattr:               _PLfuse_getxattr,
867 listxattr:              _PLfuse_listxattr,
868 removexattr:            _PLfuse_removexattr,
869 };
870
871 MODULE = Fuse           PACKAGE = Fuse
872 PROTOTYPES: DISABLE
873
874 void
875 perl_fuse_main(...)
876         PREINIT:
877         struct fuse_operations fops = 
878                 {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
879                  NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
880         int i, fd, varnum = 0, debug, threaded, have_mnt;
881         char *mountpoint;
882         char *mountopts;
883         STRLEN n_a;
884         STRLEN l;
885         INIT:
886         if(items != 29) {
887                 fprintf(stderr,"Perl<->C inconsistency or internal error\n");
888                 XSRETURN_UNDEF;
889         }
890         CODE:
891         debug = SvIV(ST(0));
892         threaded = SvIV(ST(1));
893         if(threaded) {
894 #ifdef FUSE_USE_ITHREADS
895                 master_interp = PERL_GET_INTERP;
896 #else
897                 fprintf(stderr,"FUSE warning: Your script has requested multithreaded "
898                                "mode, but your perl was not built with -Dusethreads.  "
899                                "Threads are disabled.\n");
900                 threaded = 0;
901 #endif
902         }
903         mountpoint = SvPV_nolen(ST(2));
904         mountopts = SvPV_nolen(ST(3));
905         for(i=0;i<N_CALLBACKS;i++) {
906                 SV *var = ST(i+4);
907                 /* allow symbolic references, or real code references. */
908                 if(SvOK(var) && (SvPOK(var) || (SvROK(var) && SvTYPE(SvRV(var)) == SVt_PVCV))) {
909                         void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops;
910                         tmp2[i] = tmp1[i];
911 #ifdef FUSE_USE_ITHREADS
912                         if(threaded)
913                 /* note: under 5.8.7, this croaks for code references. */
914                 SvSHARE(var);
915 #endif
916                         _PLfuse_callbacks[i] = var;
917                 } else
918                 if(SvOK(var)) {
919                         croak("invalid callback passed to perl_fuse_main "
920                               "(%s is not a string, code ref, or undef).\n",
921                               i+4,SvPVbyte_nolen(var));
922                 }
923         }
924         /* FIXME: need to pass fusermount arguments */
925         fd = fuse_mount(mountpoint,mountopts);
926         if(fd < 0)
927                 croak("could not mount fuse filesystem!");
928         if(threaded) {
929                 fuse_loop_mt(fuse_new(fd,debug ? "debug" : NULL,&fops));
930         } else
931                 fuse_loop(fuse_new(fd,debug ? "debug" : NULL,&fops));