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