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