rfuse 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/rfuse/rfuse.c ADDED
@@ -0,0 +1,2045 @@
1
+ #ifdef linux
2
+ /* For pread()/pwrite() */
3
+ #define _XOPEN_SOURCE 500
4
+ #endif
5
+ //FOR LINUX ONLY
6
+ #include <linux/stat.h>
7
+ #include <linux/kdev_t.h>
8
+
9
+ #include <ruby.h>
10
+ #include <fuse.h>
11
+ #include <errno.h>
12
+ #include <sys/statfs.h>
13
+ //#ifdef HAVE_SETXATTR
14
+ #include <sys/xattr.h>
15
+ //#endif
16
+
17
+ #include <ruby/encoding.h>
18
+ #include "helper.h"
19
+ #include "intern_rfuse.h"
20
+ #include "filler.h"
21
+ #include "context.h"
22
+
23
+ #include "file_info.h"
24
+ #include "pollhandle.h"
25
+ #include "bufferwrapper.h"
26
+
27
+
28
+ static VALUE mRFuse;
29
+ static VALUE eRFuse_Error;
30
+
31
+ static int unsafe_return_error(VALUE *args)
32
+ {
33
+
34
+ if (rb_respond_to(rb_errinfo(),rb_intern("errno"))) {
35
+ //We expect these and they get passed on the fuse so be quiet...
36
+ return rb_funcall(rb_errinfo(),rb_intern("errno"),0);
37
+ } else {
38
+ VALUE info;
39
+ info = rb_inspect(rb_errinfo());
40
+ printf ("ERROR: Exception %s not an Errno:: !respond_to?(:errno) \n",STR2CSTR(info));
41
+ //We need the ruby_errinfo backtrace not fuse.loop ... rb_backtrace();
42
+ VALUE bt_ary = rb_funcall(rb_errinfo(), rb_intern("backtrace"),0);
43
+ int c;
44
+ for (c=0;c<RARRAY_LEN(bt_ary);c++) {
45
+ printf("%s\n",RSTRING_PTR(RARRAY_PTR(bt_ary)[c]));
46
+ }
47
+ return Qnil;
48
+ }
49
+ }
50
+
51
+ static int return_error(int def_error)
52
+ {
53
+ /*if the raised error has a method errno the return that value else
54
+ return def(ault)_error */
55
+ VALUE res;
56
+ int error = 0;
57
+ res=rb_protect((VALUE (*)())unsafe_return_error,Qnil,&error);
58
+ if (error)
59
+ {
60
+ //something went wrong resolving the exception
61
+ printf ("ERROR: Exception in exception!\n");
62
+ return def_error;
63
+ }
64
+ else
65
+ {
66
+ return NIL_P(res) ? def_error : FIX2INT(res);
67
+ }
68
+ }
69
+
70
+ //Every call needs this stuff
71
+ static void init_context_path_args(VALUE *args,struct fuse_context *ctx,const char *path)
72
+ {
73
+ args[0] = ctx->private_data;
74
+ args[1] = wrap_context(ctx);
75
+ args[2] = rb_str_new2(path);
76
+ rb_enc_associate(args[2],rb_filesystem_encoding());
77
+ }
78
+ /*
79
+ @overload readdir(context,path,filler,offset,ffi)
80
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#0f634deda31d1e1c42664585ae820076 readdir}
81
+
82
+ List contents of a directory
83
+
84
+ @param [Context] context
85
+ @param [String] path
86
+ @param [Filler] filler
87
+ @param [Fixnum] offset
88
+ @param [FileInfo] ffi
89
+
90
+ @return [void]
91
+ @raise [Errno]
92
+ */
93
+ static VALUE unsafe_readdir(VALUE *args)
94
+ {
95
+ return rb_funcall3(args[0],rb_intern("readdir"),5,&args[1]);
96
+ }
97
+
98
+ static int rf_readdir(const char *path, void *buf,
99
+ fuse_fill_dir_t filler, off_t offset,struct fuse_file_info *ffi)
100
+ {
101
+ VALUE fuse_module;
102
+ VALUE rfiller_class;
103
+ VALUE rfiller_instance;
104
+ struct filler_t *fillerc;
105
+ VALUE args[6];
106
+ VALUE res;
107
+ int error = 0;
108
+
109
+ struct fuse_context *ctx=fuse_get_context();
110
+ init_context_path_args(args,ctx,path);
111
+
112
+ //create a filler object
113
+ fuse_module = rb_const_get(rb_cObject, rb_intern("RFuse"));
114
+ rfiller_class=rb_const_get(fuse_module,rb_intern("Filler"));
115
+ rfiller_instance=rb_funcall(rfiller_class,rb_intern("new"),0);
116
+ Data_Get_Struct(rfiller_instance,struct filler_t,fillerc);
117
+
118
+ fillerc->filler=filler;//Init the filler by hand.... TODO: cleaner
119
+ fillerc->buffer=buf;
120
+ args[3]=rfiller_instance;
121
+ args[4]=INT2NUM(offset);
122
+ args[5]=get_file_info(ffi);
123
+
124
+ res=rb_protect((VALUE (*)())unsafe_readdir,(VALUE)args,&error);
125
+ return error ? -(return_error(ENOENT)) : 0 ;
126
+ }
127
+
128
+ /*
129
+ Resolve target of symbolic link
130
+ @overload readlink(context,path,size)
131
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#b4ce6e6d69dfde3ec550f22d932c5633 readlink}
132
+ @param [Context] context
133
+ @param [String] path
134
+ @param [Integer] size if the resolved path is greater than this size it should be truncated
135
+
136
+ @return [String] the resolved link path
137
+ @raise [Errno]
138
+ */
139
+ static VALUE unsafe_readlink(VALUE *args)
140
+ {
141
+ return rb_funcall3(args[0],rb_intern("readlink"),3,&args[1]);
142
+ }
143
+
144
+ static int rf_readlink(const char *path, char *buf, size_t size)
145
+ {
146
+ VALUE args[4];
147
+ VALUE res;
148
+ int error = 0;
149
+
150
+ struct fuse_context *ctx=fuse_get_context();
151
+ init_context_path_args(args,ctx,path);
152
+
153
+ args[3]=INT2NUM(size);
154
+ char *rbuf;
155
+ res=rb_protect((VALUE (*)())unsafe_readlink,(VALUE)args,&error);
156
+ if (error)
157
+ {
158
+ return -(return_error(ENOENT));
159
+ }
160
+ else
161
+ {
162
+ rbuf=STR2CSTR(res);
163
+ strncpy(buf,rbuf,size);
164
+ return 0;
165
+ }
166
+ }
167
+
168
+ /*
169
+ @deprecated see {#readdir}
170
+ @abstract Fuse operation getdir
171
+ */
172
+ static VALUE unsafe_getdir(VALUE *args)
173
+ {
174
+ return rb_funcall3(args[0],rb_intern("getdir"),3,&args[1]);
175
+ }
176
+
177
+ //call getdir with an Filler object
178
+ static int rf_getdir(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
179
+ {
180
+ VALUE fuse_module;
181
+ VALUE rfiller_class;
182
+ VALUE rfiller_instance;
183
+ VALUE args[4];
184
+ VALUE res;
185
+ struct filler_t *fillerc;
186
+ int error = 0;
187
+
188
+ struct fuse_context *ctx=fuse_get_context();
189
+ init_context_path_args(args,ctx,path);
190
+
191
+ //create a filler object
192
+ fuse_module = rb_const_get(rb_cObject, rb_intern("RFuse"));
193
+ rfiller_class = rb_const_get(fuse_module,rb_intern("Filler"));
194
+ rfiller_instance = rb_funcall(rfiller_class,rb_intern("new"),0);
195
+
196
+ Data_Get_Struct(rfiller_instance,struct filler_t,fillerc);
197
+
198
+ fillerc->df = df;
199
+ fillerc->dh = dh;
200
+
201
+ args[3]=rfiller_instance;
202
+
203
+ res = rb_protect((VALUE (*)())unsafe_getdir, (VALUE)args, &error);
204
+
205
+ return error ? -(return_error(ENOENT)) : 0 ;
206
+ }
207
+
208
+ /*
209
+ Create a file node
210
+ @overload mknod(context,path,mode,major,minor)
211
+ @abstract Fuse Operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1465eb2268cec2bb5ed11cb09bbda42f mknod}
212
+
213
+ @param [Context] context
214
+ @param [String] path
215
+ @param [Integer] mode type & permissions
216
+ @param [Integer] major
217
+ @param [Integer] minor
218
+
219
+ @return[void]
220
+
221
+ This is called for creation of all non-directory, non-symlink nodes. If the filesystem defines {#create}, then for regular files that will be called instead.
222
+
223
+ */
224
+ static VALUE unsafe_mknod(VALUE *args)
225
+ {
226
+ return rb_funcall3(args[0],rb_intern("mknod"),5,&args[1]);
227
+ }
228
+
229
+ static int rf_mknod(const char *path, mode_t mode,dev_t dev)
230
+ {
231
+ VALUE args[6];
232
+ VALUE res;
233
+ int error = 0;
234
+ struct fuse_context *ctx=fuse_get_context();
235
+ init_context_path_args(args,ctx,path);
236
+
237
+ int major;
238
+ int minor;
239
+
240
+ major = MAJOR(dev);
241
+ minor = MINOR(dev);
242
+
243
+ args[3]=INT2FIX(mode);
244
+ args[4]=INT2FIX(major);
245
+ args[5]=INT2FIX(minor);
246
+ res=rb_protect((VALUE (*)())unsafe_mknod,(VALUE) args,&error);
247
+ return error ? -(return_error(ENOENT)) : 0 ;
248
+ }
249
+
250
+ /*
251
+ Get file attributes.
252
+ @overload getattr(context,path)
253
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#7a4c5d8eaf7179d819618c0cf3f73724 getattr}
254
+ @param [Context] context
255
+ @param [String] path
256
+
257
+ @return [Stat] or something that quacks like a stat, or nil if the path does not exist
258
+ @raise [Errno]
259
+
260
+ Similar to stat(). The 'st_dev' and 'st_blksize' fields are ignored. The 'st_ino' field is ignored except if the 'use_ino' mount option is given.
261
+ */
262
+ static VALUE unsafe_getattr(VALUE *args)
263
+ {
264
+ return rb_funcall3(args[0],rb_intern("getattr"),2,&args[1]);
265
+ }
266
+
267
+ //calls getattr with path and expects something like FuseStat back
268
+ static int rf_getattr(const char *path, struct stat *stbuf)
269
+ {
270
+ VALUE args[3];
271
+ VALUE res;
272
+ int error = 0;
273
+ struct fuse_context *ctx=fuse_get_context();
274
+ init_context_path_args(args,ctx,path);
275
+
276
+ res=rb_protect((VALUE (*)())unsafe_getattr,(VALUE) args,&error);
277
+
278
+ if (res == Qnil) {
279
+ return -ENOENT;
280
+ }
281
+ if (error)
282
+ {
283
+ return -(return_error(ENOENT));
284
+ }
285
+ else
286
+ {
287
+ rstat2stat(res,stbuf);
288
+ return 0;
289
+ }
290
+ }
291
+
292
+ /*
293
+ Create a directory
294
+
295
+ @overload mkdir(context,path,mode)
296
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#0a38aa6ca60e945772d5d21b0c1c8916 mkdir}
297
+
298
+ @param [Context] context
299
+ @param [String] path
300
+ @param [Integer] mode to obtain correct directory permissions use mode | {Stat.S_IFDIR}
301
+
302
+ @return [void]
303
+ @raise [Errno]
304
+
305
+ */
306
+ static VALUE unsafe_mkdir(VALUE *args)
307
+ {
308
+ return rb_funcall3(args[0],rb_intern("mkdir"),3,&args[1]);
309
+ }
310
+
311
+ static int rf_mkdir(const char *path, mode_t mode)
312
+ {
313
+ VALUE args[4];
314
+ VALUE res;
315
+ int error = 0;
316
+
317
+ struct fuse_context *ctx=fuse_get_context();
318
+ init_context_path_args(args,ctx,path);
319
+
320
+ args[3]=INT2FIX(mode);
321
+ res=rb_protect((VALUE (*)())unsafe_mkdir,(VALUE) args,&error);
322
+
323
+ if (error)
324
+ {
325
+ return -(return_error(ENOENT));
326
+ }
327
+ else
328
+ {
329
+ return 0;
330
+ }
331
+ }
332
+
333
+ /*
334
+ File open operation
335
+
336
+ @overload open(context,path,ffi)
337
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#14b98c3f7ab97cc2ef8f9b1d9dc0709d open}
338
+ @param [Context] context
339
+ @param [String] path
340
+ @param [FileInfo] ffi
341
+ file open flags etc.
342
+ The fh attribute may be used to store an arbitrary filehandle object which will be passed to all subsequent operations on this file
343
+
344
+ @raise [Errno::ENOPERM] if user is not permitted to open the file
345
+ @raise [Errno] for other errors
346
+
347
+ @return [void]
348
+ */
349
+ static VALUE unsafe_open(VALUE *args)
350
+ {
351
+ return rb_funcall3(args[0],rb_intern("open"),3,&args[1]);
352
+ }
353
+
354
+ static int rf_open(const char *path,struct fuse_file_info *ffi)
355
+ {
356
+ VALUE args[4];
357
+ VALUE res;
358
+ int error = 0;
359
+
360
+ struct fuse_context *ctx=fuse_get_context();
361
+ init_context_path_args(args,ctx,path);
362
+
363
+ args[3]=wrap_file_info(ctx,ffi);
364
+
365
+ res=rb_protect((VALUE (*)())unsafe_open,(VALUE) args,&error);
366
+ if (error)
367
+ {
368
+ return -(return_error(ENOENT));
369
+ }
370
+ else
371
+ {
372
+ return 0;
373
+ }
374
+ }
375
+
376
+ //This method is registered as a default for release in the case when
377
+ //open/create are defined, but a specific release method is not.
378
+ //similarly for opendir/releasedir
379
+ static int rf_release_ffi(const char *path, struct fuse_file_info *ffi)
380
+ {
381
+ struct fuse_context *ctx=fuse_get_context();
382
+
383
+ release_file_info(ctx,ffi);
384
+
385
+ }
386
+
387
+ /*
388
+ Release an open file
389
+
390
+ @overload release(context,path,ffi)
391
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#bac8718cdfc1ee273a44831a27393419 release}
392
+ @param [Context] context
393
+ @param [String] path
394
+ @param [FileInfo] ffi
395
+
396
+ @return [void]
397
+
398
+ Release is called when there are no more references to an open file: all file descriptors are closed and all memory mappings are unmapped.
399
+
400
+ For every {#open} call there will be exactly one {#release} call with the same flags and file descriptor. It is possible to have a file opened more than once, in which case only the last release will mean, that no more reads/writes will happen on the file.
401
+ */
402
+ static VALUE unsafe_release(VALUE *args)
403
+ {
404
+ return rb_funcall3(args[0],rb_intern("release"),3,&args[1]);
405
+ }
406
+
407
+ static int rf_release(const char *path, struct fuse_file_info *ffi)
408
+ {
409
+ VALUE args[4];
410
+ VALUE res;
411
+ int error = 0;
412
+
413
+ struct fuse_context *ctx=fuse_get_context();
414
+ init_context_path_args(args,ctx,path);
415
+
416
+ args[3]=release_file_info(ctx,ffi);
417
+
418
+ res=rb_protect((VALUE (*)())unsafe_release,(VALUE) args,&error);
419
+
420
+ if (error)
421
+ {
422
+ return -(return_error(ENOENT));
423
+ }
424
+ else
425
+ {
426
+ return 0;
427
+ }
428
+ }
429
+
430
+ /*
431
+ Synchronize file contents
432
+
433
+ @overload fsync(context,path,datasync,ffi)
434
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#92bdd6f43ba390a54ac360541c56b528 fsync}
435
+
436
+ @param [Context] context
437
+ @param [String] path
438
+ @param [Integer] datasync if non-zero, then only user data should be flushed, not the metadata
439
+ @param [FileInfo] ffi
440
+
441
+ @return [void]
442
+ @raise [Errno]
443
+ */
444
+ static VALUE unsafe_fsync(VALUE *args) {
445
+ return rb_funcall3(args[0],rb_intern("fsync"),4,&args[1]);
446
+ }
447
+
448
+ static int rf_fsync(const char *path, int datasync, struct fuse_file_info *ffi)
449
+ {
450
+ VALUE args[5];
451
+ VALUE res;
452
+ int error = 0;
453
+
454
+ struct fuse_context *ctx=fuse_get_context();
455
+ init_context_path_args(args,ctx,path);
456
+
457
+ args[3] = INT2NUM(datasync);
458
+ args[4] = get_file_info(ffi);
459
+
460
+ res = rb_protect((VALUE (*)())unsafe_fsync,(VALUE) args,&error);
461
+
462
+ if (error)
463
+ {
464
+ return -(return_error(ENOENT));
465
+ }
466
+ else
467
+ {
468
+ return 0;
469
+ }
470
+ }
471
+
472
+
473
+
474
+ /*
475
+ Possibly flush cached data
476
+
477
+ @overload flush(context,path,ffi)
478
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#d4ec9c309072a92dd82ddb20efa4ab14 flush}
479
+
480
+ @param [Context] context
481
+ @param [String] path
482
+ @param [FileInfo] ffi
483
+
484
+ @return [void]
485
+ @raise [Errno]
486
+
487
+ BIG NOTE: This is not equivalent to fsync(). It's not a request to sync dirty data.
488
+
489
+ Flush is called on each close() of a file descriptor. So if a filesystem wants to return write errors in close() and the file has cached dirty data, this is a good place to write back data and return any errors. Since many applications ignore close() errors this is not always useful.
490
+
491
+ NOTE: The flush() method may be called more than once for each open(). This happens if more than one file descriptor refers to an opened file due to dup(), dup2() or fork() calls. It is not possible to determine if a flush is final, so each flush should be treated equally. Multiple write-flush sequences are relatively rare, so this shouldn't be a problem.
492
+
493
+ Filesystems shouldn't assume that flush will always be called after some writes, or that if will be called at all.
494
+ */
495
+ static VALUE unsafe_flush(VALUE *args)
496
+ {
497
+ return rb_funcall3(args[0],rb_intern("flush"),3,&args[1]);
498
+ }
499
+
500
+ static int rf_flush(const char *path,struct fuse_file_info *ffi)
501
+ {
502
+ VALUE args[4];
503
+ VALUE res;
504
+ int error = 0;
505
+ struct fuse_context *ctx=fuse_get_context();
506
+ init_context_path_args(args,ctx,path);
507
+ args[3]=get_file_info(ffi);
508
+ res=rb_protect((VALUE (*)())unsafe_flush,(VALUE) args,&error);
509
+
510
+ return error ? -(return_error(ENOENT)) : 0;
511
+ }
512
+
513
+ /*
514
+ Change the size of a file
515
+
516
+ @overload truncate(context,path,offset)
517
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#8efb50b9cd975ba8c4c450248caff6ed truncate}
518
+
519
+ @param [Context] context
520
+ @param [String] path
521
+ @param [Integer] offset
522
+
523
+ @return [void]
524
+ @raise [Errno]
525
+ */
526
+ static VALUE unsafe_truncate(VALUE *args)
527
+ {
528
+ return rb_funcall3(args[0],rb_intern("truncate"),3,&args[1]);
529
+ }
530
+
531
+ static int rf_truncate(const char *path,off_t offset)
532
+ {
533
+ VALUE args[4];
534
+ VALUE res;
535
+ int error = 0;
536
+ struct fuse_context *ctx=fuse_get_context();
537
+ init_context_path_args(args,ctx,path);
538
+ args[3]=INT2FIX(offset);
539
+ res=rb_protect((VALUE (*)())unsafe_truncate,(VALUE) args,&error);
540
+
541
+ return error ? -(return_error(ENOENT)) : 0;
542
+ }
543
+
544
+
545
+ /*
546
+ Change access/modification times of a file
547
+
548
+ @overload utime(context,path,actime,modtime)
549
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#cb7452acad1002d418409892b6e54c2e utime}
550
+ @deprecated See {#utimens}
551
+
552
+ @param [Context] context
553
+ @param [String] path
554
+ @param [Integer] actime access time
555
+ @param [Integer] modtime modification time
556
+
557
+ @return [void]
558
+ @raise [Errno]
559
+ */
560
+ static VALUE unsafe_utime(VALUE *args)
561
+ {
562
+ return rb_funcall3(args[0],rb_intern("utime"),4,&args[1]);
563
+ }
564
+
565
+ static int rf_utime(const char *path,struct utimbuf *utim)
566
+ {
567
+ VALUE args[5];
568
+ VALUE res;
569
+ int error = 0;
570
+
571
+ struct fuse_context *ctx=fuse_get_context();
572
+ init_context_path_args(args,ctx,path);
573
+
574
+ args[3]=INT2NUM(utim->actime);
575
+ args[4]=INT2NUM(utim->modtime);
576
+ res=rb_protect((VALUE (*)())unsafe_utime,(VALUE) args,&error);
577
+
578
+ return error ? -(return_error(ENOENT)) : 0;
579
+ }
580
+
581
+ /*
582
+ Change file ownership
583
+
584
+ @overload chown(context,path,uid,gid)
585
+
586
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#40421f8a43e903582c49897894f4692d chown}
587
+
588
+ @param [Context] context
589
+ @param [String] path
590
+ @param [Integer] uid new user id
591
+ @param [Integer] gid new group id
592
+
593
+ @return [void]
594
+ @raise [Errno]
595
+ */
596
+ static VALUE unsafe_chown(VALUE *args)
597
+ {
598
+ return rb_funcall3(args[0],rb_intern("chown"),4,&args[1]);
599
+ }
600
+
601
+ static int rf_chown(const char *path,uid_t uid,gid_t gid)
602
+ {
603
+ VALUE args[5];
604
+ VALUE res;
605
+ int error = 0;
606
+ struct fuse_context *ctx=fuse_get_context();
607
+ init_context_path_args(args,ctx,path);
608
+ args[3]=INT2FIX(uid);
609
+ args[4]=INT2FIX(gid);
610
+ res=rb_protect((VALUE (*)())unsafe_chown,(VALUE) args,&error);
611
+
612
+ return error ? -(return_error(ENOENT)) : 0;
613
+ }
614
+
615
+ /*
616
+ Change file permissions
617
+
618
+ @overload chmod(context,path,mode)
619
+
620
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#7e75d299efe3a401e8473af7028e5cc5 chmod}
621
+
622
+ @param [Context] context
623
+ @param [String] path
624
+ @param [Integer] mode
625
+
626
+ @return [void]
627
+ @raise [Errno]
628
+ */
629
+ static VALUE unsafe_chmod(VALUE *args)
630
+ {
631
+ return rb_funcall3(args[0],rb_intern("chmod"),3,&args[1]);
632
+ }
633
+
634
+ static int rf_chmod(const char *path,mode_t mode)
635
+ {
636
+ VALUE args[4];
637
+ VALUE res;
638
+ int error = 0;
639
+ struct fuse_context *ctx=fuse_get_context();
640
+ init_context_path_args(args,ctx,path);
641
+ args[3]=INT2FIX(mode);
642
+ res=rb_protect((VALUE (*)())unsafe_chmod,(VALUE) args,&error);
643
+
644
+ return error ? -(return_error(ENOENT)) : 0;
645
+ }
646
+
647
+ /*
648
+ Remove a file
649
+
650
+ @overload unlink(context,path)
651
+
652
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#8bf63301a9d6e94311fa10480993801e unlink}
653
+
654
+ @param [Context] context
655
+ @param [String] path
656
+
657
+ @return [void]
658
+ @raise [Errno]
659
+ */
660
+ static VALUE unsafe_unlink(VALUE *args)
661
+ {
662
+ return rb_funcall3(args[0],rb_intern("unlink"),2,&args[1]);
663
+ }
664
+
665
+ static int rf_unlink(const char *path)
666
+ {
667
+ VALUE args[3];
668
+ VALUE res;
669
+ int error = 0;
670
+ struct fuse_context *ctx=fuse_get_context();
671
+ init_context_path_args(args,ctx,path);
672
+ res=rb_protect((VALUE (*)())unsafe_unlink,(VALUE) args,&error);
673
+
674
+ return error ? -(return_error(ENOENT)) : 0;
675
+ }
676
+
677
+ /*
678
+ Remove a directory
679
+
680
+ @overload rmdir(context,path)
681
+
682
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#c59578d18db12f0142ae1ab6e8812d55 rmdir}
683
+
684
+ @param [Context] context
685
+ @param [String] path
686
+
687
+ @return [void]
688
+ @raise [Errno]
689
+ */
690
+ static VALUE unsafe_rmdir(VALUE *args)
691
+ {
692
+ return rb_funcall3(args[0],rb_intern("rmdir"),2,&args[1]);
693
+ }
694
+
695
+ static int rf_rmdir(const char *path)
696
+ {
697
+ VALUE args[3];
698
+ VALUE res;
699
+ int error = 0;
700
+ struct fuse_context *ctx=fuse_get_context();
701
+ init_context_path_args(args,ctx,path);
702
+ res = rb_protect((VALUE (*)())unsafe_rmdir, (VALUE) args ,&error);
703
+
704
+ return error ? -(return_error(ENOENT)) : 0;
705
+ }
706
+
707
+ /*
708
+ Create a symbolic link
709
+
710
+ @overload symlink(context,to,from)
711
+
712
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#b86022391e56a8ad3211cf754b5b5ebe symlink}
713
+
714
+ @param [Context] context
715
+ @param [String] to
716
+ @param [String] from
717
+
718
+ @return [void]
719
+ @raise [Errno]
720
+
721
+ Create a symbolic link named "from" which, when evaluated, will lead to "to".
722
+ */
723
+ static VALUE unsafe_symlink(VALUE *args){
724
+ return rb_funcall3(args[0],rb_intern("symlink"),3,&args[1]);
725
+ }
726
+
727
+ static int rf_symlink(const char *path,const char *as)
728
+ {
729
+ VALUE args[4];
730
+ VALUE res;
731
+ int error = 0;
732
+ struct fuse_context *ctx=fuse_get_context();
733
+ init_context_path_args(args,ctx,path);
734
+
735
+ args[3]=rb_str_new2(as);
736
+ rb_enc_associate(args[3],rb_filesystem_encoding());
737
+
738
+ res=rb_protect((VALUE (*)())unsafe_symlink,(VALUE) args,&error);
739
+
740
+ return error ? -(return_error(ENOENT)) : 0;
741
+ }
742
+
743
+ /*
744
+ @overload rename(context,from,to)
745
+
746
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#a777cbddc91887b117ac414e9a2d3cb5 rename}
747
+
748
+ @param [Context] context
749
+ @param [String] from
750
+ @param [String] to
751
+
752
+ @return [void]
753
+ @raise [Errno]
754
+
755
+ Rename the file, directory, or other object "from" to the target "to". Note that the source and target don't have to be in the same directory, so it may be necessary to move the source to an entirely new directory. See rename(2) for full details.
756
+ */
757
+ static VALUE unsafe_rename(VALUE *args)
758
+ {
759
+ return rb_funcall3(args[0],rb_intern("rename"),3,&args[1]);
760
+ }
761
+
762
+ static int rf_rename(const char *path,const char *as)
763
+ {
764
+ VALUE args[4];
765
+ VALUE res;
766
+ int error = 0;
767
+ struct fuse_context *ctx=fuse_get_context();
768
+ init_context_path_args(args,ctx,path);
769
+
770
+ args[3]=rb_str_new2(as);
771
+ rb_enc_associate(args[3],rb_filesystem_encoding());
772
+
773
+ res=rb_protect((VALUE (*)())unsafe_rename,(VALUE) args,&error);
774
+
775
+ return error ? -(return_error(ENOENT)) : 0;
776
+ }
777
+
778
+
779
+ /*
780
+ Create a hard link to file
781
+ @overload link(context,from,to)
782
+
783
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1b234c43e826c6a690d80ea895a17f61 link}
784
+
785
+ @param [Context] context
786
+ @param [String] from
787
+ @param [String] to
788
+
789
+ @return [void]
790
+ @raise [Errno]
791
+ */
792
+ static VALUE unsafe_link(VALUE *args)
793
+ {
794
+ return rb_funcall3(args[0],rb_intern("link"),3,&args[1]);
795
+ }
796
+
797
+ static int rf_link(const char *path,const char * as)
798
+ {
799
+ VALUE args[4];
800
+ VALUE res;
801
+ int error = 0;
802
+ struct fuse_context *ctx=fuse_get_context();
803
+ init_context_path_args(args,ctx,path);
804
+ args[3]=rb_str_new2(as);
805
+ rb_enc_associate(args[3],rb_filesystem_encoding());
806
+ res=rb_protect((VALUE (*)())unsafe_link,(VALUE) args,&error);
807
+
808
+ return error ? -(return_error(ENOENT)) : 0;
809
+ }
810
+
811
+
812
+ /*
813
+ Read data from an open file
814
+
815
+ @overload read(context,path,size,offset,ffi)
816
+
817
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#2a1c6b4ce1845de56863f8b7939501b5 read}
818
+
819
+ @param [Context] context
820
+ @param [String] path
821
+ @param [Integer] size
822
+ @param [Integer] offset
823
+ @param [FileInfo] ffi
824
+
825
+ @return [String] should be exactly the number of bytes requested, or empty string on EOF
826
+ @raise [Errno]
827
+ */
828
+ static VALUE unsafe_read(VALUE *args)
829
+ {
830
+ VALUE res;
831
+
832
+ res = rb_funcall3(args[0],rb_intern("read"),5,&args[1]);
833
+
834
+ return StringValue(res);
835
+ }
836
+
837
+
838
+ long rb_strcpy(VALUE str, char *buf, size_t size)
839
+ {
840
+ long length;
841
+
842
+ length = RSTRING_LEN(str);
843
+ if (length <= (long) size)
844
+ {
845
+ memcpy(buf,RSTRING_PTR(str),length);
846
+ }
847
+
848
+ return length;
849
+ }
850
+
851
+ static int rf_read(const char *path,char * buf, size_t size,off_t offset,struct fuse_file_info *ffi)
852
+ {
853
+ VALUE args[6];
854
+ VALUE res;
855
+ int error = 0;
856
+ long length=0;
857
+ char* rbuf;
858
+
859
+ struct fuse_context *ctx=fuse_get_context();
860
+ init_context_path_args(args,ctx,path);
861
+
862
+ args[3]=INT2NUM(size);
863
+ args[4]=INT2NUM(offset);
864
+ args[5]=get_file_info(ffi);
865
+
866
+ res=rb_protect((VALUE (*)())unsafe_read,(VALUE) args,&error);
867
+
868
+ if (error)
869
+ {
870
+ return -(return_error(ENOENT));
871
+ }
872
+ else
873
+ {
874
+
875
+ length = rb_strcpy(res,buf,size);
876
+
877
+ if (length <= (long) size) {
878
+ return length;
879
+ } else {
880
+ //This cannot happen => IO error.
881
+ return -(return_error(ENOENT));
882
+ }
883
+
884
+ }
885
+ }
886
+
887
+
888
+ /*
889
+ Write data to an open file
890
+
891
+ @overload write(context,path,size,offset,ffi)
892
+
893
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#897d1ece4b8b04c92d97b97b2dbf9768 write}
894
+
895
+ @param [Context] context
896
+ @param [String] path
897
+ @param [String] data
898
+ @param [Integer] offset
899
+ @param [FileInfo] ffi
900
+
901
+ @return [Integer] exactly the number of bytes written except on error
902
+ @raise [Errno]
903
+ */
904
+ static VALUE unsafe_write(VALUE *args)
905
+ {
906
+ return rb_funcall3(args[0],rb_intern("write"),5,&args[1]);
907
+ }
908
+
909
+ static int rf_write(const char *path,const char *buf,size_t size,
910
+ off_t offset,struct fuse_file_info *ffi)
911
+ {
912
+ VALUE args[6];
913
+ VALUE res;
914
+ int error = 0;
915
+ struct fuse_context *ctx=fuse_get_context();
916
+ init_context_path_args(args,ctx,path);
917
+
918
+ args[3]=rb_str_new(buf, size);
919
+ args[4]=INT2NUM(offset);
920
+ args[5]=get_file_info(ffi);
921
+
922
+ res = rb_protect((VALUE (*)())unsafe_write,(VALUE) args, &error);
923
+
924
+ if (error)
925
+ {
926
+ return -(return_error(ENOENT));
927
+ }
928
+ else
929
+ {
930
+ return NUM2INT(res);
931
+ }
932
+ }
933
+
934
+ /*
935
+ Get file system statistics
936
+
937
+ @overload statfs(context,path)
938
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#4e765e29122e7b6b533dc99849a52655 statfs}
939
+ @param [Context] context
940
+ @param [String] path
941
+
942
+ @return [StatVfs] or something that quacks like a statVfs
943
+ @raise [Errno]
944
+
945
+ The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
946
+
947
+ */
948
+ static VALUE unsafe_statfs(VALUE *args)
949
+ {
950
+ return rb_funcall3(args[0],rb_intern("statfs"),2,&args[1]);
951
+ }
952
+
953
+ static int rf_statfs(const char * path, struct statvfs * vfsinfo)
954
+ {
955
+ VALUE args[1];
956
+ VALUE res;
957
+ int error = 0;
958
+
959
+ struct fuse_context *ctx=fuse_get_context();
960
+ init_context_path_args(args,ctx,path);
961
+
962
+ res = rb_protect((VALUE (*)())unsafe_statfs,(VALUE) args,&error);
963
+
964
+ if (error || (res == Qnil))
965
+ {
966
+ return -(return_error(ENOENT));
967
+ }
968
+ else
969
+ {
970
+ rstatvfs2statvfs(res,vfsinfo);
971
+ return 0;
972
+ }
973
+ }
974
+
975
+
976
+ /*
977
+ Set extended attributes
978
+
979
+ @overload setxattr(context,path,name,data,flags)
980
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#988ced7091c2821daa208e6c96d8b598 setxattr}
981
+ @param [Context] context
982
+ @param [String] path
983
+ @param [String] name
984
+ @param [String] data
985
+ @param [Integer] flags
986
+
987
+ @return [void]
988
+ @raise [Errno]
989
+
990
+ */
991
+ static VALUE unsafe_setxattr(VALUE *args)
992
+ {
993
+ return rb_funcall3(args[0],rb_intern("setxattr"),5,&args[1]);
994
+ }
995
+
996
+ static int rf_setxattr(const char *path,const char *name,
997
+ const char *value, size_t size, int flags)
998
+ {
999
+ VALUE args[6];
1000
+ VALUE res;
1001
+ int error = 0;
1002
+
1003
+ struct fuse_context *ctx=fuse_get_context();
1004
+ init_context_path_args(args,ctx,path);
1005
+
1006
+ args[3]=rb_str_new2(name);
1007
+ args[4]=rb_str_new(value,size);
1008
+ args[5]=INT2NUM(flags);
1009
+
1010
+ res=rb_protect((VALUE (*)())unsafe_setxattr,(VALUE) args,&error);
1011
+
1012
+ return error ? -(return_error(ENOENT)) : 0;
1013
+ }
1014
+
1015
+
1016
+ /*
1017
+ Get extended attribute
1018
+
1019
+ @overload getxattr(context,path,name)
1020
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#e21503c64fe2990c8a599f5ba339a8f2 getxattr}
1021
+ @param [Context] context
1022
+ @param [String] path
1023
+ @param [String] name
1024
+
1025
+ @return [String] attribute value
1026
+ @raise [Errno]
1027
+
1028
+ */
1029
+ static VALUE unsafe_getxattr(VALUE *args)
1030
+ {
1031
+ VALUE res;
1032
+ res = rb_funcall3(args[0],rb_intern("getxattr"),3,&args[1]);
1033
+
1034
+ return StringValue(res);
1035
+ }
1036
+
1037
+ static int rf_getxattr(const char *path,const char *name,char *buf,
1038
+ size_t size)
1039
+ {
1040
+ VALUE args[4];
1041
+ VALUE res;
1042
+ char *rbuf;
1043
+ long length = 0;
1044
+ int error = 0;
1045
+
1046
+ struct fuse_context *ctx=fuse_get_context();
1047
+ init_context_path_args(args,ctx,path);
1048
+
1049
+ args[3]=rb_str_new2(name);
1050
+ res=rb_protect((VALUE (*)())unsafe_getxattr,(VALUE) args,&error);
1051
+
1052
+ if (error)
1053
+ {
1054
+ return -(return_error(ENOENT));
1055
+ }
1056
+ else
1057
+ {
1058
+ return rb_strcpy(res,buf,size);
1059
+ }
1060
+ }
1061
+
1062
+ /*
1063
+ List extended attributes
1064
+
1065
+ @overload listxattr(context,path)
1066
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#b4a9c361ce48406f07d5a08ab03f5de8 listxattr}
1067
+ @param [Context] context
1068
+ @param [String] path
1069
+
1070
+ @return [Array<String>] list of attribute names
1071
+ @raise [Errno]
1072
+ */
1073
+ static VALUE unsafe_listxattr(VALUE *args)
1074
+ {
1075
+ VALUE res;
1076
+ res = rb_funcall3(args[0],rb_intern("listxattr"),2,&args[1]);
1077
+
1078
+ //We'll let Ruby do the hard work of creating a String
1079
+ //separated by NULLs
1080
+ return rb_funcall(mRFuse,rb_intern("packxattr"),1,res);
1081
+ }
1082
+
1083
+ static int rf_listxattr(const char *path,char *buf, size_t size)
1084
+ {
1085
+ VALUE args[3];
1086
+ VALUE res;
1087
+ char *rbuf;
1088
+ size_t length =0;
1089
+ int error = 0;
1090
+
1091
+ struct fuse_context *ctx=fuse_get_context();
1092
+ init_context_path_args(args,ctx,path);
1093
+
1094
+ res=rb_protect((VALUE (*)())unsafe_listxattr,(VALUE) args,&error);
1095
+
1096
+ if (error)
1097
+ {
1098
+ return -(return_error(ENOENT));
1099
+ }
1100
+ else {
1101
+ return rb_strcpy(res,buf,size);
1102
+ }
1103
+ }
1104
+
1105
+
1106
+ /*
1107
+ Remove extended attribute
1108
+
1109
+ @overload removexattr(context,path,name)
1110
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#5e54de801a0e0d7019e4579112ecc477 removexattr}
1111
+ @param [Context] context
1112
+ @param [String] path
1113
+ @param [String] name attribute to remove
1114
+
1115
+ @return [void]
1116
+ @raise [Errno]
1117
+ */
1118
+ static VALUE unsafe_removexattr(VALUE *args)
1119
+ {
1120
+ return rb_funcall3(args[0],rb_intern("removexattr"),3,&args[1]);
1121
+ }
1122
+
1123
+ static int rf_removexattr(const char *path,const char *name)
1124
+ {
1125
+ VALUE args[4];
1126
+ VALUE res;
1127
+ int error = 0;
1128
+ struct fuse_context *ctx=fuse_get_context();
1129
+ init_context_path_args(args,ctx,path);
1130
+ args[3]=rb_str_new2(name);
1131
+ res=rb_protect((VALUE (*)())unsafe_removexattr,(VALUE) args,&error);
1132
+
1133
+ return error ? -(return_error(ENOENT)) : 0 ;
1134
+ }
1135
+
1136
+
1137
+ /*
1138
+ Open directory
1139
+
1140
+ @overload opendir(context,path,name)
1141
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1813889bc5e6e0087a936b7abe8b923f opendir}
1142
+ @param [Context] context
1143
+ @param [String] path
1144
+ @param [FileInfo] ffi
1145
+
1146
+ @return [void]
1147
+ @raise [Errno]
1148
+
1149
+
1150
+ Unless the 'default_permissions' mount option is given, this method should check if opendir is permitted for this directory. Optionally opendir may also return an arbitrary filehandle in the fuse_file_info structure, which will be available to {#readdir}, {#fsyncdir}, {#releasedir}.
1151
+
1152
+ */
1153
+ static VALUE unsafe_opendir(VALUE *args)
1154
+ {
1155
+ return rb_funcall3(args[0],rb_intern("opendir"),3,&args[1]);
1156
+ }
1157
+
1158
+ static int rf_opendir(const char *path,struct fuse_file_info *ffi)
1159
+ {
1160
+ VALUE args[4];
1161
+ VALUE res;
1162
+ int error = 0;
1163
+ struct fuse_context *ctx=fuse_get_context();
1164
+ init_context_path_args(args,ctx,path);
1165
+
1166
+ args[3]=wrap_file_info(ctx,ffi);
1167
+
1168
+ res=rb_protect((VALUE (*)())unsafe_opendir,(VALUE) args,&error);
1169
+
1170
+ return error ? -(return_error(ENOENT)) : 0 ;
1171
+ }
1172
+
1173
+ /*
1174
+ Release directory
1175
+
1176
+ @overload releasedir(context,path,ffi)
1177
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#729e53d36acc05a7a8985a1a3bbfac1e releasedir}
1178
+ @param [Context] context
1179
+ @param [String] path
1180
+ @param [FileInfo] ffi
1181
+
1182
+ @return [void]
1183
+ @raise [Errno]
1184
+ */
1185
+ static VALUE unsafe_releasedir(VALUE *args)
1186
+ {
1187
+
1188
+ return rb_funcall(args[0],rb_intern("releasedir"),3,&args[1]);
1189
+ }
1190
+
1191
+ static int rf_releasedir(const char *path,struct fuse_file_info *ffi)
1192
+ {
1193
+ VALUE args[4];
1194
+ VALUE res;
1195
+ int error = 0;
1196
+
1197
+ struct fuse_context *ctx=fuse_get_context();
1198
+ init_context_path_args(args,ctx,path);
1199
+ args[3]=release_file_info(ctx,ffi);
1200
+
1201
+ res=rb_protect((VALUE (*)())unsafe_releasedir,(VALUE) args,&error);
1202
+
1203
+ return error ? -(return_error(ENOENT)) : 0 ;
1204
+ }
1205
+
1206
+
1207
+ /*
1208
+ Sync directory
1209
+
1210
+ @overload fsyncdir(context,path,datasync,ffi)
1211
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#ba5cc1fe9a63ec152ceb19656f243256 fsyncdir}
1212
+ @param [Context] context
1213
+ @param [String] path
1214
+ @param [Integer] datasync if nonzero sync only data, not metadata
1215
+ @param [FileInfo] ffi
1216
+
1217
+ @return [void]
1218
+ @raise [Errno]
1219
+
1220
+ */
1221
+ static VALUE unsafe_fsyncdir(VALUE *args)
1222
+ {
1223
+ return rb_funcall(args[0],rb_intern("fsyncdir"),4,&args[1]);
1224
+ }
1225
+
1226
+ static int rf_fsyncdir(const char *path,int meta,struct fuse_file_info *ffi)
1227
+ {
1228
+ VALUE args[5];
1229
+ VALUE res;
1230
+ int error = 0;
1231
+ struct fuse_context *ctx=fuse_get_context();
1232
+ init_context_path_args(args,ctx,path);
1233
+ args[3]=INT2NUM(meta);
1234
+ args[4]=get_file_info(ffi);
1235
+ res=rb_protect((VALUE (*)())unsafe_fsyncdir,(VALUE) args,&error);
1236
+
1237
+ return error ? -(return_error(ENOENT)) : 0 ;
1238
+ }
1239
+
1240
+ /*
1241
+ Called when filesystem is initialised
1242
+
1243
+ @overload init(info)
1244
+ @abstract Fuse Operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#dc6dc71274f185de72217e38d62142c4 init}
1245
+
1246
+ @param [Context] context
1247
+ @param [Struct] info connection information
1248
+
1249
+ @return [void]
1250
+ */
1251
+ static VALUE unsafe_init(VALUE* args)
1252
+ {
1253
+ return rb_funcall3(args[0],rb_intern("init"),2,&args[1]);
1254
+ }
1255
+
1256
+ static void *rf_init(struct fuse_conn_info *conn)
1257
+ {
1258
+ VALUE args[3];
1259
+ VALUE res;
1260
+ int error = 0;
1261
+
1262
+ struct fuse_context *ctx = fuse_get_context();
1263
+
1264
+ VALUE self = ctx->private_data;
1265
+
1266
+ args[0] = self;
1267
+ args[1] = wrap_context(ctx);
1268
+
1269
+ //Create a struct for the conn_info
1270
+ //TODO - some of these are writable!
1271
+ VALUE s = rb_const_get(rb_cObject,rb_intern("Struct"));
1272
+ VALUE fci = rb_funcall(s,rb_intern("new"),7,
1273
+ ID2SYM(rb_intern("proto_major")),
1274
+ ID2SYM(rb_intern("proto_minor")),
1275
+ ID2SYM(rb_intern("async_read")),
1276
+ ID2SYM(rb_intern("max_write")),
1277
+ ID2SYM(rb_intern("max_readahead")),
1278
+ ID2SYM(rb_intern("capable")),
1279
+ ID2SYM(rb_intern("want"))
1280
+ );
1281
+
1282
+ VALUE fcio = rb_funcall(fci,rb_intern("new"),7,
1283
+ UINT2NUM(conn->proto_major),
1284
+ UINT2NUM(conn->proto_minor),
1285
+ UINT2NUM(conn->async_read),
1286
+ UINT2NUM(conn->max_write),
1287
+ UINT2NUM(conn->max_readahead),
1288
+ UINT2NUM(conn->capable),
1289
+ UINT2NUM(conn->want)
1290
+ );
1291
+
1292
+ args[2] = fcio;
1293
+
1294
+ res = rb_protect((VALUE (*)())unsafe_init,(VALUE) args,&error);
1295
+
1296
+ if (error)
1297
+ {
1298
+ return NULL;
1299
+ }
1300
+ else
1301
+ {
1302
+ //This previously was the result of the init call (res)
1303
+ //but it was never made available to any of the file operations
1304
+ //and nothing was done to prevent it from being GC'd so
1305
+ //filesystems would need to have stored it separately anyway
1306
+ return (void *) self;
1307
+ }
1308
+ }
1309
+
1310
+ /*
1311
+ Cleanup filesystem
1312
+
1313
+ @overload destroy()
1314
+ @abstract Fuse Operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#c41d37ab860204fe4bd7612f9fb036c5 destroy}
1315
+
1316
+ @param [Context] context
1317
+
1318
+ @return [void]
1319
+
1320
+ Called at filesystem exit - which itself is triggered when this fuse object
1321
+ is garbage collected, so not sure it is actually safe to call this
1322
+ */
1323
+ static VALUE unsafe_destroy(VALUE* args)
1324
+ {
1325
+ return rb_funcall3(args[0],rb_intern("destroy"),1,&args[1]);
1326
+ }
1327
+
1328
+ static void rf_destroy(void *user_data)
1329
+ {
1330
+ VALUE args[2];
1331
+ int error = 0;
1332
+
1333
+ struct fuse_context *ctx = fuse_get_context();
1334
+ args[0] = ctx->private_data;
1335
+ args[1] = wrap_context(ctx);
1336
+
1337
+ rb_protect((VALUE (*)())unsafe_destroy,(VALUE) args,&error);
1338
+ }
1339
+
1340
+ /*
1341
+ Check access permissions
1342
+
1343
+ @overload access(context,path,mode)
1344
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#2248db35e200265f7fb9a18348229858 access}
1345
+ @param [Context] context
1346
+ @param [String] path
1347
+ @param [Integer] mode the permissions to check
1348
+
1349
+ @return [void]
1350
+ @raise [Errno::EACCESS] if the requested permission isn't available
1351
+
1352
+ */
1353
+ static VALUE unsafe_access(VALUE* args)
1354
+ {
1355
+ return rb_funcall3(args[0],rb_intern("access"),3,&args[1]);
1356
+ }
1357
+
1358
+ static int rf_access(const char *path, int mask)
1359
+ {
1360
+ VALUE args[4];
1361
+ VALUE res;
1362
+ int error = 0;
1363
+ struct fuse_context *ctx=fuse_get_context();
1364
+ init_context_path_args(args,ctx,path);
1365
+ args[3] = INT2NUM(mask);
1366
+ res = rb_protect((VALUE (*)())unsafe_access,(VALUE) args,&error);
1367
+
1368
+ return error ? -(return_error(ENOENT)) : 0 ;
1369
+ }
1370
+
1371
+
1372
+ /*
1373
+ Create and open a file
1374
+
1375
+ @overload create(context,path,mode,ffi)
1376
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#97243e0f9268a96236bc3b6f2bacee17 create}
1377
+ @param [Context] context
1378
+ @param [String] path
1379
+ @param [Integer] mode the file permissions to create
1380
+ @param [Fileinfo] ffi - use the {FileInfo#fh} attribute to store a filehandle
1381
+
1382
+ @return [void]
1383
+ @raise [Errno]
1384
+
1385
+ If the file does not exist, first create it with the specified mode, and then open it.
1386
+
1387
+ */
1388
+ static VALUE unsafe_create(VALUE* args)
1389
+ {
1390
+ return rb_funcall3(args[0],rb_intern("create"),4,&args[1]);
1391
+ }
1392
+
1393
+ static int rf_create(const char *path, mode_t mode, struct fuse_file_info *ffi)
1394
+ {
1395
+ VALUE args[5];
1396
+ VALUE res;
1397
+ int error = 0;
1398
+
1399
+ struct fuse_context *ctx = fuse_get_context();
1400
+ init_context_path_args(args,ctx,path);
1401
+ args[3] = INT2NUM(mode);
1402
+ args[4] = wrap_file_info(ctx,ffi);
1403
+
1404
+ res = rb_protect((VALUE (*)())unsafe_create,(VALUE) args,&error);
1405
+
1406
+ return error ? -(return_error(ENOENT)) : 0 ;
1407
+
1408
+ }
1409
+
1410
+
1411
+ /*
1412
+ Change the size of an open file
1413
+
1414
+ @overload ftruncate(context,path,size,ffi)
1415
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1e492882859740f13cbf3344cf963c70 ftruncate}
1416
+ @param [Context] context
1417
+ @param [String] path
1418
+ @param [Integer] size
1419
+ @param [Fileinfo] ffi
1420
+
1421
+ @return [void]
1422
+ @raise [Errno]
1423
+
1424
+ */
1425
+ static VALUE unsafe_ftruncate(VALUE* args)
1426
+ {
1427
+ return rb_funcall3(args[0],rb_intern("ftruncate"),4,&args[1]);
1428
+ }
1429
+
1430
+ static int rf_ftruncate(const char *path, off_t size,
1431
+ struct fuse_file_info *ffi)
1432
+ {
1433
+ VALUE args[5];
1434
+ VALUE res;
1435
+ int error = 0;
1436
+
1437
+ struct fuse_context *ctx = fuse_get_context();
1438
+ init_context_path_args(args,ctx,path);
1439
+ args[3] = INT2NUM(size);
1440
+ args[4] = get_file_info(ffi);
1441
+
1442
+ res = rb_protect((VALUE (*)())unsafe_ftruncate,(VALUE) args,&error);
1443
+
1444
+ return error ? -(return_error(ENOENT)) : 0 ;
1445
+ }
1446
+
1447
+
1448
+ /*
1449
+ Get attributes of an open file
1450
+
1451
+ @overload fgetattr(context,path,ffi)
1452
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#573d79862df591c98e1685225a4cd3a5 fgetattr}
1453
+ @param [Context] context
1454
+ @param [String] path
1455
+ @param [Fileinfo] ffi
1456
+
1457
+ @return [Stat] file attributes
1458
+ @raise [Errno]
1459
+
1460
+ */
1461
+ static VALUE unsafe_fgetattr(VALUE *args)
1462
+ {
1463
+ return rb_funcall3(args[0],rb_intern("fgetattr"),3,&args[1]);
1464
+ }
1465
+
1466
+ static int rf_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *ffi)
1467
+ {
1468
+ VALUE args[4];
1469
+ VALUE res;
1470
+ int error = 0;
1471
+
1472
+ struct fuse_context *ctx = fuse_get_context();
1473
+ init_context_path_args(args,ctx,path);
1474
+ args[3] = get_file_info(ffi);
1475
+
1476
+ res=rb_protect((VALUE (*)())unsafe_fgetattr,(VALUE) args,&error);
1477
+
1478
+ if (error || (res == Qnil))
1479
+ {
1480
+ return -(return_error(ENOENT));
1481
+ }
1482
+ else
1483
+ {
1484
+ rstat2stat(res,stbuf);
1485
+ return 0;
1486
+ }
1487
+ }
1488
+
1489
+ /*
1490
+ Perform POSIX file locking operation
1491
+
1492
+ @overload lock(context,path,ffi,cmd,flock)
1493
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1c3fff5cf0c1c2003d117e764b9a76fd lock}
1494
+ @param [Context] context
1495
+ @param [String] path
1496
+ @param [Fileinfo] ffi
1497
+ @param [Integer] cmd
1498
+ @param [Struct] flock
1499
+
1500
+ @return [void]
1501
+ @raise [Errno]
1502
+
1503
+ The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
1504
+
1505
+ For the meaning of fields in 'struct flock' see the man page for fcntl(2). The l_whence field will always be set to SEEK_SET.
1506
+
1507
+ For checking lock ownership, the {FileInfo#owner} argument must be used.
1508
+
1509
+ For F_GETLK operation, the library will first check currently held locks, and if a conflicting lock is found it will return information without calling this method. This ensures, that for local locks the l_pid field is correctly filled in. The results may not be accurate in case of race conditions and in the presence of hard links, but it's unlikly that an application would rely on accurate GETLK results in these cases. If a conflicting lock is not found, this method will be called, and the filesystem may fill out l_pid by a meaningful value, or it may leave this field zero.
1510
+
1511
+ For F_SETLK and F_SETLKW the l_pid field will be set to the pid of the process performing the locking operation.
1512
+
1513
+ Note: if this method is not implemented, the kernel will still allow file locking to work locally. Hence it is only interesting for network filesystems and similar.
1514
+ */
1515
+ static VALUE unsafe_lock(VALUE *args)
1516
+ {
1517
+ return rb_funcall3(args[0],rb_intern("lock"),5,&args[1]);
1518
+ }
1519
+
1520
+ static int rf_lock(const char *path, struct fuse_file_info *ffi,
1521
+ int cmd, struct flock *lock)
1522
+ {
1523
+ VALUE args[6];
1524
+ VALUE res;
1525
+ int error = 0;
1526
+
1527
+ struct fuse_context *ctx = fuse_get_context();
1528
+ init_context_path_args(args,ctx,path);
1529
+
1530
+ //TODO Wrap the struct flock so these attributes can be set
1531
+
1532
+ //Create a struct for the lock structure
1533
+ VALUE s = rb_const_get(rb_cObject,rb_intern("Struct"));
1534
+ VALUE lockc = rb_funcall(s,rb_intern("new"),5,
1535
+ ID2SYM(rb_intern("l_type")),
1536
+ ID2SYM(rb_intern("l_whence")),
1537
+ ID2SYM(rb_intern("l_start")),
1538
+ ID2SYM(rb_intern("l_len")),
1539
+ ID2SYM(rb_intern("l_pid"))
1540
+ );
1541
+
1542
+ VALUE locko = rb_funcall(lockc,rb_intern("new"),5,
1543
+ UINT2NUM(lock->l_type),
1544
+ UINT2NUM(lock->l_whence),
1545
+ UINT2NUM(lock->l_start),
1546
+ UINT2NUM(lock->l_len),
1547
+ UINT2NUM(lock->l_pid)
1548
+ );
1549
+
1550
+ args[3] = get_file_info(ffi);
1551
+ args[4] = INT2NUM(cmd);
1552
+ args[5] = locko;
1553
+
1554
+ res = rb_protect((VALUE (*)())unsafe_lock,(VALUE) args,&error);
1555
+
1556
+ return error ? -(return_error(ENOENT)) : 0 ;
1557
+ }
1558
+
1559
+
1560
+ /*
1561
+ Change access/modification times of a file
1562
+
1563
+ @overload utimens(context,path,actime,modtime)
1564
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#79955861cc5eb006954476607ef28944 utimens}
1565
+
1566
+ @param [Context] context
1567
+ @param [String] path
1568
+ @param [Integer] actime access time in nanoseconds
1569
+ @param [Integer] modtime modification time in nanoseconds
1570
+
1571
+ @return [void]
1572
+ @raise [Errno]
1573
+ */
1574
+ static VALUE unsafe_utimens(VALUE *args)
1575
+ {
1576
+ return rb_funcall3(args[0],rb_intern("utimens"),4,&args[1]);
1577
+ }
1578
+
1579
+ static int rf_utimens(const char * path, const struct timespec tv[2])
1580
+ {
1581
+ VALUE args[5];
1582
+ VALUE res;
1583
+ int error = 0;
1584
+
1585
+ struct fuse_context *ctx = fuse_get_context();
1586
+ init_context_path_args(args,ctx,path);
1587
+
1588
+ // tv_sec * 1000000 + tv_nsec
1589
+ args[3] = rb_funcall(
1590
+ rb_funcall(
1591
+ INT2NUM(tv[0].tv_sec), rb_intern("*"), 1, INT2NUM(1000000)
1592
+ ),
1593
+ rb_intern("+"), 1, INT2NUM(tv[0].tv_nsec)
1594
+ );
1595
+
1596
+ args[4] = rb_funcall(
1597
+ rb_funcall(
1598
+ INT2NUM(tv[1].tv_sec), rb_intern("*"), 1, INT2NUM(1000000)
1599
+ ),
1600
+ rb_intern("+"), 1, INT2NUM(tv[1].tv_nsec)
1601
+ );
1602
+
1603
+ res = rb_protect((VALUE (*)())unsafe_utimens,(VALUE) args, &error);
1604
+ return error ? -(return_error(ENOENT)) : 0 ;
1605
+ }
1606
+
1607
+ /*
1608
+ Map block index within file to block index within device
1609
+
1610
+ @overload bmap(context,path,blocksize,index)
1611
+ @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#e3f3482e33a0eada0292350d76b82901 bmap}
1612
+
1613
+ @param [Context] context
1614
+ @param [String] path
1615
+ @param [Integer] blocksize
1616
+ @param [Integer] index
1617
+
1618
+ @return [Integer] device relative block index
1619
+ @raise [Errno]
1620
+
1621
+
1622
+ Note: This makes sense only for block device backed filesystems mounted with the 'blkdev' option
1623
+ */
1624
+ static VALUE unsafe_bmap(VALUE *args)
1625
+ {
1626
+ return rb_funcall3(args[0],rb_intern("bmap"),4,&args[1]);
1627
+ }
1628
+
1629
+ static int rf_bmap(const char *path, size_t blocksize, uint64_t *idx)
1630
+ {
1631
+ VALUE args[5];
1632
+ VALUE res;
1633
+ int error = 0;
1634
+
1635
+ struct fuse_context *ctx = fuse_get_context();
1636
+ init_context_path_args(args,ctx,path);
1637
+ args[3] = INT2NUM(blocksize);
1638
+ args[4] = LL2NUM(*idx);
1639
+
1640
+ res = rb_protect((VALUE (*)())unsafe_bmap,(VALUE) args, &error);
1641
+
1642
+ if (error)
1643
+ {
1644
+ return -(return_error(ENOENT));
1645
+ }
1646
+ else
1647
+ {
1648
+ *idx = NUM2LL(res);
1649
+ return 0;
1650
+ }
1651
+ }
1652
+
1653
+ //----------------------IOCTL
1654
+
1655
+ static VALUE unsafe_ioctl(VALUE *args)
1656
+ {
1657
+ VALUE path = args[0];
1658
+ VALUE cmd = args[1];
1659
+ VALUE arg = args[2];
1660
+ VALUE ffi = args[3];
1661
+ VALUE flags = args[4];
1662
+ VALUE data = args[5];
1663
+
1664
+ struct fuse_context *ctx = fuse_get_context();
1665
+
1666
+ return rb_funcall( ctx->private_data, rb_intern("ioctl"), 7, wrap_context(ctx),
1667
+ path, cmd, arg, ffi, flags, data);
1668
+ }
1669
+
1670
+ static int rf_ioctl(const char *path, int cmd, void *arg,
1671
+ struct fuse_file_info *ffi, unsigned int flags, void *data)
1672
+ {
1673
+ VALUE args[6];
1674
+ VALUE res;
1675
+ int error = 0;
1676
+
1677
+ args[0] = rb_str_new2(path);
1678
+ rb_enc_associate(args[0],rb_filesystem_encoding());
1679
+ args[1] = INT2NUM(cmd);
1680
+ args[2] = wrap_buffer(arg);
1681
+ args[3] = get_file_info(ffi);
1682
+ args[4] = INT2NUM(flags);
1683
+ args[5] = wrap_buffer(data);
1684
+
1685
+ res = rb_protect((VALUE (*)())unsafe_ioctl,(VALUE) args, &error);
1686
+
1687
+ if (error)
1688
+ {
1689
+ return -(return_error(ENOENT));
1690
+ }
1691
+
1692
+ return 0;
1693
+ }
1694
+
1695
+ //----------------------POLL
1696
+
1697
+ static VALUE unsafe_poll(VALUE *args)
1698
+ {
1699
+ VALUE path = args[0];
1700
+ VALUE ffi = args[1];
1701
+ VALUE ph = args[2];
1702
+ VALUE reventsp = args[3];
1703
+
1704
+ struct fuse_context *ctx = fuse_get_context();
1705
+
1706
+ return rb_funcall( ctx->private_data, rb_intern("poll"), 5, wrap_context(ctx),
1707
+ path, ffi, ph, reventsp);
1708
+ }
1709
+
1710
+ static int rf_poll(const char *path, struct fuse_file_info *ffi,
1711
+ struct fuse_pollhandle *ph, unsigned *reventsp)
1712
+ {
1713
+ VALUE args[4];
1714
+ VALUE res;
1715
+ int error = 0;
1716
+
1717
+ args[0] = rb_str_new2(path);
1718
+ rb_enc_associate(args[0],rb_filesystem_encoding());
1719
+ args[1] = get_file_info(ffi);
1720
+ args[2] = wrap_pollhandle(ph);
1721
+ args[3] = INT2NUM(*reventsp);
1722
+
1723
+ res = rb_protect((VALUE (*)())unsafe_poll,(VALUE) args, &error);
1724
+
1725
+ if (error)
1726
+ {
1727
+ return -(return_error(ENOENT));
1728
+ }
1729
+ else
1730
+ {
1731
+ *reventsp = NUM2INT(args[3]);
1732
+ }
1733
+ return 0;
1734
+ }
1735
+
1736
+ /*
1737
+ Is the filesystem successfully mounted
1738
+
1739
+ @return [Boolean] true if mounted, false otherwise
1740
+
1741
+ */
1742
+ static VALUE rf_mounted(VALUE self)
1743
+ {
1744
+ struct intern_fuse *inf;
1745
+ Data_Get_Struct(self,struct intern_fuse,inf);
1746
+
1747
+ // Never mounted, unmounted via fusermount, or via rf_unmount
1748
+ return (inf->fuse == NULL || fuse_exited(inf->fuse) ) ? Qfalse : Qtrue;
1749
+ }
1750
+
1751
+ /*
1752
+ Unmount filesystem
1753
+ */
1754
+ VALUE rf_unmount(VALUE self)
1755
+ {
1756
+ struct intern_fuse *inf;
1757
+ Data_Get_Struct(self,struct intern_fuse,inf);
1758
+
1759
+ fuse_exit(inf->fuse);
1760
+
1761
+ if (inf->fc != NULL) {
1762
+ fuse_unmount(inf->mountpoint, inf->fc);
1763
+ inf->fc = NULL;
1764
+ }
1765
+ return Qnil;
1766
+ }
1767
+
1768
+ /*
1769
+ @return [String] directory where this filesystem is mounted
1770
+ */
1771
+ VALUE rf_mountname(VALUE self)
1772
+ {
1773
+ struct intern_fuse *inf;
1774
+ Data_Get_Struct(self,struct intern_fuse,inf);
1775
+ VALUE result = rb_str_new2(inf->mountpoint);
1776
+ rb_enc_associate(result,rb_filesystem_encoding());
1777
+
1778
+ return result;
1779
+ }
1780
+
1781
+ /*
1782
+ @deprecated obsolete in FUSE itself
1783
+ */
1784
+ VALUE rf_invalidate(VALUE self,VALUE path)
1785
+ {
1786
+ struct intern_fuse *inf;
1787
+ Data_Get_Struct(self,struct intern_fuse,inf);
1788
+ return fuse_invalidate(inf->fuse,STR2CSTR(path));
1789
+ }
1790
+
1791
+ /*
1792
+ @return [Integer] /dev/fuse file descriptor for use with IO.select and {#process}
1793
+ @raise [RFuse::Error] if fuse not mounted
1794
+ */
1795
+ VALUE rf_fd(VALUE self)
1796
+ {
1797
+ struct intern_fuse *inf;
1798
+ Data_Get_Struct(self,struct intern_fuse,inf);
1799
+ if (inf->fuse == NULL) {
1800
+ rb_raise(eRFuse_Error,"FUSE not mounted");
1801
+ return Qnil;
1802
+ } else {
1803
+ return INT2NUM(intern_fuse_fd(inf));
1804
+ }
1805
+ }
1806
+
1807
+ /*
1808
+ Process one fuse command from the kernel
1809
+
1810
+ @return [Integer] 0 if successful
1811
+ @raise [RFuse::Error] if fuse not mounted
1812
+ */
1813
+ VALUE rf_process(VALUE self)
1814
+ {
1815
+ struct intern_fuse *inf;
1816
+ Data_Get_Struct(self,struct intern_fuse,inf);
1817
+ if (inf->fuse == NULL) {
1818
+ rb_raise(eRFuse_Error,"FUSE not mounted");
1819
+ return Qnil;
1820
+ } else {
1821
+ return INT2NUM(intern_fuse_process(inf));
1822
+ }
1823
+ }
1824
+
1825
+ #define RESPOND_TO(obj,methodname) \
1826
+ rb_funcall( \
1827
+ obj,rb_intern("respond_to?"), \
1828
+ 1, rb_str_new2(methodname) \
1829
+ ) == Qtrue
1830
+
1831
+ /*
1832
+ * initialize and mount the filesystem
1833
+ * @param [String] mountpoint The mountpoint
1834
+ * @param [Array<String>] options fuse arguments (-h to see a list)
1835
+ */
1836
+ static VALUE rf_initialize(
1837
+ VALUE self,
1838
+ VALUE mountpoint_obj,
1839
+ VALUE opts)
1840
+ {
1841
+
1842
+ //Allow things like Pathname to be sent as a mountpoint
1843
+ VALUE mountpoint = rb_obj_as_string(mountpoint_obj);
1844
+ Check_Type(opts, T_ARRAY);
1845
+
1846
+ struct intern_fuse *inf;
1847
+ Data_Get_Struct(self,struct intern_fuse,inf);
1848
+
1849
+ inf->mountpoint = strdup(StringValueCStr(mountpoint));
1850
+
1851
+ if (RESPOND_TO(self,"getattr"))
1852
+ inf->fuse_op.getattr = rf_getattr;
1853
+ if (RESPOND_TO(self,"readlink"))
1854
+ inf->fuse_op.readlink = rf_readlink;
1855
+ if (RESPOND_TO(self,"getdir"))
1856
+ inf->fuse_op.getdir = rf_getdir; // Deprecated
1857
+ if (RESPOND_TO(self,"mknod"))
1858
+ inf->fuse_op.mknod = rf_mknod;
1859
+ if (RESPOND_TO(self,"mkdir"))
1860
+ inf->fuse_op.mkdir = rf_mkdir;
1861
+ if (RESPOND_TO(self,"unlink"))
1862
+ inf->fuse_op.unlink = rf_unlink;
1863
+ if (RESPOND_TO(self,"rmdir"))
1864
+ inf->fuse_op.rmdir = rf_rmdir;
1865
+ if (RESPOND_TO(self,"symlink"))
1866
+ inf->fuse_op.symlink = rf_symlink;
1867
+ if (RESPOND_TO(self,"rename"))
1868
+ inf->fuse_op.rename = rf_rename;
1869
+ if (RESPOND_TO(self,"link"))
1870
+ inf->fuse_op.link = rf_link;
1871
+ if (RESPOND_TO(self,"chmod"))
1872
+ inf->fuse_op.chmod = rf_chmod;
1873
+ if (RESPOND_TO(self,"chown"))
1874
+ inf->fuse_op.chown = rf_chown;
1875
+ if (RESPOND_TO(self,"truncate"))
1876
+ inf->fuse_op.truncate = rf_truncate;
1877
+ if (RESPOND_TO(self,"utime"))
1878
+ inf->fuse_op.utime = rf_utime; // Deprecated
1879
+ if (RESPOND_TO(self,"open")) {
1880
+ inf->fuse_op.open = rf_open;
1881
+ inf->fuse_op.release = rf_release_ffi; // remove open file reference
1882
+ }
1883
+ if (RESPOND_TO(self,"create")) {
1884
+ inf->fuse_op.create = rf_create;
1885
+ inf->fuse_op.release = rf_release_ffi; // remove open file reference
1886
+ }
1887
+ if (RESPOND_TO(self,"read"))
1888
+ inf->fuse_op.read = rf_read;
1889
+ if (RESPOND_TO(self,"write"))
1890
+ inf->fuse_op.write = rf_write;
1891
+ if (RESPOND_TO(self,"statfs"))
1892
+ inf->fuse_op.statfs = rf_statfs;
1893
+ if (RESPOND_TO(self,"flush"))
1894
+ inf->fuse_op.flush = rf_flush;
1895
+ if (RESPOND_TO(self,"release"))
1896
+ inf->fuse_op.release = rf_release;
1897
+ if (RESPOND_TO(self,"fsync"))
1898
+ inf->fuse_op.fsync = rf_fsync;
1899
+ if (RESPOND_TO(self,"setxattr"))
1900
+ inf->fuse_op.setxattr = rf_setxattr;
1901
+ if (RESPOND_TO(self,"getxattr"))
1902
+ inf->fuse_op.getxattr = rf_getxattr;
1903
+ if (RESPOND_TO(self,"listxattr"))
1904
+ inf->fuse_op.listxattr = rf_listxattr;
1905
+ if (RESPOND_TO(self,"removexattr"))
1906
+ inf->fuse_op.removexattr = rf_removexattr;
1907
+ if (RESPOND_TO(self,"opendir")) {
1908
+ inf->fuse_op.opendir = rf_opendir;
1909
+ inf->fuse_op.release = rf_release_ffi; // remove open file reference
1910
+ }
1911
+ if (RESPOND_TO(self,"readdir"))
1912
+ inf->fuse_op.readdir = rf_readdir;
1913
+ if (RESPOND_TO(self,"releasedir"))
1914
+ inf->fuse_op.releasedir = rf_releasedir;
1915
+ if (RESPOND_TO(self,"fsyncdir"))
1916
+ inf->fuse_op.fsyncdir = rf_fsyncdir;
1917
+ if (RESPOND_TO(self,"init"))
1918
+ inf->fuse_op.init = rf_init;
1919
+ // if (RESPOND_TO(self,"destroy"))
1920
+ // inf->fuse_op.destroy = rf_destroy;
1921
+ if (RESPOND_TO(self,"access"))
1922
+ inf->fuse_op.access = rf_access;
1923
+ if (RESPOND_TO(self,"ftruncate"))
1924
+ inf->fuse_op.ftruncate = rf_ftruncate;
1925
+ if (RESPOND_TO(self,"fgetattr"))
1926
+ inf->fuse_op.fgetattr = rf_fgetattr;
1927
+ if (RESPOND_TO(self,"lock"))
1928
+ inf->fuse_op.lock = rf_lock;
1929
+ if (RESPOND_TO(self,"utimens"))
1930
+ inf->fuse_op.utimens = rf_utimens;
1931
+ if (RESPOND_TO(self,"bmap"))
1932
+ inf->fuse_op.bmap = rf_bmap;
1933
+ /*
1934
+ if (RESPOND_TO(self,"ioctl"))
1935
+ inf->fuse_op.ioctl = rf_ioctl;
1936
+ if (RESPOND_TO(self,"poll"))
1937
+ inf->fuse_op.poll = rf_poll;
1938
+ */
1939
+
1940
+ struct fuse_args *args = rarray2fuseargs(opts);
1941
+
1942
+ //Store our fuse object in user_data, this will be returned to use in the
1943
+ //session context
1944
+ void* user_data = self;
1945
+
1946
+ int init_result;
1947
+
1948
+ // init_result indicates not mounted, but so does inf->fuse == NULL
1949
+ // raise exceptions only if we try to use the mount
1950
+ // can test with mounted?
1951
+ init_result = intern_fuse_init(inf, args, user_data);
1952
+
1953
+ //Create the open files hash where we cache FileInfo objects
1954
+ VALUE open_files_hash;
1955
+ if (init_result == 0) {
1956
+ open_files_hash=rb_hash_new();
1957
+ rb_iv_set(self,"@open_files",open_files_hash);
1958
+ rb_funcall(self,rb_intern("ruby_initialize"),0);
1959
+ }
1960
+ return self;
1961
+ }
1962
+
1963
+ static VALUE rf_new(VALUE class)
1964
+ {
1965
+ struct intern_fuse *inf;
1966
+ VALUE self;
1967
+ inf = intern_fuse_new();
1968
+ self=Data_Wrap_Struct(class, 0, intern_fuse_destroy, inf);
1969
+ return self;
1970
+ }
1971
+
1972
+ /*
1973
+ * Document-class: RFuse::Fuse
1974
+ *
1975
+ * A FUSE filesystem - extend this class implementing
1976
+ * the various abstract methods to provide your filesystem.
1977
+ *
1978
+ * All file operations take a {Context} and a path as well as any other necessary parameters
1979
+ *
1980
+ * Mount your filesystem by creating an instance of your subclass and call #loop to begin processing
1981
+ */
1982
+ void rfuse_init(VALUE module)
1983
+ {
1984
+ #if 0
1985
+ //Trick Yardoc
1986
+ mRFuse = rb_define_mRFuse("RFuse");
1987
+ #endif
1988
+ mRFuse = module;
1989
+ VALUE cFuse=rb_define_class_under(mRFuse,"Fuse",rb_cObject);
1990
+
1991
+ rb_define_alloc_func(cFuse,rf_new);
1992
+
1993
+ rb_define_method(cFuse,"initialize",rf_initialize,2);
1994
+ rb_define_method(cFuse,"mounted?",rf_mounted,0);
1995
+ rb_define_method(cFuse,"invalidate",rf_invalidate,1);
1996
+ rb_define_method(cFuse,"unmount",rf_unmount,0);
1997
+ rb_define_method(cFuse,"mountname",rf_mountname,0);
1998
+ rb_define_alias(cFuse,"mountpoint","mountname");
1999
+ rb_define_method(cFuse,"fd",rf_fd,0);
2000
+ rb_define_method(cFuse,"process",rf_process,0);
2001
+ rb_attr(cFuse,rb_intern("open_files"),1,0,Qfalse);
2002
+
2003
+ eRFuse_Error = rb_define_class_under(mRFuse,"Error",rb_eStandardError);
2004
+
2005
+ #if 0
2006
+ //Trick Yarddoc into documenting abstract fuseoperations
2007
+ rb_define_method(cFuse,"readdir",unsafe_readdir,0);
2008
+ rb_define_method(cFuse,"readlink",unsafe_readlink,0);
2009
+ rb_define_method(cFuse,"getdir",unsafe_getdir,0);
2010
+ rb_define_method(cFuse,"mknod",unsafe_mknod,0);
2011
+ rb_define_method(cFuse,"getattr",unsafe_getattr,0);
2012
+ rb_define_method(cFuse,"mkdir",unsafe_mkdir,0);
2013
+ rb_define_method(cFuse,"open",unsafe_open,0);
2014
+ rb_define_method(cFuse,"release",unsafe_release,0);
2015
+ rb_define_method(cFuse,"fsync",unsafe_fsync,0);
2016
+ rb_define_method(cFuse,"flush",unsafe_flush,0);
2017
+ rb_define_method(cFuse,"truncate",unsafe_truncate,0);
2018
+ rb_define_method(cFuse,"utime",unsafe_utime,0);
2019
+ rb_define_method(cFuse,"chown",unsafe_chown,0);
2020
+ rb_define_method(cFuse,"chmod",unsafe_chmod,0);
2021
+ rb_define_method(cFuse,"unlink",unsafe_unlink,0);
2022
+ rb_define_method(cFuse,"symlink",unsafe_symlink,0);
2023
+ rb_define_method(cFuse,"rename",unsafe_rename,0);
2024
+ rb_define_method(cFuse,"link",unsafe_link,0);
2025
+ rb_define_method(cFuse,"read",unsafe_read,0);
2026
+ rb_define_method(cFuse,"write",unsafe_write,0);
2027
+ rb_define_method(cFuse,"statfs",unsafe_statfs,0);
2028
+ rb_define_method(cFuse,"setxattr",unsafe_setxattr,0);
2029
+ rb_define_method(cFuse,"getxattr",unsafe_getxattr,0);
2030
+ rb_define_method(cFuse,"listxattr",unsafe_listxattr,0);
2031
+ rb_define_method(cFuse,"removexattr",unsafe_removexattr,0);
2032
+ rb_define_method(cFuse,"opendir",unsafe_opendir,0);
2033
+ rb_define_method(cFuse,"releasedir",unsafe_releasedir,0);
2034
+ rb_define_method(cFuse,"fsyncdir",unsafe_fsyncdir,0);
2035
+ rb_define_method(cFuse,"init",unsafe_init,0);
2036
+ rb_define_method(cFuse,"destroy",unsafe_destroy,0);
2037
+ rb_define_method(cFuse,"access",unsafe_access,0);
2038
+ rb_define_method(cFuse,"create",unsafe_create,0);
2039
+ rb_define_method(cFuse,"ftruncate",unsafe_ftruncate,0);
2040
+ rb_define_method(cFuse,"fgetattr",unsafe_fgetattr,0);
2041
+ rb_define_method(cFuse,"lock",unsafe_lock,0);
2042
+ rb_define_method(cFuse,"utimens",unsafe_utimens,0);
2043
+ rb_define_method(cFuse,"bmap",unsafe_bmap,0);
2044
+ #endif
2045
+ }