pfuse 0.7.5
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/.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
|
+
|