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 +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
|