fix compilation problems
[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 SV *_PLfuse_callbacks[18];
15
16 int _PLfuse_getattr(const char *file, struct stat *result) {
17         dSP;
18         int rv, statcount;
19         ENTER;
20         SAVETMPS;
21         PUSHMARK(SP);
22         XPUSHs(sv_2mortal(newSVpv(file,strlen(file))));
23         PUTBACK;
24         rv = call_sv(_PLfuse_callbacks[0],G_ARRAY);
25         SPAGAIN;
26         if(rv != 13) {
27                 if(rv > 1) {
28                         fprintf(stderr,"inappropriate number of returned values from getattr\n");
29                         rv = -ENOSYS;
30                 } else if(rv)
31                         rv = POPi;
32                 else
33                         rv = -ENOENT;
34         } else {
35                 result->st_blksize = POPi;
36                 result->st_ctime = POPi;
37                 result->st_mtime = POPi;
38                 result->st_atime = POPi;
39                 /* What the HELL?  Perl says the blockcount is the last argument.
40                  * Everything else says the blockcount is the last argument.  So why
41                  * was it folded into the middle of the list? */
42                 result->st_blocks = POPi;
43                 result->st_size = POPi;
44                 result->st_rdev = POPi;
45                 result->st_gid = POPi;
46                 result->st_uid = POPi;
47                 result->st_nlink = POPi;
48                 result->st_mode = POPi;
49                 /*result->st_ino =*/ POPi;
50                 result->st_dev = POPi;
51                 rv = 0;
52         }
53         FREETMPS;
54         LEAVE;
55         PUTBACK;
56         return rv;
57 }
58
59 int _PLfuse_readlink(const char *file,char *buf,size_t buflen) {
60         int rv;
61         char *rvstr;
62         dSP;
63         I32 ax;
64         if(buflen < 1)
65                 return EINVAL;
66         ENTER;
67         SAVETMPS;
68         PUSHMARK(SP);
69         XPUSHs(sv_2mortal(newSVpv(file,0)));
70         PUTBACK;
71         rv = call_sv(_PLfuse_callbacks[1],G_SCALAR);
72         SPAGAIN;
73         if(!rv)
74                 rv = -ENOENT;
75         else {
76                 SV *mysv = POPs;
77                 if(SvTYPE(mysv) == SVt_IV || SvTYPE(mysv) == SVt_NV)
78                         rv = SvIV(mysv);
79                 else {
80                         strncpy(buf,SvPV_nolen(mysv),buflen);
81                         rv = 0;
82                 }
83         }
84         FREETMPS;
85         LEAVE;
86         buf[buflen-1] = 0;
87         PUTBACK;
88         return rv;
89 }
90
91 int _PLfuse_getdir(const char *file, fuse_dirh_t dirh, fuse_dirfil_t dirfil) {
92         int prv, rv;
93         dSP;
94         ENTER;
95         SAVETMPS;
96         PUSHMARK(SP);
97         XPUSHs(sv_2mortal(newSVpv(file,0)));
98         PUTBACK;
99         prv = call_sv(_PLfuse_callbacks[2],G_ARRAY);
100         SPAGAIN;
101         if(prv) {
102                 rv = POPi;
103                 while(--prv)
104                         dirfil(dirh,POPp,0,0);
105         } else {
106                 fprintf(stderr,"getdir() handler returned nothing!\n");
107                 rv = -ENOSYS;
108         }
109         FREETMPS;
110         LEAVE;
111         PUTBACK;
112         return rv;
113 }
114
115 int _PLfuse_mknod (const char *file, mode_t mode, dev_t dev) {
116         int rv;
117         SV *rvsv;
118         char *rvstr;
119         dSP;
120         ENTER;
121         SAVETMPS;
122         PUSHMARK(SP);
123         XPUSHs(sv_2mortal(newSVpv(file,0)));
124         XPUSHs(sv_2mortal(newSViv(mode)));
125         XPUSHs(sv_2mortal(newSViv(dev)));
126         PUTBACK;
127         rv = call_sv(_PLfuse_callbacks[3],G_SCALAR);
128         SPAGAIN;
129         if(rv)
130                 rv = POPi;
131         else
132                 rv = 0;
133         FREETMPS;
134         LEAVE;
135         PUTBACK;
136         return rv;
137 }
138
139 int _PLfuse_mkdir (const char *file, mode_t mode) {
140         int rv;
141         SV *rvsv;
142         char *rvstr;
143         dSP;
144         DEBUGf("mkdir begin: %i\n",sp-PL_stack_base);
145         ENTER;
146         SAVETMPS;
147         PUSHMARK(SP);
148         XPUSHs(sv_2mortal(newSVpv(file,0)));
149         XPUSHs(sv_2mortal(newSViv(mode)));
150         PUTBACK;
151         rv = call_sv(_PLfuse_callbacks[4],G_SCALAR);
152         SPAGAIN;
153         if(rv)
154                 rv = POPi;
155         else
156                 rv = 0;
157         FREETMPS;
158         LEAVE;
159         PUTBACK;
160         DEBUGf("mkdir end: %i %i\n",sp-PL_stack_base,rv);
161         return rv;
162 }
163
164
165 int _PLfuse_unlink (const char *file) {
166         int rv;
167         SV *rvsv;
168         char *rvstr;
169         dSP;
170         DEBUGf("unlink begin: %i\n",sp-PL_stack_base);
171         ENTER;
172         SAVETMPS;
173         PUSHMARK(SP);
174         XPUSHs(sv_2mortal(newSVpv(file,0)));
175         PUTBACK;
176         rv = call_sv(_PLfuse_callbacks[5],G_SCALAR);
177         SPAGAIN;
178         if(rv)
179                 rv = POPi;
180         else
181                 rv = 0;
182         FREETMPS;
183         LEAVE;
184         PUTBACK;
185         DEBUGf("unlink end: %i\n",sp-PL_stack_base);
186         return rv;
187 }
188
189 int _PLfuse_rmdir (const char *file) {
190         int rv;
191         SV *rvsv;
192         char *rvstr;
193         dSP;
194         DEBUGf("rmdir begin: %i\n",sp-PL_stack_base);
195         ENTER;
196         SAVETMPS;
197         PUSHMARK(SP);
198         XPUSHs(sv_2mortal(newSVpv(file,0)));
199         PUTBACK;
200         rv = call_sv(_PLfuse_callbacks[6],G_SCALAR);
201         SPAGAIN;
202         if(rv)
203                 rv = POPi;
204         else
205                 rv = 0;
206         FREETMPS;
207         LEAVE;
208         PUTBACK;
209         DEBUGf("rmdir end: %i %i\n",sp-PL_stack_base,rv);
210         return rv;
211 }
212
213 int _PLfuse_symlink (const char *file, const char *new) {
214         int rv;
215         SV *rvsv;
216         char *rvstr;
217         dSP;
218         DEBUGf("symlink begin: %i\n",sp-PL_stack_base);
219         ENTER;
220         SAVETMPS;
221         PUSHMARK(SP);
222         XPUSHs(sv_2mortal(newSVpv(file,0)));
223         XPUSHs(sv_2mortal(newSVpv(new,0)));
224         PUTBACK;
225         rv = call_sv(_PLfuse_callbacks[7],G_SCALAR);
226         SPAGAIN;
227         if(rv)
228                 rv = POPi;
229         else
230                 rv = 0;
231         FREETMPS;
232         LEAVE;
233         PUTBACK;
234         DEBUGf("symlink end: %i\n",sp-PL_stack_base);
235         return rv;
236 }
237
238 int _PLfuse_rename (const char *file, const char *new) {
239         int rv;
240         SV *rvsv;
241         char *rvstr;
242         dSP;
243         DEBUGf("rename begin: %i\n",sp-PL_stack_base);
244         ENTER;
245         SAVETMPS;
246         PUSHMARK(SP);
247         XPUSHs(sv_2mortal(newSVpv(file,0)));
248         XPUSHs(sv_2mortal(newSVpv(new,0)));
249         PUTBACK;
250         rv = call_sv(_PLfuse_callbacks[8],G_SCALAR);
251         SPAGAIN;
252         if(rv)
253                 rv = POPi;
254         else
255                 rv = 0;
256         FREETMPS;
257         LEAVE;
258         PUTBACK;
259         DEBUGf("rename end: %i\n",sp-PL_stack_base);
260         return rv;
261 }
262
263 int _PLfuse_link (const char *file, const char *new) {
264         int rv;
265         SV *rvsv;
266         char *rvstr;
267         dSP;
268         DEBUGf("link begin: %i\n",sp-PL_stack_base);
269         ENTER;
270         SAVETMPS;
271         PUSHMARK(SP);
272         XPUSHs(sv_2mortal(newSVpv(file,0)));
273         XPUSHs(sv_2mortal(newSVpv(new,0)));
274         PUTBACK;
275         rv = call_sv(_PLfuse_callbacks[9],G_SCALAR);
276         SPAGAIN;
277         if(rv)
278                 rv = POPi;
279         else
280                 rv = 0;
281         FREETMPS;
282         LEAVE;
283         PUTBACK;
284         DEBUGf("link end: %i\n",sp-PL_stack_base);
285         return rv;
286 }
287
288 int _PLfuse_chmod (const char *file, mode_t mode) {
289         int rv;
290         SV *rvsv;
291         char *rvstr;
292         dSP;
293         DEBUGf("chmod begin: %i\n",sp-PL_stack_base);
294         ENTER;
295         SAVETMPS;
296         PUSHMARK(SP);
297         XPUSHs(sv_2mortal(newSVpv(file,0)));
298         XPUSHs(sv_2mortal(newSViv(mode)));
299         PUTBACK;
300         rv = call_sv(_PLfuse_callbacks[10],G_SCALAR);
301         SPAGAIN;
302         if(rv)
303                 rv = POPi;
304         else
305                 rv = 0;
306         FREETMPS;
307         LEAVE;
308         PUTBACK;
309         DEBUGf("chmod end: %i\n",sp-PL_stack_base);
310         return rv;
311 }
312
313 int _PLfuse_chown (const char *file, uid_t uid, gid_t gid) {
314         int rv;
315         SV *rvsv;
316         char *rvstr;
317         dSP;
318         DEBUGf("chown begin: %i\n",sp-PL_stack_base);
319         ENTER;
320         SAVETMPS;
321         PUSHMARK(SP);
322         XPUSHs(sv_2mortal(newSVpv(file,0)));
323         XPUSHs(sv_2mortal(newSViv(uid)));
324         XPUSHs(sv_2mortal(newSViv(gid)));
325         PUTBACK;
326         rv = call_sv(_PLfuse_callbacks[11],G_SCALAR);
327         SPAGAIN;
328         if(rv)
329                 rv = POPi;
330         else
331                 rv = 0;
332         FREETMPS;
333         LEAVE;
334         PUTBACK;
335         DEBUGf("chown end: %i\n",sp-PL_stack_base);
336         return rv;
337 }
338
339 int _PLfuse_truncate (const char *file, off_t off) {
340         int rv;
341         SV *rvsv;
342         char *rvstr;
343         dSP;
344         DEBUGf("truncate begin: %i\n",sp-PL_stack_base);
345         ENTER;
346         SAVETMPS;
347         PUSHMARK(SP);
348         XPUSHs(sv_2mortal(newSVpv(file,0)));
349         XPUSHs(sv_2mortal(newSViv(off)));
350         PUTBACK;
351         rv = call_sv(_PLfuse_callbacks[12],G_SCALAR);
352         SPAGAIN;
353         if(rv)
354                 rv = POPi;
355         else
356                 rv = 0;
357         FREETMPS;
358         LEAVE;
359         PUTBACK;
360         DEBUGf("truncate end: %i\n",sp-PL_stack_base);
361         return rv;
362 }
363
364 int _PLfuse_utime (const char *file, struct utimbuf *uti) {
365         int rv;
366         SV *rvsv;
367         char *rvstr;
368         dSP;
369         DEBUGf("utime begin: %i\n",sp-PL_stack_base);
370         ENTER;
371         SAVETMPS;
372         PUSHMARK(SP);
373         XPUSHs(sv_2mortal(newSVpv(file,0)));
374         XPUSHs(sv_2mortal(newSViv(uti->actime)));
375         XPUSHs(sv_2mortal(newSViv(uti->modtime)));
376         PUTBACK;
377         rv = call_sv(_PLfuse_callbacks[13],G_SCALAR);
378         SPAGAIN;
379         if(rv)
380                 rv = POPi;
381         else
382                 rv = 0;
383         FREETMPS;
384         LEAVE;
385         PUTBACK;
386         DEBUGf("utime end: %i\n",sp-PL_stack_base);
387         return rv;
388 }
389
390 int _PLfuse_open (const char *file, int flags) {
391         int rv;
392         SV *rvsv;
393         char *rvstr;
394         dSP;
395         DEBUGf("open begin: %i\n",sp-PL_stack_base);
396         ENTER;
397         SAVETMPS;
398         PUSHMARK(SP);
399         XPUSHs(sv_2mortal(newSVpv(file,0)));
400         XPUSHs(sv_2mortal(newSViv(flags)));
401         PUTBACK;
402         rv = call_sv(_PLfuse_callbacks[14],G_SCALAR);
403         SPAGAIN;
404         if(rv)
405                 rv = POPi;
406         else
407                 rv = 0;
408         FREETMPS;
409         LEAVE;
410         PUTBACK;
411         DEBUGf("open end: %i %i\n",sp-PL_stack_base,rv);
412         return rv;
413 }
414
415 int _PLfuse_read (const char *file, char *buf, size_t buflen, off_t off) {
416         int rv;
417         char *rvstr;
418         dSP;
419         DEBUGf("read begin: %i\n",sp-PL_stack_base);
420         ENTER;
421         SAVETMPS;
422         PUSHMARK(SP);
423         XPUSHs(sv_2mortal(newSVpv(file,0)));
424         XPUSHs(sv_2mortal(newSViv(buflen)));
425         XPUSHs(sv_2mortal(newSViv(off)));
426         PUTBACK;
427         rv = call_sv(_PLfuse_callbacks[15],G_SCALAR);
428         SPAGAIN;
429         if(!rv)
430                 rv = -ENOENT;
431         else {
432                 SV *mysv = POPs;
433                 if(SvTYPE(mysv) == SVt_NV || SvTYPE(mysv) == SVt_IV)
434                         rv = SvIV(mysv);
435                 else {
436                         if(SvPOK(mysv)) {
437                                 rv = SvCUR(mysv);
438                         } else {
439                                 rv = 0;
440                         }
441                         if(rv > buflen)
442                                 croak("read() handler returned more than buflen! (%i > %i)",rv,buflen);
443                         if(rv)
444                                 memcpy(buf,SvPV_nolen(mysv),rv);
445                 }
446         }
447         FREETMPS;
448         LEAVE;
449         PUTBACK;
450         DEBUGf("read end: %i %i\n",sp-PL_stack_base,rv);
451         return rv;
452 }
453
454 int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) {
455         int rv;
456         char *rvstr;
457         dSP;
458         DEBUGf("write begin: %i\n",sp-PL_stack_base);
459         ENTER;
460         SAVETMPS;
461         PUSHMARK(SP);
462         XPUSHs(sv_2mortal(newSVpv(file,0)));
463         XPUSHs(sv_2mortal(newSVpvn(buf,buflen)));
464         XPUSHs(sv_2mortal(newSViv(off)));
465         PUTBACK;
466         rv = call_sv(_PLfuse_callbacks[16],G_SCALAR);
467         SPAGAIN;
468         if(rv)
469                 rv = POPi;
470         else
471                 rv = 0;
472         FREETMPS;
473         LEAVE;
474         PUTBACK;
475         DEBUGf("write end: %i\n",sp-PL_stack_base);
476         return rv;
477 }
478
479 int _PLfuse_statfs (const char *file, struct statfs *st) {
480         int rv;
481         char *rvstr;
482         dSP;
483         DEBUGf("statfs begin: %i\n",sp-PL_stack_base);
484         ENTER;
485         SAVETMPS;
486         PUSHMARK(SP);
487         PUTBACK;
488         rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
489         SPAGAIN;
490         if(rv > 5) {
491                 st->f_bsize    = POPi;
492                 st->f_bfree    = POPi;
493                 st->f_blocks   = POPi;
494                 st->f_ffree    = POPi;
495                 st->f_files    = POPi;
496                 st->f_namelen  = POPi;
497                 if(rv > 6)
498                         rv = POPi;
499                 else
500                         rv = 0;
501         } else
502         if(rv > 1)
503                 croak("inappropriate number of returned values from statfs");
504         else
505         if(rv)
506                 rv = POPi;
507         else
508                 rv = -ENOSYS;
509         FREETMPS;
510         LEAVE;
511         PUTBACK;
512         DEBUGf("statfs end: %i\n",sp-PL_stack_base);
513         return rv;
514 }
515
516 struct fuse_operations _available_ops = {
517 getattr:        _PLfuse_getattr,
518                         _PLfuse_readlink,
519                         _PLfuse_getdir,
520                         _PLfuse_mknod,
521                         _PLfuse_mkdir,
522                         _PLfuse_unlink,
523                         _PLfuse_rmdir,
524                         _PLfuse_symlink,
525                         _PLfuse_rename,
526                         _PLfuse_link,
527                         _PLfuse_chmod,
528                         _PLfuse_chown,
529                         _PLfuse_truncate,
530                         _PLfuse_utime,
531                         _PLfuse_open,
532                         _PLfuse_read,
533                         _PLfuse_write,
534                         _PLfuse_statfs
535 };
536
537 MODULE = Fuse           PACKAGE = Fuse
538 PROTOTYPES: DISABLE
539
540 void
541 perl_fuse_main(...)
542         PREINIT:
543         struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
544         int i, fd, varnum = 0, debug, have_mnt;
545         char *mountpoint;
546         STRLEN n_a;
547         STRLEN l;
548         INIT:
549         if(items != 20) {
550                 fprintf(stderr,"Perl<->C inconsistency or internal error\n");
551                 XSRETURN_UNDEF;
552         }
553         CODE:
554         debug = SvIV(ST(0));
555         mountpoint = SvPV_nolen(ST(1));
556         /* FIXME: reevaluate multithreading support when perl6 arrives */
557         for(i=0;i<18;i++) {
558                 SV *var = ST(i+2);
559                 if((var != &PL_sv_undef) && SvROK(var)) {
560                         if(SvTYPE(SvRV(var)) == SVt_PVCV) {
561                                 void **tmp1 = (void**)&_available_ops, **tmp2 = (void**)&fops;
562                                 tmp2[i] = tmp1[i];
563                                 _PLfuse_callbacks[i] = var;
564                         } else
565                                 croak("arg is not a code reference!");
566                 }
567         }
568         /* FIXME: need to pass fusermount arguments */
569         fd = fuse_mount(mountpoint,NULL);
570         if(fd < 0)
571                 croak("could not mount fuse filesystem!");
572         fuse_loop(fuse_new(fd,debug ? "debug" : NULL,&fops));