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 +68 -0
- data/Rakefile +3 -1
- data/TODO.txt +22 -1
- data/ext/bufferwrapper.c +48 -0
- data/ext/bufferwrapper.h +10 -0
- data/ext/file_info.c +35 -5
- data/ext/filler.c +9 -4
- data/ext/helper.c +6 -10
- data/ext/helper.h +5 -0
- data/ext/intern_rfuse.c +39 -5
- data/ext/intern_rfuse.h +2 -0
- data/ext/pollhandle.c +54 -0
- data/ext/pollhandle.h +10 -0
- data/ext/rfuse.c +155 -20
- data/sample/test-ruby.rb +21 -1
- metadata +23 -8
- data/.gitignore +0 -7
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.
|
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
|
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).
|
data/ext/bufferwrapper.c
ADDED
@@ -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
|
+
}
|
data/ext/bufferwrapper.h
ADDED
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
|
-
|
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
|
-
|
21
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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->
|
54
|
-
args->
|
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 =
|
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
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
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
{
|
43
|
-
//went wrong
|
44
|
-
printf ("ERROR:
|
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
|
-
|
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
|
-
|
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
|
-
|
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;
|
1748
|
+
inf->fuse_op.ioctl = rf_ioctl;
|
1617
1749
|
if (RESPOND_TO(self,"poll"))
|
1618
|
-
inf->fuse_op.poll = rf_poll;
|
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:
|
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
|
-
|
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
|
-
|
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:
|
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
|
-
|
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.
|
92
|
+
rubygems_version: 1.3.7
|
78
93
|
signing_key:
|
79
94
|
specification_version: 3
|
80
95
|
summary: Ruby language binding for FUSE
|