rfuse-ng 0.4.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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