rfuse-ng 0.4.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.txt CHANGED
@@ -1,3 +1,71 @@
1
+ 2011-02-27
2
+
3
+ All fuse operations are implemented. ioctl() and poll() are untested,
4
+ thus, probably won't work properly. Please contact me if you can test
5
+ these features, now I have a little bit more time for the project.
6
+
7
+ Itegrated features from other folks' patches. Thanks for Grant Gardner
8
+ (GG) and Yonatan Maman (YM)
9
+
10
+ Pathces:
11
+
12
+ YM-1: ruby_19_yonatan.pathc
13
+ * allow rfuse-ng to compile under ruby 1.9.2
14
+
15
+ GG-1: 0001-allow-nil-for-readder-filler.patch
16
+ * allow readdir to push "nil" as the stat value into filler (fuse will
17
+ then call getattr() when required)
18
+ * allow open to place a ruby object into fuse_file_info->fh and be
19
+ cleaned up again in release
20
+
21
+ GG-2: 0002-exception-backtraces-and-ruby-filehandle-object-in-o.patch
22
+ * tweak the error handling to log the caught exception and its
23
+ backtrace
24
+ * The error handling part will not print any output if the thrown
25
+ exception responds_to?(:errno) since I gather that would be expected
26
+ (eg ENOENT)
27
+
28
+ GG-3: 0003-Add-fd-and-process-calls-to-RFuse-object.patch
29
+
30
+ This one allows you to run the event loop in ruby instead of calling
31
+ fuse_loop() which is useful if you want to install your own signal handlers
32
+ and cleanup nicely if fuse is unmounted externally.
33
+
34
+ eg...
35
+
36
+ def FuseFS.run
37
+ unless @fuse
38
+ raise "fuse is not mounted
39
+ end
40
+
41
+ begin
42
+ #Get the /dev/fuse fd
43
+ io = IO.for_fd(@fuse.fd)
44
+ rescue Errno::EBADF
45
+ raise "fuse not mounted"
46
+ end
47
+
48
+ @running = true
49
+ while @running
50
+ begin
51
+ IO.select([io])
52
+ # Process a fuse command, returns -1 if fuse has been
53
+ unmounted remotely.
54
+ if (@fuse.process() < 0)
55
+ @running = false
56
+ end
57
+ rescue Errno::EBADF
58
+ #We've tried to select on a dead fd...
59
+ @running = false
60
+ end
61
+ end
62
+ end
63
+
64
+ BUGS to fix:
65
+
66
+ Parameters are not handled correctly to fuse_mount, see test-ruby.rb
67
+ for details.
68
+
1
69
  2010-06-20
2
70
 
3
71
  Only poll() and ioctl() are missing. Fixed compilation error
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'rubygems'
2
4
  require 'rake'
3
5
 
@@ -5,7 +7,7 @@ begin
5
7
  require 'jeweler'
6
8
  Jeweler::Tasks.new do |gem|
7
9
  gem.name = "rfuse-ng"
8
- gem.version = "0.4.0"
10
+ gem.version = "0.5.3"
9
11
  gem.summary = 'Ruby language binding for FUSE'
10
12
  gem.description = 'Ruby language binding for FUSE. It was forked from rfuse'
11
13
  gem.rubyforge_project = 'rfuse-ng'
data/TODO.txt CHANGED
@@ -2,5 +2,26 @@ Todo list from rfuse:
2
2
 
3
3
  *Unit Test
4
4
  *Multithreading
5
- *Better Errorhandling
5
+ *Better Error handling
6
6
  *Test,test,test
7
+
8
+ Todo list for ng:
9
+
10
+ Basicly same as above, except:
11
+
12
+ A lot of testing has been done and an army of bugs was slaughtered in
13
+ the process, so rfuse-ng can be called "beta", means other folks have
14
+ to test it probably by trying to do something useful.
15
+
16
+ Error handling still needs to be improved greatly. Stuff needs logging
17
+ (syslog?) with different verbosity levels to support developement and
18
+ still don't litter the logs on production systems.
19
+
20
+ Multithreading is still a mistery for me, but definitely a must to have
21
+ feature.
22
+
23
+ Since manual testing takes up some 60% of my time, I desperately need
24
+ unit tests, so this item still valid too.
25
+
26
+ BUG: find out why kernel parameter passing behaves very oddly (see
27
+ test-ruby.rb for details).
@@ -0,0 +1,48 @@
1
+ #include <stdlib.h>
2
+ #include <ruby.h>
3
+ #include <fuse.h>
4
+
5
+ #include "bufferwrapper.h"
6
+
7
+ VALUE bufferwrapper_new(VALUE class)
8
+ {
9
+ rb_raise(rb_eNotImpError, "new() not implemented (it has no use), and should not be called");
10
+ return Qnil;
11
+ }
12
+
13
+ VALUE bufferwrapper_initialize(VALUE self)
14
+ {
15
+ return self;
16
+ }
17
+
18
+ VALUE bufferwrapper_getdata(VALUE self, VALUE size)
19
+ {
20
+ void *buf;
21
+
22
+ Data_Get_Struct(self, void, buf);
23
+
24
+ return rb_str_new(buf, FIX2INT(size));
25
+ }
26
+
27
+ VALUE wrap_buffer(void *buf)
28
+ {
29
+ VALUE rRFuse;
30
+ VALUE rBufferWrapper;
31
+
32
+ rRFuse = rb_const_get(rb_cObject,rb_intern("RFuse"));
33
+ rBufferWrapper = rb_const_get(rRFuse,rb_intern("BufferWrapper"));
34
+
35
+ return Data_Wrap_Struct(rBufferWrapper, NULL, NULL, buf);
36
+ }
37
+
38
+ VALUE bufferwrapper_init(VALUE module)
39
+ {
40
+ VALUE cBufferWrapper = rb_define_class_under(module,"BufferWrapper",rb_cObject);
41
+
42
+ rb_define_alloc_func(cBufferWrapper,bufferwrapper_new);
43
+
44
+ rb_define_method(cBufferWrapper,"initialize",bufferwrapper_initialize,0);
45
+ rb_define_method(cBufferWrapper,"getData",bufferwrapper_getdata,1);
46
+
47
+ return cBufferWrapper;
48
+ }
@@ -0,0 +1,10 @@
1
+ #include <fuse.h>
2
+ #include <ruby.h>
3
+
4
+ VALUE wrap_buffer(void *buf);
5
+
6
+ VALUE bufferwrapper_new(VALUE class);
7
+ VALUE bufferwrapper_getdata(VALUE self, VALUE size);
8
+ VALUE bufferwrapper_init(VALUE module);
9
+
10
+ VALUE bufferwrapper_initialize(VALUE self);
data/ext/file_info.c CHANGED
@@ -2,12 +2,21 @@
2
2
  #include <fuse.h>
3
3
 
4
4
 
5
+ static void file_info_mark(struct fuse_file_info *ffi) {
6
+ if (TYPE(ffi->fh) != T_NONE) {
7
+ rb_gc_mark((VALUE) ffi->fh);
8
+ }
9
+ }
10
+
11
+ //creates a FileInfo object from an already allocated ffi
5
12
  VALUE wrap_file_info(struct fuse_file_info *ffi) {
6
13
  VALUE rRFuse;
7
14
  VALUE rFileInfo;
8
15
  rRFuse=rb_const_get(rb_cObject,rb_intern("RFuse"));
9
16
  rFileInfo=rb_const_get(rRFuse,rb_intern("FileInfo"));
10
- return Data_Wrap_Struct(rFileInfo,0,0,ffi); //shouldn't be freed!
17
+ //TODO GG: we need a mark function here to ensure the ffi-fh value is not GC'd
18
+ //between open and release
19
+ return Data_Wrap_Struct(rFileInfo,file_info_mark,0,ffi); //shouldn't be freed!
11
20
 
12
21
  };
13
22
 
@@ -16,11 +25,12 @@ VALUE file_info_initialize(VALUE self){
16
25
  return self;
17
26
  }
18
27
 
28
+ //TODO GG: This probably needs a free function and be converted to alloc/initialize
29
+ //but this probably never gets called anyway
30
+ //TODO FT: test: this _should_not_ be called, an exception would do the trick :)
19
31
  VALUE file_info_new(VALUE class){
20
- VALUE self;
21
- struct fuse_file_info *f;
22
- self = Data_Make_Struct(class, struct fuse_file_info, 0,NULL,f);
23
- return self;
32
+ rb_raise(rb_eNotImpError, "new() not implemented (it has no use), and should not be called");
33
+ return Qnil;
24
34
  }
25
35
 
26
36
  VALUE file_info_writepage(VALUE self) {
@@ -35,11 +45,31 @@ VALUE file_info_flags(VALUE self) {
35
45
  return INT2FIX(f->flags);
36
46
  }
37
47
 
48
+ //fh is possibly a pointer to a ruby object and can be set
49
+ VALUE file_info_fh(VALUE self) {
50
+ struct fuse_file_info *f;
51
+ Data_Get_Struct(self,struct fuse_file_info,f);
52
+ if (TYPE(f->fh) != T_NONE) {
53
+ return (VALUE) f->fh;
54
+ } else {
55
+ return Qnil;
56
+ }
57
+ }
58
+
59
+ VALUE file_info_fh_assign(VALUE self,VALUE value) {
60
+ struct fuse_file_info *f;
61
+ Data_Get_Struct(self,struct fuse_file_info,f);
62
+ f->fh = value;
63
+ return value;
64
+ }
65
+
38
66
  VALUE file_info_init(VALUE module) {
39
67
  VALUE cFileInfo=rb_define_class_under(module,"FileInfo",rb_cObject);
40
68
  rb_define_alloc_func(cFileInfo,file_info_new);
41
69
  rb_define_method(cFileInfo,"initialize",file_info_initialize,0);
42
70
  rb_define_method(cFileInfo,"flags",file_info_flags,0);
43
71
  rb_define_method(cFileInfo,"writepage",file_info_writepage,0);
72
+ rb_define_method(cFileInfo,"fh",file_info_fh,0);
73
+ rb_define_method(cFileInfo,"fh=",file_info_fh_assign,1);
44
74
  return cFileInfo;
45
75
  }
data/ext/filler.c CHANGED
@@ -16,10 +16,15 @@ VALUE rfiller_new(VALUE class){
16
16
  VALUE rfiller_push(VALUE self, VALUE name, VALUE stat, VALUE offset) {
17
17
  struct filler_t *f;
18
18
  Data_Get_Struct(self,struct filler_t,f);
19
- struct stat st;
20
- memset(&st, 0, sizeof(st));
21
- rstat2stat(stat,&st);
22
- f->filler(f->buffer,STR2CSTR(name),&st,NUM2LONG(offset));
19
+ //Allow nil return instead of a stat
20
+ if (NIL_P(stat)) {
21
+ f->filler(f->buffer,STR2CSTR(name),NULL,NUM2LONG(offset));
22
+ } else {
23
+ struct stat st;
24
+ memset(&st, 0, sizeof(st));
25
+ rstat2stat(stat,&st);
26
+ f->filler(f->buffer,STR2CSTR(name),&st,NUM2LONG(offset));
27
+ }
23
28
  return self;
24
29
  }
25
30
 
data/ext/helper.c CHANGED
@@ -47,24 +47,20 @@ void rfuseconninfo2fuseconninfo(VALUE rfuseconninfo,struct fuse_conn_info *fusec
47
47
  struct fuse_args * rarray2fuseargs(VALUE rarray){
48
48
 
49
49
  Check_Type(rarray, T_ARRAY);
50
-
51
50
  struct fuse_args *args = malloc(sizeof(struct fuse_args));
52
-
53
- args->argc = RARRAY(rarray)->len;
54
- args->argv = malloc(args->argc * sizeof(char *) + 1);
55
- /* Nope, this isn't really 'allocated'. The elements
56
- * of this array shouldn't be freed */
57
- args->allocated = 0;
51
+ args->argc = RARRAY_LEN(rarray);
52
+ args->argv = malloc((args->argc + 1) * sizeof(char *));
53
+ args->allocated = 1;
58
54
 
59
55
  int i;
60
56
  VALUE v;
57
+
61
58
  for(i = 0; i < args->argc; i++) {
62
- v = RARRAY(rarray)->ptr[i];
59
+ v = RARRAY_PTR(rarray)[i];
63
60
  Check_Type(v, T_STRING);
64
- args->argv[i] = STR2CSTR(RSTRING(v));
61
+ args->argv[i] = rb_string_value_ptr(&v); //STR2CSTR(RSTRING(v));
65
62
  }
66
63
  args->argv[args->argc] = NULL;
67
64
 
68
65
  return args;
69
66
  }
70
-
data/ext/helper.h CHANGED
@@ -11,4 +11,9 @@ void rstatvfs2statvfs(VALUE rstatvfs,struct statvfs *statvfsbuf);
11
11
  void rfuseconninfo2fuseconninfo(VALUE rfuseconninfo,struct fuse_conn_info *fuseconninfo);
12
12
  struct fuse_args * rarray2fuseargs(VALUE rarray);
13
13
 
14
+ #if defined(RUBY_VERSION) && RUBY_VERSION >= 19
15
+ #define STR2CSTR(X) StringValuePtr(X)
16
+ #endif
17
+
18
+
14
19
  #endif
data/ext/intern_rfuse.c CHANGED
@@ -1,21 +1,22 @@
1
+ #include "intern_rfuse.h"
2
+ #include <fuse/fuse_lowlevel.h>
3
+ #include <stdio.h>
1
4
  #include <stdlib.h>
2
5
  #include <string.h>
3
- #include <fuse.h>
4
- #include "intern_rfuse.h"
5
6
 
6
7
  struct intern_fuse *intern_fuse_new() {
7
8
  struct intern_fuse *inf;
8
9
  inf = (struct intern_fuse *) malloc(sizeof(struct intern_fuse));
9
10
  memset(&inf->fuse_op, 0, sizeof(struct fuse_operations));
10
11
  return inf;
11
- };
12
+ }
12
13
 
13
14
  int intern_fuse_destroy(struct intern_fuse *inf){
14
15
  //you have to take care, that fuse is unmounted yourself!
15
16
  fuse_destroy(inf->fuse);
16
17
  free(inf);
17
18
  return 0;
18
- };
19
+ }
19
20
 
20
21
  int intern_fuse_init(
21
22
  struct intern_fuse *inf,
@@ -40,4 +41,37 @@ int intern_fuse_init(
40
41
 
41
42
  strncpy(inf->mountname, mountpoint, MOUNTNAME_MAX);
42
43
  return 0;
43
- };
44
+ }
45
+
46
+ // Return the /dev/fuse file descriptor for use with IO.select
47
+ int intern_fuse_fd(struct intern_fuse *inf)
48
+ {
49
+ if (inf->fc == NULL) {
50
+ return -1;
51
+ }
52
+
53
+ struct fuse_chan *fc = inf->fc;
54
+ return fuse_chan_fd(fc);
55
+ }
56
+
57
+ //Process one fuse command (ie after IO.select)
58
+ int intern_fuse_process(struct intern_fuse *inf)
59
+ {
60
+ if (inf->fuse == NULL) {
61
+ return -1;
62
+ }
63
+
64
+
65
+ if (fuse_exited(inf->fuse)) {
66
+ return -1;
67
+ }
68
+
69
+ struct fuse_cmd *cmd;
70
+ cmd = fuse_read_cmd(inf->fuse);
71
+
72
+ if (cmd != NULL) {
73
+ fuse_process_cmd(inf->fuse, cmd);
74
+ }
75
+
76
+ return 0;
77
+ }
data/ext/intern_rfuse.h CHANGED
@@ -20,4 +20,6 @@ int intern_fuse_init(
20
20
  struct fuse_args *libopts
21
21
  );
22
22
 
23
+ int intern_fuse_fd(struct intern_fuse *inf);
24
+ int intern_fuse_process(struct intern_fuse *inf);
23
25
  int intern_fuse_destroy(struct intern_fuse *inf);
data/ext/pollhandle.c ADDED
@@ -0,0 +1,54 @@
1
+ #include <ruby.h>
2
+ #include <fuse.h>
3
+
4
+ #include "pollhandle.h"
5
+
6
+ static int pollhandle_destroy(struct fuse_pollhandle *ph)
7
+ {
8
+ fuse_pollhandle_destroy(ph);
9
+ return 0;
10
+ }
11
+
12
+ VALUE pollhandle_new(VALUE class)
13
+ {
14
+ rb_raise(rb_eNotImpError, "new() not implemented (it has no use), and should not be called");
15
+ return Qnil;
16
+ }
17
+
18
+ VALUE pollhandle_initialize(VALUE self)
19
+ {
20
+ return self;
21
+ }
22
+
23
+ VALUE pollhandle_notify_poll(VALUE self)
24
+ {
25
+ struct fuse_pollhandle *ph;
26
+ Data_Get_Struct(self, struct fuse_pollhandle, ph);
27
+ return INT2FIX(fuse_notify_poll(ph));
28
+ }
29
+
30
+ VALUE wrap_pollhandle(struct fuse_pollhandle *ph)
31
+ {
32
+ VALUE rRFuse;
33
+ VALUE rPollHandle;
34
+
35
+ rRFuse = rb_const_get(rb_cObject,rb_intern("RFuse"));
36
+ rPollHandle = rb_const_get(rRFuse,rb_intern("PollHandle"));
37
+
38
+ // We need a mark function here to ensure the ph is not GC'd
39
+ // between poll and notify_poll
40
+ return Data_Wrap_Struct(rPollHandle, NULL, pollhandle_destroy, ph);
41
+
42
+ }
43
+
44
+ VALUE pollhandle_init(VALUE module)
45
+ {
46
+ VALUE cPollHandle = rb_define_class_under(module,"PollHandle",rb_cObject);
47
+
48
+ rb_define_alloc_func(cPollHandle,pollhandle_new);
49
+
50
+ rb_define_method(cPollHandle,"initialize",pollhandle_initialize,0);
51
+ rb_define_method(cPollHandle,"notifyPoll",pollhandle_notify_poll,0);
52
+
53
+ return cPollHandle;
54
+ }
data/ext/pollhandle.h ADDED
@@ -0,0 +1,10 @@
1
+ #include <fuse.h>
2
+ #include <ruby.h>
3
+
4
+ VALUE wrap_pollhandle(struct fuse_pollhandle *ph);
5
+
6
+ VALUE pollhandle_new(VALUE class);
7
+ VALUE pollhandle_initialize(VALUE self);
8
+ VALUE pollhandle_notify_poll(VALUE self);
9
+
10
+ VALUE pollhandle_init(VALUE module);
data/ext/rfuse.c CHANGED
@@ -17,18 +17,44 @@
17
17
  #include "intern_rfuse.h"
18
18
  #include "filler.h"
19
19
  #include "context.h"
20
+
20
21
  #include "file_info.h"
22
+ #include "pollhandle.h"
23
+ #include "bufferwrapper.h"
21
24
 
22
25
  //this is a global variable where we store the fuse object
23
26
  static VALUE fuse_object;
24
27
 
28
+ #if !defined(STR2CSTR)
29
+ #define STR2CSTR(X) StringValuePtr(X)
30
+ #endif
31
+
32
+ // The ugliest hack I've seen today
33
+ #if HAVE_RUBY_RUBY_H
34
+ static VALUE ruby_errinfo()
35
+ {
36
+ return rb_errinfo();
37
+ }
38
+ #endif
39
+
25
40
  static int unsafe_return_error(VALUE *args)
26
41
  {
27
- VALUE info;
28
- info = rb_inspect(ruby_errinfo);
29
- rb_backtrace();
30
- printf ("ERROR %s\n",STR2CSTR(info));
31
- return rb_funcall(info,rb_intern("errno"),0);
42
+
43
+ if (rb_respond_to(ruby_errinfo,rb_intern("errno"))) {
44
+ //We expect these and they get passed on the fuse so be quiet...
45
+ return rb_funcall(ruby_errinfo,rb_intern("errno"),0);
46
+ } else {
47
+ VALUE info;
48
+ info = rb_inspect(ruby_errinfo);
49
+ printf ("ERROR: Exception %s not an Errno:: !respond_to?(:errno) \n",STR2CSTR(info));
50
+ //We need the ruby_errinfo backtrace not fuse.loop ... rb_backtrace();
51
+ VALUE bt_ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"),0);
52
+ int c;
53
+ for (c=0;c<RARRAY(bt_ary)->len;c++) {
54
+ printf("%s\n",RSTRING(RARRAY(bt_ary)->ptr[c])->ptr);
55
+ }
56
+ return Qnil;
57
+ }
32
58
  }
33
59
 
34
60
  static int return_error(int def_error)
@@ -39,14 +65,14 @@ static int return_error(int def_error)
39
65
  int error = 0;
40
66
  res=rb_protect((VALUE (*)())unsafe_return_error,Qnil,&error);
41
67
  if (error)
42
- { //this exception has no errno method or something else
43
- //went wrong
44
- printf ("ERROR: Not an Errno::xxx error or exception in exception!\n");
68
+ {
69
+ //something went wrong resolving the exception
70
+ printf ("ERROR: Exception in exception!\n");
45
71
  return def_error;
46
72
  }
47
- else
73
+ else
48
74
  {
49
- return FIX2INT(res);
75
+ return NIL_P(res) ? def_error : FIX2INT(res);
50
76
  }
51
77
  }
52
78
 
@@ -300,6 +326,7 @@ static int rf_open(const char *path,struct fuse_file_info *ffi)
300
326
  VALUE res;
301
327
  int error = 0;
302
328
  args[0]=rb_str_new2(path);
329
+ //GG: is args[1] kept on the stack and thus referenced from the GC's perspective?
303
330
  args[1]=wrap_file_info(ffi);
304
331
  res=rb_protect((VALUE (*)())unsafe_open,(VALUE) args,&error);
305
332
  if (error)
@@ -308,6 +335,10 @@ static int rf_open(const char *path,struct fuse_file_info *ffi)
308
335
  }
309
336
  else
310
337
  {
338
+ if (TYPE(ffi->fh) != T_NONE) {
339
+ //Make sure the GC doesn't collect our FileHandle
340
+ rb_gc_register_address((VALUE*) &ffi->fh);
341
+ }
311
342
  return 0;
312
343
  }
313
344
  }
@@ -332,7 +363,9 @@ static int rf_release(const char *path, struct fuse_file_info *ffi)
332
363
  args[0]=rb_str_new2(path);
333
364
  args[1]=wrap_file_info(ffi);
334
365
  res=rb_protect((VALUE (*)())unsafe_release,(VALUE) args,&error);
335
-
366
+ if (TYPE(ffi->fh) != T_NONE) {
367
+ rb_gc_unregister_address((VALUE*) &ffi->fh);
368
+ }
336
369
  if (error)
337
370
  {
338
371
  return -(return_error(ENOENT));
@@ -701,6 +734,22 @@ static VALUE unsafe_read(VALUE *args)
701
734
  wrap_context(ctx),path,size,offset,ffi);
702
735
  }
703
736
 
737
+
738
+
739
+ char*
740
+ rb_str2cstr(str, len)
741
+ VALUE str;
742
+ long *len;
743
+ {
744
+ StringValue(str);
745
+ if (len) *len = RSTRING_LEN(str);
746
+ else if (RTEST(ruby_verbose) && RSTRING_LEN(str) != ((long)strlen(RSTRING_PTR(str))) ) {
747
+ rb_warn("string contains \\0 character");
748
+ }
749
+ return RSTRING_PTR(str);
750
+ }
751
+
752
+
704
753
  static int rf_read(const char *path,char * buf, size_t size,off_t offset,struct fuse_file_info *ffi)
705
754
  {
706
755
  VALUE args[4];
@@ -724,7 +773,7 @@ static int rf_read(const char *path,char * buf, size_t size,off_t offset,struct
724
773
  {
725
774
  length = NUM2LONG(rb_funcall(res, rb_intern("length"), 0));
726
775
  rbuf = rb_str2cstr(res, &length);
727
- if (length<=size)
776
+ if (length<=(long)size)
728
777
  {
729
778
  memcpy(buf,rbuf,length);
730
779
  return length;
@@ -1442,19 +1491,82 @@ static int rf_bmap(const char *path, size_t blocksize, uint64_t *idx)
1442
1491
 
1443
1492
  //----------------------IOCTL
1444
1493
 
1494
+ static VALUE unsafe_ioctl(VALUE *args)
1495
+ {
1496
+ VALUE path = args[0];
1497
+ VALUE cmd = args[1];
1498
+ VALUE arg = args[2];
1499
+ VALUE ffi = args[3];
1500
+ VALUE flags = args[4];
1501
+ VALUE data = args[5];
1502
+
1503
+ struct fuse_context *ctx = fuse_get_context();
1504
+
1505
+ return rb_funcall( fuse_object, rb_intern("ioctl"), 7, wrap_context(ctx),
1506
+ path, cmd, arg, ffi, flags, data);
1507
+ }
1508
+
1445
1509
  static int rf_ioctl(const char *path, int cmd, void *arg,
1446
1510
  struct fuse_file_info *ffi, unsigned int flags, void *data)
1447
1511
  {
1448
- //TODO
1512
+ VALUE args[6];
1513
+ VALUE res;
1514
+ int error = 0;
1515
+
1516
+ args[0] = rb_str_new2(path);
1517
+ args[1] = INT2NUM(cmd);
1518
+ args[2] = wrap_buffer(arg);
1519
+ args[3] = wrap_file_info(ffi);
1520
+ args[4] = INT2NUM(flags);
1521
+ args[5] = wrap_buffer(data);
1522
+
1523
+ res = rb_protect((VALUE (*)())unsafe_ioctl,(VALUE) args, &error);
1524
+
1525
+ if (error)
1526
+ {
1527
+ return -(return_error(ENOENT));
1528
+ }
1529
+
1449
1530
  return 0;
1450
1531
  }
1451
1532
 
1452
1533
  //----------------------POLL
1453
1534
 
1535
+ static VALUE unsafe_poll(VALUE *args)
1536
+ {
1537
+ VALUE path = args[0];
1538
+ VALUE ffi = args[1];
1539
+ VALUE ph = args[2];
1540
+ VALUE reventsp = args[3];
1541
+
1542
+ struct fuse_context *ctx = fuse_get_context();
1543
+
1544
+ return rb_funcall( fuse_object, rb_intern("poll"), 5, wrap_context(ctx),
1545
+ path, ffi, ph, reventsp);
1546
+ }
1547
+
1454
1548
  static int rf_poll(const char *path, struct fuse_file_info *ffi,
1455
1549
  struct fuse_pollhandle *ph, unsigned *reventsp)
1456
1550
  {
1457
- //TODO
1551
+ VALUE args[4];
1552
+ VALUE res;
1553
+ int error = 0;
1554
+
1555
+ args[0] = rb_str_new2(path);
1556
+ args[1] = wrap_file_info(ffi);
1557
+ args[2] = wrap_pollhandle(ph);
1558
+ args[3] = INT2NUM(*reventsp);
1559
+
1560
+ res = rb_protect((VALUE (*)())unsafe_poll,(VALUE) args, &error);
1561
+
1562
+ if (error)
1563
+ {
1564
+ return -(return_error(ENOENT));
1565
+ }
1566
+ else
1567
+ {
1568
+ *reventsp = NUM2INT(args[3]);
1569
+ }
1458
1570
  return 0;
1459
1571
  }
1460
1572
 
@@ -1516,6 +1628,25 @@ VALUE rf_invalidate(VALUE self,VALUE path)
1516
1628
  return fuse_invalidate(inf->fuse,STR2CSTR(path)); //TODO: check if str?
1517
1629
  }
1518
1630
 
1631
+ //----------------------FD
1632
+ // Return /dev/fuse file descriptor for use with IO.select
1633
+ VALUE rf_fd(VALUE self)
1634
+ {
1635
+ struct intern_fuse *inf;
1636
+ Data_Get_Struct(self,struct intern_fuse,inf);
1637
+ return INT2NUM(intern_fuse_fd(inf));
1638
+ }
1639
+
1640
+ //----------------------PROCESS
1641
+ // Process one fuse command from the kernel
1642
+ // returns < 0 if we're not mounted.. won't be this simple in a mt scenario
1643
+ VALUE rf_process(VALUE self)
1644
+ {
1645
+ struct intern_fuse *inf;
1646
+ Data_Get_Struct(self,struct intern_fuse,inf);
1647
+ return INT2NUM(intern_fuse_process(inf));
1648
+ }
1649
+
1519
1650
  #define RESPOND_TO(obj,methodname) \
1520
1651
  rb_funcall( \
1521
1652
  obj,rb_intern("respond_to?"), \
@@ -1531,11 +1662,12 @@ static VALUE rf_initialize(
1531
1662
  VALUE libopts)
1532
1663
  {
1533
1664
  Check_Type(mountpoint, T_STRING);
1534
-
1535
- // getdir is deprecated, use readdir instead
1665
+ Check_Type(kernelopts, T_ARRAY);
1666
+ Check_Type(libopts, T_ARRAY);
1536
1667
 
1537
1668
  struct intern_fuse *inf;
1538
1669
  Data_Get_Struct(self,struct intern_fuse,inf);
1670
+
1539
1671
  if (RESPOND_TO(self,"getattr"))
1540
1672
  inf->fuse_op.getattr = rf_getattr;
1541
1673
  if (RESPOND_TO(self,"readlink"))
@@ -1613,9 +1745,10 @@ static VALUE rf_initialize(
1613
1745
  if (RESPOND_TO(self,"bmap"))
1614
1746
  inf->fuse_op.bmap = rf_bmap;
1615
1747
  if (RESPOND_TO(self,"ioctl"))
1616
- inf->fuse_op.ioctl = rf_ioctl; // TODO
1748
+ inf->fuse_op.ioctl = rf_ioctl;
1617
1749
  if (RESPOND_TO(self,"poll"))
1618
- inf->fuse_op.poll = rf_poll; // TODO
1750
+ inf->fuse_op.poll = rf_poll;
1751
+
1619
1752
 
1620
1753
  struct fuse_args
1621
1754
  *kargs = rarray2fuseargs(kernelopts),
@@ -1634,7 +1767,7 @@ static VALUE rf_new(VALUE class)
1634
1767
  struct intern_fuse *inf;
1635
1768
  VALUE self;
1636
1769
  inf = intern_fuse_new();
1637
- self=Data_Wrap_Struct(class, 0,intern_fuse_destroy,inf);
1770
+ self=Data_Wrap_Struct(class, 0, intern_fuse_destroy, inf);
1638
1771
  return self;
1639
1772
  }
1640
1773
 
@@ -1646,11 +1779,13 @@ VALUE rfuse_init(VALUE module)
1646
1779
 
1647
1780
  rb_define_method(cFuse,"initialize",rf_initialize,3);
1648
1781
  rb_define_method(cFuse,"loop",rf_loop,0);
1649
- rb_define_method(cFuse,"loop_mt",rf_loop_mt,0); //TODO: not until RIKE!
1782
+ rb_define_method(cFuse,"loop_mt",rf_loop_mt,0); //TODO: multithreading
1650
1783
  rb_define_method(cFuse,"exit",rf_exit,0);
1651
1784
  rb_define_method(cFuse,"invalidate",rf_invalidate,1);
1652
1785
  rb_define_method(cFuse,"unmount",rf_unmount,0);
1653
1786
  rb_define_method(cFuse,"mountname",rf_mountname,0);
1787
+ rb_define_method(cFuse,"fd",rf_fd,0);
1788
+ rb_define_method(cFuse,"process",rf_process,0);
1654
1789
 
1655
1790
  return cFuse;
1656
1791
  }
data/sample/test-ruby.rb CHANGED
@@ -347,7 +347,21 @@ class MyFuse < RFuse::Fuse
347
347
  return s
348
348
  end
349
349
 
350
+ def ioctl(ctx, path, cmd, arg, ffi, flags, data)
351
+ # FT: I was not been able to test it.
352
+ print "*** IOCTL: command: ", cmd, "\n"
353
+ end
354
+
355
+ def poll(ctx, path, ffi, ph, reventsp)
356
+ print "*** POLL: ", path, "\n"
357
+ # This is how we notify the caller if something happens:
358
+ ph.notifyPoll();
359
+ # when the GC harvests the object it calls fuse_pollhandle_destroy
360
+ # by itself.
361
+ end
362
+
350
363
  def init(ctx,rfuseconninfo)
364
+ print "RFuse-ng TestFS started\n"
351
365
  print "init called\n"
352
366
  print "proto_major: "
353
367
  print rfuseconninfo.proto_major
@@ -357,7 +371,13 @@ class MyFuse < RFuse::Fuse
357
371
 
358
372
  end #class Fuse
359
373
 
360
- fo = MyFuse.new("/tmp/fuse",["allow_other"],["debug"], MyDir.new("",493));
374
+ # Parameters are intended to passed as array elements. This clearly don't
375
+ # work with kernel options. The first element is discarded and the first
376
+ # element after the -o is also discarded. Somebody please figure this out,
377
+ # I already wasted half my weekend trying to solve this.
378
+
379
+ fo = MyFuse.new("/tmp/fuse",["notparsed","-o notparsed,allow_other"],["debug"], MyDir.new("",0777));
380
+
361
381
  #kernel: default_permissions,allow_other,kernel_cache,large_read,direct_io
362
382
  # max_read=N,fsname=NAME
363
383
  #library: debug,hard_remove
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rfuse-ng
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ hash: 13
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 3
10
+ version: 0.5.3
5
11
  platform: ruby
6
12
  authors:
7
13
  - !binary |
@@ -11,7 +17,7 @@ autorequire:
11
17
  bindir: bin
12
18
  cert_chain: []
13
19
 
14
- date: 2010-06-20 00:00:00 +02:00
20
+ date: 2011-02-27 00:00:00 +01:00
15
21
  default_executable:
16
22
  dependencies: []
17
23
 
@@ -26,7 +32,6 @@ extra_rdoc_files:
26
32
  - README.ng
27
33
  - README.rfuse
28
34
  files:
29
- - .gitignore
30
35
  - CHANGELOG.txt
31
36
  - LICENSE
32
37
  - README.ng
@@ -34,6 +39,8 @@ files:
34
39
  - Rakefile
35
40
  - THANKS
36
41
  - TODO.txt
42
+ - ext/bufferwrapper.c
43
+ - ext/bufferwrapper.h
37
44
  - ext/context.c
38
45
  - ext/context.h
39
46
  - ext/extconf.rb
@@ -45,6 +52,8 @@ files:
45
52
  - ext/helper.h
46
53
  - ext/intern_rfuse.c
47
54
  - ext/intern_rfuse.h
55
+ - ext/pollhandle.c
56
+ - ext/pollhandle.h
48
57
  - ext/rfuse.c
49
58
  - ext/rfuse.h
50
59
  - ext/rfuse_mod.c
@@ -55,26 +64,32 @@ homepage: http://rubyforge.org/projects/rfuse-ng
55
64
  licenses:
56
65
  - LGPL
57
66
  post_install_message:
58
- rdoc_options:
59
- - --charset=UTF-8
67
+ rdoc_options: []
68
+
60
69
  require_paths:
61
70
  - lib
62
71
  required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
63
73
  requirements:
64
74
  - - ">="
65
75
  - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
66
79
  version: "0"
67
- version:
68
80
  required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
69
82
  requirements:
70
83
  - - ">="
71
84
  - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
72
88
  version: "0"
73
- version:
74
89
  requirements: []
75
90
 
76
91
  rubyforge_project: rfuse-ng
77
- rubygems_version: 1.3.5
92
+ rubygems_version: 1.3.7
78
93
  signing_key:
79
94
  specification_version: 3
80
95
  summary: Ruby language binding for FUSE
data/.gitignore DELETED
@@ -1,7 +0,0 @@
1
- pkg
2
- *.gemspec
3
- *.o
4
- *.so
5
- *~
6
- Makefile
7
- pushgem.sh