pfuse 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +14 -0
- data/API.txt +279 -0
- data/Changes.txt +63 -0
- data/LICENSE +21 -0
- data/README +36 -0
- data/Rakefile +20 -0
- data/TODO +11 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +12 -0
- data/ext/fusefs_fuse.c +150 -0
- data/ext/fusefs_fuse.h +19 -0
- data/ext/fusefs_lib.c +560 -0
- data/ext/fusefs_lib.h +119 -0
- data/hello.sh +10 -0
- data/lib/fusefs.rb +114 -0
- data/pfuse.gemspec +69 -0
- data/sample/demo.rb +100 -0
- data/sample/dictfs.rb +84 -0
- data/sample/hello.rb +27 -0
- data/sample/openurifs.rb +53 -0
- data/sample/railsfs.rb +77 -0
- data/sample/sqlfs.rb +134 -0
- data/sample/yamlfs.rb +168 -0
- data/test/fusefs_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +84 -0
data/ext/fusefs_lib.c
ADDED
@@ -0,0 +1,560 @@
|
|
1
|
+
// ruby-fuse
|
2
|
+
// A Ruby module to interact with the FUSE userland filesystem in
|
3
|
+
// a clear way.
|
4
|
+
|
5
|
+
// TODO
|
6
|
+
// * return values are inconsistent
|
7
|
+
// * fill in the rest of the fuse api
|
8
|
+
// * turn half of these into macros
|
9
|
+
// * sample FS for testing
|
10
|
+
|
11
|
+
#include "fusefs_lib.h"
|
12
|
+
|
13
|
+
// rf_getattr - FuseRoot.getattr should return a FuseFS::Stat object
|
14
|
+
static int
|
15
|
+
rf_getattr(const char *path, struct stat *stbuf)
|
16
|
+
{
|
17
|
+
VALUE cur_entry;
|
18
|
+
|
19
|
+
debug("rf_getattr(%s)\n", path);
|
20
|
+
|
21
|
+
memset(stbuf, 0, sizeof(struct stat));
|
22
|
+
cur_entry = rf_call("getattr", path, Qnil);
|
23
|
+
|
24
|
+
if (RTEST(cur_entry)) {
|
25
|
+
VSTAT2STAT(cur_entry, stbuf);
|
26
|
+
return 0;
|
27
|
+
} else {
|
28
|
+
return -ENOENT;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
// rf_readlink - resolve symlink then read bufsize into buf
|
33
|
+
|
34
|
+
// rf_mknod - make a special file node
|
35
|
+
static int
|
36
|
+
rf_mknod(const char *path, mode_t umode, dev_t rdev)
|
37
|
+
{
|
38
|
+
debug("rf_mknod(%s, 0%o)\n", path, umode);
|
39
|
+
|
40
|
+
// We ONLY permit regular files. No blocks, characters, fifos, etc.
|
41
|
+
if (!S_ISREG(umode)) {
|
42
|
+
return -EACCES;
|
43
|
+
}
|
44
|
+
|
45
|
+
// FuseFS.mknod only takes a path, since we don't handle non-files as above
|
46
|
+
if (!RTEST(rf_call("mknod", path, Qnil)))
|
47
|
+
return -EACCES;
|
48
|
+
|
49
|
+
return 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
// rf_mkdir - make a directory file
|
53
|
+
static int
|
54
|
+
rf_mkdir(const char *path, mode_t mode)
|
55
|
+
{
|
56
|
+
VALUE ret;
|
57
|
+
|
58
|
+
debug("rf_mkdir(%s, 0%o)\n", path, mode);
|
59
|
+
|
60
|
+
ret = rf_call("mkdir", path, UINT2NUM(mode));
|
61
|
+
|
62
|
+
if (RTEST(ret))
|
63
|
+
return NUM2INT(ret);
|
64
|
+
|
65
|
+
return -ENOENT;
|
66
|
+
}
|
67
|
+
|
68
|
+
// rf_unlink - remove directory entry
|
69
|
+
static int
|
70
|
+
rf_unlink(const char *path)
|
71
|
+
{
|
72
|
+
debug("rf_unlink(%s)\n", path);
|
73
|
+
|
74
|
+
if (!RTEST(rf_call("unlink", path, Qnil)))
|
75
|
+
return -ENOENT;
|
76
|
+
|
77
|
+
return 0;
|
78
|
+
}
|
79
|
+
|
80
|
+
// rf_rmdir - remove a directory file
|
81
|
+
static int
|
82
|
+
rf_rmdir(const char *path)
|
83
|
+
{
|
84
|
+
VALUE ret;
|
85
|
+
|
86
|
+
debug("rf_mkdir(%s)\n", path);
|
87
|
+
|
88
|
+
ret = rf_call("rmdir", path, Qnil);
|
89
|
+
|
90
|
+
if (RTEST(ret))
|
91
|
+
return NUM2INT(ret);
|
92
|
+
|
93
|
+
return -ENOENT;
|
94
|
+
}
|
95
|
+
|
96
|
+
// rf_symlink - make a symbolic link to a file
|
97
|
+
static int
|
98
|
+
rf_symlink(const char *path, const char *dest)
|
99
|
+
{
|
100
|
+
VALUE args;
|
101
|
+
VALUE ret;
|
102
|
+
|
103
|
+
debug("rf_symlink(%s, %s)\n", path, dest);
|
104
|
+
|
105
|
+
args = rb_ary_new();
|
106
|
+
rb_ary_push(args, rb_str_new2(dest));
|
107
|
+
|
108
|
+
ret = rf_call("symlink", path, args);
|
109
|
+
|
110
|
+
if (RTEST(ret))
|
111
|
+
return NUM2INT(ret);
|
112
|
+
|
113
|
+
return -ENOENT;
|
114
|
+
}
|
115
|
+
|
116
|
+
// rf_rename - change the name of a file
|
117
|
+
static int
|
118
|
+
rf_rename(const char *path, const char *dest)
|
119
|
+
{
|
120
|
+
VALUE ret;
|
121
|
+
VALUE args;
|
122
|
+
|
123
|
+
debug("rf_rename(%s, %s)\n", path, dest);
|
124
|
+
|
125
|
+
args = rb_ary_new();
|
126
|
+
rb_ary_push(args, rb_str_new2(dest));
|
127
|
+
|
128
|
+
ret = rf_call("rename", path, args);
|
129
|
+
|
130
|
+
if (RTEST(ret))
|
131
|
+
return NUM2INT(ret);
|
132
|
+
|
133
|
+
return 0;
|
134
|
+
}
|
135
|
+
|
136
|
+
// rf_link - make a hard file link
|
137
|
+
static int
|
138
|
+
rf_link(const char *path, const char *dest)
|
139
|
+
{
|
140
|
+
VALUE args;
|
141
|
+
VALUE ret;
|
142
|
+
|
143
|
+
debug("rf_link(%s, %s)\n", path, dest);
|
144
|
+
|
145
|
+
args = rb_ary_new();
|
146
|
+
rb_ary_push(args, rb_str_new2(dest));
|
147
|
+
|
148
|
+
ret = rf_call("link", path, args);
|
149
|
+
if (RTEST(ret))
|
150
|
+
return NUM2INT(ret);
|
151
|
+
|
152
|
+
return 0;
|
153
|
+
}
|
154
|
+
|
155
|
+
// rf_chmod - change mode of file
|
156
|
+
static int
|
157
|
+
rf_chmod(const char *path, mode_t mode)
|
158
|
+
{
|
159
|
+
VALUE ret;
|
160
|
+
|
161
|
+
debug("rf_chmod(%s, %o)\n", path, mode);
|
162
|
+
|
163
|
+
ret = rf_call("chmod", path, INT2NUM(mode));
|
164
|
+
|
165
|
+
if (RTEST(ret))
|
166
|
+
return NUM2INT(ret);
|
167
|
+
|
168
|
+
return -ENOENT;
|
169
|
+
}
|
170
|
+
|
171
|
+
// rf_chown - change owner and group of a file
|
172
|
+
|
173
|
+
// rf_truncate - truncate or extend a file to a specified length
|
174
|
+
static int
|
175
|
+
rf_truncate(const char *path, off_t offset)
|
176
|
+
{
|
177
|
+
VALUE ret;
|
178
|
+
|
179
|
+
debug("rf_truncate(%s, %d)\n", path, offset);
|
180
|
+
|
181
|
+
ret = rf_call("truncate", path, ULONG2NUM(offset));
|
182
|
+
|
183
|
+
if (RTEST(ret))
|
184
|
+
return NUM2INT(ret);
|
185
|
+
|
186
|
+
return -ENOENT;
|
187
|
+
}
|
188
|
+
|
189
|
+
// rf_utime - set file times
|
190
|
+
static int
|
191
|
+
rf_utime(const char *path, struct utimbuf *ubuf)
|
192
|
+
{
|
193
|
+
VALUE ret;
|
194
|
+
VALUE args;
|
195
|
+
|
196
|
+
args = rb_ary_new();
|
197
|
+
rb_ary_push(args, LONG2NUM(ubuf->actime));
|
198
|
+
rb_ary_push(args, LONG2NUM(ubuf->modtime));
|
199
|
+
|
200
|
+
ret = rf_call("utime", path, args);
|
201
|
+
|
202
|
+
if (RTEST(ret))
|
203
|
+
return ret;
|
204
|
+
|
205
|
+
// default to non-error because I don't see myself using this much
|
206
|
+
return 0;
|
207
|
+
}
|
208
|
+
|
209
|
+
// rf_open - open or create a file for reading or writing
|
210
|
+
// opening the file will probably be a noop for most backends
|
211
|
+
static int
|
212
|
+
rf_open(const char *path, struct fuse_file_info *fi)
|
213
|
+
{
|
214
|
+
char open_opts[4], *optr;
|
215
|
+
|
216
|
+
debug("rf_open(%s)\n", path);
|
217
|
+
|
218
|
+
optr = open_opts;
|
219
|
+
switch (fi->flags & 3) {
|
220
|
+
case 0:
|
221
|
+
*(optr++) = 'r';
|
222
|
+
break;
|
223
|
+
case 1:
|
224
|
+
*(optr++) = 'w';
|
225
|
+
break;
|
226
|
+
case 2:
|
227
|
+
*(optr++) = 'w';
|
228
|
+
*(optr++) = 'r';
|
229
|
+
break;
|
230
|
+
default:
|
231
|
+
debug("Opening a file with something other than rd, wr, or rdwr?");
|
232
|
+
}
|
233
|
+
|
234
|
+
if (fi->flags & O_APPEND)
|
235
|
+
*(optr++) = 'a';
|
236
|
+
*(optr) = '\0';
|
237
|
+
|
238
|
+
if (!RTEST(rf_call("open", path, rb_str_new2(open_opts)))) {
|
239
|
+
return -ENOENT;
|
240
|
+
}
|
241
|
+
|
242
|
+
return 0;
|
243
|
+
}
|
244
|
+
|
245
|
+
// rf_read - read input
|
246
|
+
static int
|
247
|
+
rf_read(
|
248
|
+
const char *path,
|
249
|
+
char *buf,
|
250
|
+
size_t size,
|
251
|
+
off_t offset,
|
252
|
+
struct fuse_file_info *fi)
|
253
|
+
{
|
254
|
+
VALUE ret;
|
255
|
+
VALUE args;
|
256
|
+
|
257
|
+
debug("rf_read(%s)\n", path);
|
258
|
+
|
259
|
+
args = rb_ary_new();
|
260
|
+
rb_ary_push(args, LONG2NUM(offset));
|
261
|
+
rb_ary_push(args, LONG2NUM(size));
|
262
|
+
|
263
|
+
ret = rf_call("read", path, args);
|
264
|
+
|
265
|
+
if (!RTEST(ret))
|
266
|
+
return 0;
|
267
|
+
|
268
|
+
if (TYPE(ret) != T_STRING)
|
269
|
+
return 0;
|
270
|
+
|
271
|
+
memcpy(buf, RSTRING(ret)->ptr, RSTRING(ret)->len);
|
272
|
+
return RSTRING(ret)->len;
|
273
|
+
}
|
274
|
+
|
275
|
+
// rf_write - write output
|
276
|
+
static int
|
277
|
+
rf_write(
|
278
|
+
const char *path,
|
279
|
+
const char *buf,
|
280
|
+
size_t size,
|
281
|
+
off_t offset,
|
282
|
+
struct fuse_file_info *fi)
|
283
|
+
{
|
284
|
+
VALUE ret;
|
285
|
+
VALUE args;
|
286
|
+
|
287
|
+
debug("rf_write(%s)\n", path);
|
288
|
+
|
289
|
+
args = rb_ary_new();
|
290
|
+
rb_ary_push(args, ULONG2NUM(offset));
|
291
|
+
rb_ary_push(args, ULONG2NUM(size));
|
292
|
+
rb_ary_push(args, rb_str_new(buf, size));
|
293
|
+
|
294
|
+
ret = rf_call("write", path, args);
|
295
|
+
|
296
|
+
if (RTEST(ret))
|
297
|
+
return NUM2INT(ret);
|
298
|
+
|
299
|
+
return 0UL;
|
300
|
+
}
|
301
|
+
|
302
|
+
// rf_statfs - get filesystem statistics
|
303
|
+
static int
|
304
|
+
rf_statfs(const char *path, struct statvfs *stbuf)
|
305
|
+
{
|
306
|
+
return 0;
|
307
|
+
// VALUE cur_entry;
|
308
|
+
|
309
|
+
// debug("rf_statfs(%s)\n", path);
|
310
|
+
|
311
|
+
// cur_entry = rf_call("statfs", path, Qnil);
|
312
|
+
|
313
|
+
// if (RTEST(cur_entry)) {
|
314
|
+
// VSTATVFS2STATVFS(cur_entry, stbuf);
|
315
|
+
// return 0;
|
316
|
+
// } else {
|
317
|
+
// return -ENOENT;
|
318
|
+
// }
|
319
|
+
}
|
320
|
+
|
321
|
+
// rf_flush - close file (after system calls close())
|
322
|
+
|
323
|
+
// rf_release - close file (the final flush)
|
324
|
+
static int
|
325
|
+
rf_release(const char *path, struct fuse_file_info *fi)
|
326
|
+
{
|
327
|
+
debug("rf_release(%s)\n", path);
|
328
|
+
|
329
|
+
if (!RTEST(rf_call("release", path, Qnil)))
|
330
|
+
return -ENOENT;
|
331
|
+
|
332
|
+
return 0;
|
333
|
+
}
|
334
|
+
|
335
|
+
// rf_fsync - synchronise a file's in-core state with that on disk
|
336
|
+
|
337
|
+
// rf_setxattr - set an extended attribute value
|
338
|
+
|
339
|
+
// rf_getxattr - get an extended attribute value
|
340
|
+
|
341
|
+
// rf_listxattr - list extended attribute names
|
342
|
+
|
343
|
+
// rf_removexattr - remove an extended attribute value
|
344
|
+
|
345
|
+
// rf_opendir - check if opendir is permitted for this directory
|
346
|
+
|
347
|
+
// rf_readdir - an array of FuseFS::Stat objects sent to fill_dir
|
348
|
+
static int
|
349
|
+
rf_readdir(
|
350
|
+
const char *path,
|
351
|
+
void *buf,
|
352
|
+
fuse_fill_dir_t filler,
|
353
|
+
off_t offset,
|
354
|
+
struct fuse_file_info *fi)
|
355
|
+
{
|
356
|
+
VALUE cur_entry;
|
357
|
+
VALUE retval;
|
358
|
+
struct stat *stbuf;
|
359
|
+
|
360
|
+
debug("rf_readdir(%s)\n", path);
|
361
|
+
|
362
|
+
stbuf = malloc(sizeof(struct stat));
|
363
|
+
|
364
|
+
// TODO maybe fi is interesting
|
365
|
+
// This is what fuse does to turn off 'unused' warnings.
|
366
|
+
(void) offset;
|
367
|
+
(void) fi;
|
368
|
+
|
369
|
+
// filler takes (void *dh_, const char *name, const struct stat *statp, off_t off)
|
370
|
+
// you can pass in NULL statp for defaults
|
371
|
+
// you can pass in 0 off for magic
|
372
|
+
|
373
|
+
// These two are always in a directory
|
374
|
+
filler(buf, ".", NULL, 0);
|
375
|
+
filler(buf, "..", NULL, 0);
|
376
|
+
|
377
|
+
retval = rf_call("readdir", path, Qnil);
|
378
|
+
if (!RTEST(retval) || (TYPE(retval) != T_ARRAY)) {
|
379
|
+
return 0;
|
380
|
+
}
|
381
|
+
|
382
|
+
while ((cur_entry = rb_ary_shift(retval)) != Qnil) {
|
383
|
+
VSTAT2STAT(cur_entry, stbuf);
|
384
|
+
filler(buf, STR2CSTR(rb_funcall(cur_entry, rb_intern("name"), 0)), stbuf, 0);
|
385
|
+
}
|
386
|
+
|
387
|
+
return 0;
|
388
|
+
}
|
389
|
+
|
390
|
+
// rf_releasedir - release dir (file returned from opendir is passed in)
|
391
|
+
|
392
|
+
// rf_fsyncdir - sync everything in the dir
|
393
|
+
static int
|
394
|
+
rf_fsyncdir(const char * path, int p, struct fuse_file_info *fi)
|
395
|
+
{
|
396
|
+
VALUE ret;
|
397
|
+
VALUE args;
|
398
|
+
|
399
|
+
// non-0 p means user data only, not metadata
|
400
|
+
args = rb_ary_new();
|
401
|
+
rb_ary_push(args, INT2NUM(p));
|
402
|
+
|
403
|
+
ret = rf_call("fsyncdir", path, args);
|
404
|
+
|
405
|
+
if (RTEST(ret))
|
406
|
+
return NUM2INT(ret);
|
407
|
+
|
408
|
+
// default to non-error because I don't see myself using this much
|
409
|
+
return 0;
|
410
|
+
}
|
411
|
+
|
412
|
+
// rf_access - check access permissions of a file or pathname
|
413
|
+
static int
|
414
|
+
rf_access(const char *path, int mask)
|
415
|
+
{
|
416
|
+
debug("rf_access(%s, %d)\n", path, mask);
|
417
|
+
return 0;
|
418
|
+
}
|
419
|
+
|
420
|
+
// rf_create - create and open a file
|
421
|
+
|
422
|
+
// rf_ftruncate - truncate() but called from system ftruncate()
|
423
|
+
|
424
|
+
// rf_fgetattr - getattr() but called if rf_create() is implemented
|
425
|
+
|
426
|
+
// rf_lock - perform POSIX file locking operation
|
427
|
+
|
428
|
+
// rf_utimens - utime with nanosecond resolution
|
429
|
+
|
430
|
+
// rf_bmap - map block index within file to block index within device
|
431
|
+
|
432
|
+
// rf_flag_nullpath_ok - accept NULL path
|
433
|
+
|
434
|
+
|
435
|
+
// rf_oper
|
436
|
+
static struct fuse_operations rf_oper = {
|
437
|
+
.getattr = rf_getattr,
|
438
|
+
.readdir = rf_readdir,
|
439
|
+
.mknod = rf_mknod,
|
440
|
+
.mkdir = rf_mkdir,
|
441
|
+
.unlink = rf_unlink,
|
442
|
+
.rmdir = rf_rmdir,
|
443
|
+
.rename = rf_rename,
|
444
|
+
.truncate = rf_truncate,
|
445
|
+
.utime = rf_utime,
|
446
|
+
.open = rf_open,
|
447
|
+
.read = rf_read,
|
448
|
+
.write = rf_write,
|
449
|
+
.statfs = rf_statfs,
|
450
|
+
.release = rf_release,
|
451
|
+
.fsyncdir = rf_fsyncdir,
|
452
|
+
};
|
453
|
+
|
454
|
+
static struct fuse_operations rf_unused_oper = {
|
455
|
+
.symlink = rf_symlink,
|
456
|
+
.access = rf_access,
|
457
|
+
.link = rf_link,
|
458
|
+
.chmod = rf_chmod,
|
459
|
+
};
|
460
|
+
|
461
|
+
// rf_set_root
|
462
|
+
VALUE
|
463
|
+
rf_set_root(VALUE self, VALUE rootval)
|
464
|
+
{
|
465
|
+
if (self != cFuseFS) {
|
466
|
+
rb_raise(cFSException, "Error: 'set_root' called outside of FuseFS?!");
|
467
|
+
return Qnil;
|
468
|
+
}
|
469
|
+
|
470
|
+
rb_iv_set(cFuseFS, "@root", rootval);
|
471
|
+
FuseRoot = rootval;
|
472
|
+
|
473
|
+
return Qtrue;
|
474
|
+
}
|
475
|
+
|
476
|
+
// rf_mount_to
|
477
|
+
VALUE
|
478
|
+
rf_mount_to(int argc, VALUE *argv, VALUE self)
|
479
|
+
{
|
480
|
+
struct fuse_args *opts;
|
481
|
+
VALUE mountpoint;
|
482
|
+
int i;
|
483
|
+
char *cur;
|
484
|
+
|
485
|
+
if (self != cFuseFS) {
|
486
|
+
rb_raise(cFSException, "Error: 'mount_to' called outside of FuseFS?!");
|
487
|
+
return Qnil;
|
488
|
+
}
|
489
|
+
|
490
|
+
if (argc == 0) {
|
491
|
+
rb_raise(rb_eArgError, "mount_to requires at least 1 argument!");
|
492
|
+
return Qnil;
|
493
|
+
}
|
494
|
+
|
495
|
+
mountpoint = argv[0];
|
496
|
+
|
497
|
+
Check_Type(mountpoint, T_STRING);
|
498
|
+
opts = ALLOC(struct fuse_args);
|
499
|
+
opts->argc = argc;
|
500
|
+
opts->argv = ALLOC_N(char *, opts->argc);
|
501
|
+
opts->allocated = 1;
|
502
|
+
|
503
|
+
// TODO why
|
504
|
+
opts->argv[0] = strdup("-odirect_io");
|
505
|
+
|
506
|
+
for (i = 1; i < argc; i++) {
|
507
|
+
cur = StringValuePtr(argv[i]);
|
508
|
+
opts->argv[i] = ALLOC_N(char, RSTRING(argv[i])->len + 2);
|
509
|
+
sprintf(opts->argv[i], "-o%s", cur);
|
510
|
+
}
|
511
|
+
|
512
|
+
// TODO debug(rf_unused_oper);
|
513
|
+
(void) rf_unused_oper;
|
514
|
+
|
515
|
+
rb_iv_set(cFuseFS, "@mountpoint", mountpoint);
|
516
|
+
fusefs_setup(STR2CSTR(mountpoint), &rf_oper, opts);
|
517
|
+
|
518
|
+
return Qtrue;
|
519
|
+
}
|
520
|
+
|
521
|
+
// rf_fd
|
522
|
+
VALUE
|
523
|
+
rf_fd(VALUE self)
|
524
|
+
{
|
525
|
+
int fd = fusefs_fd();
|
526
|
+
if (fd < 0)
|
527
|
+
return Qnil;
|
528
|
+
return INT2NUM(fd);
|
529
|
+
}
|
530
|
+
|
531
|
+
// rf_process
|
532
|
+
VALUE
|
533
|
+
rf_process(VALUE self)
|
534
|
+
{
|
535
|
+
fusefs_process();
|
536
|
+
return Qnil;
|
537
|
+
}
|
538
|
+
|
539
|
+
// Init_fusefs_lib()
|
540
|
+
void
|
541
|
+
Init_fusefs_lib() {
|
542
|
+
init_time = time(NULL);
|
543
|
+
|
544
|
+
/* module FuseFS */
|
545
|
+
cFuseFS = rb_define_module("FuseFS");
|
546
|
+
|
547
|
+
/* Our exception */
|
548
|
+
cFSException = rb_define_class_under(cFuseFS, "FuseFSException",
|
549
|
+
rb_eStandardError);
|
550
|
+
|
551
|
+
/* def Fuse.run */
|
552
|
+
rb_define_singleton_method(cFuseFS, "fuse_fd", rf_fd, 0);
|
553
|
+
rb_define_singleton_method(cFuseFS, "process", rf_process, 0);
|
554
|
+
rb_define_singleton_method(cFuseFS, "mount_to", rf_mount_to, -1);
|
555
|
+
rb_define_singleton_method(cFuseFS, "mount_under", rf_mount_to, -1);
|
556
|
+
rb_define_singleton_method(cFuseFS, "mountpoint", rf_mount_to, -1);
|
557
|
+
rb_define_singleton_method(cFuseFS, "set_root", rf_set_root, 1);
|
558
|
+
rb_define_singleton_method(cFuseFS, "root=", rf_set_root, 1);
|
559
|
+
}
|
560
|
+
|
data/ext/fusefs_lib.h
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#define FUSE_USE_VERSION 26
|
2
|
+
#define _FILE_OFFSET_BITS 64
|
3
|
+
|
4
|
+
#include <fuse.h>
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <string.h>
|
7
|
+
#include <errno.h>
|
8
|
+
#include <sys/types.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <fcntl.h>
|
11
|
+
#include <unistd.h>
|
12
|
+
#include <ruby.h>
|
13
|
+
#include <stdarg.h>
|
14
|
+
|
15
|
+
#include "fusefs_fuse.h"
|
16
|
+
|
17
|
+
#define VSTAT2STAT(cur_entry, stbuf) do {\
|
18
|
+
stbuf->st_mode = NUM2INT (rb_funcall(cur_entry, rb_intern("st_mode"), 0)); \
|
19
|
+
stbuf->st_nlink = NUM2INT (rb_funcall(cur_entry, rb_intern("st_nlink"), 0)); \
|
20
|
+
stbuf->st_size = NUM2LONG (rb_funcall(cur_entry, rb_intern("st_size"), 0)); \
|
21
|
+
stbuf->st_uid = NUM2INT (rb_funcall(cur_entry, rb_intern("st_uid"), 0)); \
|
22
|
+
stbuf->st_gid = NUM2INT (rb_funcall(cur_entry, rb_intern("st_gid"), 0)); \
|
23
|
+
stbuf->st_mtime = NUM2ULONG(rb_funcall(cur_entry, rb_intern("st_mtime"), 0)); \
|
24
|
+
stbuf->st_atime = NUM2ULONG(rb_funcall(cur_entry, rb_intern("st_atime"), 0)); \
|
25
|
+
stbuf->st_ctime = NUM2ULONG(rb_funcall(cur_entry, rb_intern("st_ctime"), 0)); \
|
26
|
+
} while (0)
|
27
|
+
|
28
|
+
#define VSTATVFS2STATVFS(cur_entry, stbuf) do {\
|
29
|
+
memset(stbuf, 0, sizeof(struct statvfs)); \
|
30
|
+
stbuf->f_bsize = NUM2INT(rb_funcall(cur_entry, rb_intern("f_bsize"), 0)); \
|
31
|
+
stbuf->f_frsize = NUM2INT(rb_funcall(cur_entry, rb_intern("f_frsize"), 0)); \
|
32
|
+
stbuf->f_blocks = NUM2INT(rb_funcall(cur_entry, rb_intern("f_blocks"), 0)); \
|
33
|
+
stbuf->f_bfree = NUM2INT(rb_funcall(cur_entry, rb_intern("f_bfree"), 0)); \
|
34
|
+
stbuf->f_bavail = NUM2INT(rb_funcall(cur_entry, rb_intern("f_bavail"), 0)); \
|
35
|
+
stbuf->f_files = NUM2INT(rb_funcall(cur_entry, rb_intern("f_files"), 0)); \
|
36
|
+
stbuf->f_ffree = NUM2INT(rb_funcall(cur_entry, rb_intern("f_ffree"), 0)); \
|
37
|
+
stbuf->f_favail = NUM2INT(rb_funcall(cur_entry, rb_intern("f_favail"), 0)); \
|
38
|
+
stbuf->f_fsid = NUM2INT(rb_funcall(cur_entry, rb_intern("f_fsid"), 0)); \
|
39
|
+
stbuf->f_flag = NUM2INT(rb_funcall(cur_entry, rb_intern("f_flag"), 0)); \
|
40
|
+
stbuf->f_namemax = NUM2INT(rb_funcall(cur_entry, rb_intern("f_namemax"), 0)); \
|
41
|
+
} while (0)
|
42
|
+
|
43
|
+
// Ruby Constants constants
|
44
|
+
VALUE cFuseFS = Qnil; /* FuseFS class */
|
45
|
+
VALUE cFSException = Qnil; /* Our Exception. */
|
46
|
+
VALUE FuseRoot = Qnil; /* The root object we call */
|
47
|
+
|
48
|
+
typedef unsigned long int (*rbfunc)();
|
49
|
+
|
50
|
+
// file created, modified timestamp
|
51
|
+
// TODO no
|
52
|
+
time_t init_time;
|
53
|
+
|
54
|
+
// debug()
|
55
|
+
static void
|
56
|
+
debug(char *msg,...)
|
57
|
+
{
|
58
|
+
va_list ap;
|
59
|
+
va_start(ap,msg);
|
60
|
+
vfprintf(stdout,msg,ap);
|
61
|
+
}
|
62
|
+
|
63
|
+
// rf_protected and rf_call
|
64
|
+
//
|
65
|
+
// Used for: protection.
|
66
|
+
//
|
67
|
+
// This is called by rb_protect, and will make a call using
|
68
|
+
// the above rb_path and to_call ID to call the method safely
|
69
|
+
// on FuseRoot.
|
70
|
+
//
|
71
|
+
// We call rf_call(path,method_id), and rf_call will use rb_protect
|
72
|
+
// to call rf_protected, which makes the call on FuseRoot and returns
|
73
|
+
// whatever the call returns.
|
74
|
+
static VALUE
|
75
|
+
rf_protected(VALUE args)
|
76
|
+
{
|
77
|
+
ID to_call = SYM2ID(rb_ary_shift(args));
|
78
|
+
return rb_apply(FuseRoot,to_call,args);
|
79
|
+
}
|
80
|
+
|
81
|
+
static VALUE
|
82
|
+
rf_call(char *methname, const char *path, VALUE arg)
|
83
|
+
{
|
84
|
+
int error;
|
85
|
+
VALUE result;
|
86
|
+
VALUE methargs;
|
87
|
+
ID method;
|
88
|
+
|
89
|
+
method = rb_intern(methname);
|
90
|
+
|
91
|
+
if (arg == Qnil) {
|
92
|
+
debug(" root.%s(%s)\n", methname, path);
|
93
|
+
} else {
|
94
|
+
debug(" root.%s(%s,...)\n", methname, path);
|
95
|
+
}
|
96
|
+
|
97
|
+
if (TYPE(arg) == T_ARRAY) {
|
98
|
+
methargs = arg;
|
99
|
+
} else if (arg != Qnil) {
|
100
|
+
methargs = rb_ary_new();
|
101
|
+
rb_ary_push(methargs,arg);
|
102
|
+
} else {
|
103
|
+
methargs = rb_ary_new();
|
104
|
+
}
|
105
|
+
|
106
|
+
rb_ary_unshift(methargs,rb_str_new2(path));
|
107
|
+
rb_ary_unshift(methargs,ID2SYM(method));
|
108
|
+
|
109
|
+
/* Set up the call and make it. */
|
110
|
+
result = rb_protect(rf_protected, methargs, &error);
|
111
|
+
|
112
|
+
/* Did it error? */
|
113
|
+
if (error) {
|
114
|
+
return Qnil;
|
115
|
+
}
|
116
|
+
|
117
|
+
return result;
|
118
|
+
}
|
119
|
+
|