pfuse 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ *.o
7
+ *.bundle
8
+ *.log
9
+ Makefile
10
+ pid
11
+ hello
12
+ ext/conftest.dSYM/
13
+ tags
14
+ old.c
data/API.txt ADDED
@@ -0,0 +1,279 @@
1
+ FuseFS API DOCUMENT
2
+ ===================
3
+
4
+ Last updated: 2005.09.19 by Greg Millam
5
+
6
+ WARNING
7
+ -------
8
+
9
+ Note: If you use DirLink (in demo.rb) or in any way access a FuseFS filesystem
10
+ from *within* the ruby script accessing the FuseFS, then FuseFS will hang, and
11
+ the only recourse is a kill -KILL.
12
+
13
+ Also: If there are any open files or shells with 'pwd's in your filesystem
14
+ when you exit your ruby script, fuse *might* not actually be unmounted. To
15
+ unmount a path yourself, run the command:
16
+
17
+ fusermount -u <path>
18
+
19
+ to unmount any FUSE filesystems mounted at <path>.
20
+
21
+
22
+ FuseFS API
23
+ ----------
24
+
25
+
26
+ FuseFS provides a layer of abstraction to a programmer who wants to create a
27
+ virtual filesystem via FUSE.
28
+
29
+ FuseFS programs consist of two parts:
30
+
31
+ 1) FuseFS, which is defined in 'fusefs.rb'
32
+ 2) An object that defines a virtual directory. This must define a number of
33
+ methods (given below, in "Directory Methods" section) in order to be
34
+ usable.
35
+
36
+ To write a FuseFS program, you must:
37
+
38
+ * Define and create a Directory object that responds to the methods required
39
+ by FuseFS for its desired use.
40
+
41
+ * Call FuseFS.set_root <virtualdir> with the object defining your virtual
42
+ directory.
43
+
44
+ * Mount FuseFS under a real directory on your filesystem.
45
+
46
+ * Call FuseFS.run to start receiving and executing events.
47
+
48
+ Happy Filesystem Hacking!
49
+
50
+
51
+ Hello World FS
52
+ --------------
53
+ helloworld.rb
54
+
55
+ This creates a filesystem that contains exactly 1 file: "hello.txt" that, when
56
+ read, returns "Hello, World!"
57
+
58
+ This is not writable to, and contains no other files.
59
+
60
+ require 'fusefs'
61
+
62
+ class HelloDir
63
+ def contents(path)
64
+ ['hello.txt']
65
+ end
66
+ def file?(path)
67
+ path -- '/hello.txt'
68
+ end
69
+ def read_file(path)
70
+ "Hello, World!\n"
71
+ end
72
+ end
73
+
74
+ hellodir = HelloDir.new
75
+ FuseFS.set_root( hellodir )
76
+
77
+ # Mount under a directory given on the command line.
78
+ FuseFS.mount_under ARGV.shift
79
+ FuseFS.run
80
+
81
+
82
+ Directory Methods
83
+ -----------------
84
+
85
+ Without any methods defined, any object is by default a content-less,
86
+ file-less directory.
87
+
88
+ The following are necessary for most or all filesystems:
89
+
90
+ Directory listing and file type methods:
91
+
92
+ :contents(path) # Return an array of file and dirnames within <path>.
93
+ :directory?(path) # Return true if <path> is a directory.
94
+ :file?(path) # Return true if <path> is a file (not a directory).
95
+ :executable?(path) # Return true if <path> is an executable file.
96
+ :size(path) # Return the file size. Necessary for apache, xmms,
97
+ etc.
98
+
99
+ File reading:
100
+
101
+ :read_file(path) # Return the contents of the file at location <path>.
102
+
103
+ The following are only necessary if you want a filesystem that can be modified
104
+ by the user. Without defining any of the below, the contents of the filesystem
105
+ are automatically read-only.
106
+
107
+ File manipulation:
108
+
109
+ :can_write?(path) # Return true if the user can write to file at <path>.
110
+ :write_to(path,str) # Write the contents of <str> to file at <path>.
111
+
112
+ :can_delete?(path) # Return true if the user can delete file at <path>.
113
+ :delete(path) # Delete the file at <path>
114
+
115
+ Directory manipulation:
116
+
117
+ :can_mkdir?(path) # Return true if user can make a directory at <path>.
118
+ :mkdir(path) # Make a directory at path.
119
+
120
+ :can_rmdir?(path) # Return true if user can remove directory at <path>.
121
+ :rmdir(path) # Remove it.
122
+
123
+ Neat "toy":
124
+
125
+ :touch(path) # Called when a file is 'touch'd or otherwise has
126
+ their timestamps explicitly modified. I envision
127
+ this as a neat toy, maybe you can use it for a
128
+ push-button file?
129
+ "touch button" -> unmounts fusefs?
130
+ "touch musicfile.mp3" -> Play the mp3.
131
+
132
+ If you want a lower level control of your file, then you can use:
133
+
134
+ :raw_open(path,mode) # mode is "r" "w" or "rw", with "a" if the file
135
+ is opened for append. If raw_open returns true,
136
+ then the following calls are made:
137
+ :raw_read(path,off,sz) # Read sz bites from file at path starting at
138
+ offset off
139
+ :raw_write(path,off,sz,buf) # Write sz bites of buf to path starting at
140
+ offset off
141
+ :raw_close(path) # Close the file.
142
+
143
+
144
+ Method call flow
145
+ ================
146
+
147
+ List contents:
148
+ :directory? will be checked before :contents
149
+ (Most 'ls' or 'dir' functions will go on next
150
+ to getattr() for all contents)
151
+
152
+ Read file:
153
+ :file? will be checked before :read_file
154
+
155
+ Getattr
156
+ :directory? will be checked first.
157
+
158
+ :file? will be checked before :can_write?
159
+ :file? will be checked before :executable?
160
+
161
+ Writing files:
162
+ * directory? is usually called on the directory
163
+ The FS wants to write a new file to, before this
164
+ can occur.
165
+ :can_write? will be checked before :write_to
166
+
167
+ Deleting files:
168
+ :file? will be checked before :can_delete?
169
+ :can_delete? will be checked before :delete
170
+
171
+ Creating dirs:
172
+ * directory? is usually called on the directory
173
+ The FS wants to make a new directory in, before
174
+ this can occur.
175
+ :directory? will be checked.
176
+ :can_mkdir? is called only if :directory? is false.
177
+ :can_mkdir? will be checked before :mkdir
178
+
179
+ Deleting dirs:
180
+ :directory? will be checked before :can_rmdir?
181
+ :can_rmdir? will be checked before :rmdir
182
+
183
+
184
+ module FuseFS
185
+ -------------
186
+
187
+ FuseFS methods:
188
+
189
+ FuseFS.set_root(object)
190
+ Set the root virtual directory to <object>. All queries for obtaining
191
+ file information is directed at object.
192
+
193
+ FuseFS.mount_under(path[,opt[,opt,...]])
194
+ This will cause FuseFS to virtually mount itself under the given path.
195
+ 'path' is required to be a valid directory in your actual filesystem.
196
+
197
+ 'opt's are FUSE options. Most likely, you will only want 'allow_other'
198
+ or 'allow_root'. The two are mutually exclusive in FUSE, but allow_other
199
+ will let other users, including root, access your filesystem. allow_root
200
+ will only allow root to access it.
201
+
202
+ Also available for FuseFS users are:
203
+ default_permissions, max_read=N, fsname=NAME.
204
+
205
+ For more information, look at FUSE.
206
+
207
+ (P.S: I know FUSE allows other options, but I don't think any of the
208
+ rest will do any good with FuseFS. If you think otherwise, please let me
209
+ know!)
210
+
211
+ FuseFS.run
212
+ This is the final step to make your virtual filesystem accessible. It is
213
+ recommended you run this as your main thread, but you can thread off to
214
+ run this.
215
+
216
+ FuseFS.handle_editor = bool (true by default)
217
+ If handle_editor is true, then FuseFS will attempt to capture all editor
218
+ files and prevent them from being passed to FuseRoot. It also prevents
219
+ created and unmodified files from being passed as well, as vim (among
220
+ others) will attempt to create and then remove a file that does not
221
+ exist.
222
+
223
+ FuseFS.reader_uid and FuseFS.reader_gid
224
+ When the filesystem is accessed, the accessor's uid or gid is returned
225
+ by FuseFS.reader_uid and FuseFS.reader_gid. You can use this in
226
+ determining your permissions, or even provide different files for
227
+ different users!
228
+
229
+ FuseFS.fuse_fd and FuseFS.process
230
+ These are not intended for use by the programmer. If you want to muck
231
+ with this, read the code to see what they do :D.
232
+
233
+
234
+
235
+ FuseDir
236
+ ----------
237
+
238
+ FuseFS::FuseDir defines the methods "split_path" and "scan_path". You
239
+ should typically inherit from FuseDir in your own directory objects.
240
+
241
+ base, rest = split_path(path) # base is the file or directory in the
242
+ current context. rest is either nil,
243
+ or a path that is requested. If 'rest'
244
+ exists, then you should recurse the paths.
245
+ base, *rest = scan_path(path) # scan_path returns an array of all
246
+ directory and file elements given by
247
+ <path>. This is useful when you're
248
+ encapsulating an entire fs into one
249
+ object.
250
+
251
+ MetaDir
252
+ -------
253
+
254
+ MetaDir is a full filesystem defined with hashes. It is writable, and the user
255
+ can create and edit files within it, as well as the programmer.
256
+
257
+ Usage:
258
+ root = MetaDir.new
259
+
260
+ root.mkdir("/hello")
261
+ root.write_to("/hello/world","Hello, World!\n")
262
+ root.write_to("/hello/everybody","Hello, Everybody!\n")
263
+
264
+ FuseFS.set_root(root)
265
+
266
+ Because MetaDir is fully recursive, you can mount your own or other defined
267
+ directory structures under it. For example, to mount a dictionary filesystem
268
+ (as demonstrated in samples/dictfs.rb), use:
269
+
270
+ root.mkdir("/dict",DictFS.new)
271
+
272
+ Conclusion
273
+ ----------
274
+
275
+ Happy Hacking! If you do anything neat with this, please let me know!
276
+
277
+ My email address is walker@deafcode.com
278
+
279
+ Thanks for using FuseFS!
data/Changes.txt ADDED
@@ -0,0 +1,63 @@
1
+ FuseFS 0.7
2
+ ==========
3
+
4
+ * It's now a Rubygem on Github
5
+
6
+ FuseFS 0.6
7
+ ==========
8
+
9
+ * FuseFS.mount_under() now takes FUSE options as optional arguments, such as
10
+ 'allow_other' and 'allow_root'
11
+ * rmdir now works. (Whoops!)
12
+
13
+ FuseFS 0.5.1
14
+ ============
15
+
16
+ * Bugfix for dealing with raw files (Thanks, Kent Sibilev)
17
+
18
+ FuseFS 0.5
19
+ ==========
20
+
21
+ * Fixed for FUSE 2.4. direct_io turned from a mount option in 2.3 to a lib
22
+ option in 2.4.
23
+ * _why_the_lucky_stiff's railsfs.rb added to the samples/ dir.
24
+ * FuseRoot#raw_open is called with the path and "r" "w" "rw" for read or
25
+ write modes, along with "a" if it is called for appending.
26
+ * If raw_open returns true, FuseFS will call raw_read, raw_write, and
27
+ raw_close at necessary points. (See API.txt)
28
+ * FuseRoot#size is optionally called to determine file sizes, should the
29
+ user want a file size to be reported as anything other than 0.
30
+
31
+ FuseFS 0.4
32
+ ==========
33
+
34
+ * Stronger and more robust handling of editor swap files, but still
35
+ incomplete.
36
+ * Peppered with debug statements.
37
+ * A bit cleaner method of calling ruby functions.
38
+ * rf_rename fixed. Whoops!
39
+
40
+ FuseFS 0.3
41
+ ==========
42
+
43
+ * read_file borked FuseFS when a binary file was returned. Instead of using
44
+ strdup, it now mallocs according to the returned size, as appropriate.
45
+ * Addition of sample/openurifs.rb
46
+ * 'touch file' emptied a file, since it opened and then released without
47
+ writing. I added a 'modified' flag to fix this.
48
+ * 'touch' method call added, and called when a program attempts to modify
49
+ a file's time.
50
+ * 'executable?' check added in case programmer wants to the file to report
51
+ itself as executable to the filesystem.
52
+ * vim and emacs swap files are not passed to FuseFS =).
53
+
54
+ FuseFS 0.2
55
+ ==========
56
+
57
+ * Fix call for deleting files from 'remove' to 'delete' to match API spec.
58
+ * Addition of sample/yamlfs.rb
59
+
60
+ FuseFS 0.1
61
+ ==========
62
+
63
+ Initial import.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2005 Greg Millam.
2
+ Copyright (c) 2009 Kyle Maxwell.
3
+ Copyright (c) 2009 David Turnbull.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README ADDED
@@ -0,0 +1,36 @@
1
+ PFuseFS README
2
+ ============
3
+ Plain FUSE bindings.
4
+ The C ext is derived from fusefs-osx but stripped back to allow more logic in Ruby - the language you'd rather do tricky things in.
5
+ The FuseFS library also includes FuseFS::DirEntry, FuseFS::FileEntry and FuseFS::Entries helpers, the latter calling back to your getattr function to create an accurate stat struct.
6
+
7
+ Requirements
8
+ ------------
9
+ * FUSE (http://fuse.sourceforge.org)
10
+ * Ruby 1.8
11
+ (* C compiler)
12
+
13
+ Install
14
+ -------
15
+ gem install dsturnbull-fusefs
16
+
17
+ Usage
18
+ -----
19
+ require 'fusefs'
20
+
21
+ Some sample ruby filesystems are listed in "sample/"
22
+
23
+ When you run a fusefs script, it will listen on a socket indefinitely, so
24
+ either background the script or open another terminal to mosey around in the
25
+ filesystem.
26
+
27
+ Also, check the API.txt file for more use.
28
+
29
+
30
+ License
31
+ -------
32
+ MIT license, in file "LICENSE"
33
+
34
+
35
+ Authors: David Turnbull <dsturnbull@me.com>
36
+ Inspired by: Greg Millam <walker@deafcode.com>, Kyle Maxwell <kyle@kylemaxwell.com> (fizx/fusefs-osx)
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "pfuse"
8
+ gem.summary = %Q{fusefs}
9
+ gem.description = %Q{Gemified}
10
+ gem.email = "dsturnbull@gmail.com"
11
+ gem.homepage = "http://github.com/dsturnbull/pfuse"
12
+ gem.authors = ["David Turnbull", "Kyle Maxwell"]
13
+ gem.extensions = ["ext/extconf.rb"]
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ task :default => :build
data/TODO ADDED
@@ -0,0 +1,11 @@
1
+ TODO for FuseFS
2
+ ===============
3
+
4
+ - Problem with editors: vim attempts to create and then delete a numbered file.
5
+ This can be an issue if the filename (all digits) is reported as not valid.
6
+
7
+ I am looking for a solution for this, but it's gonna be a pain.
8
+
9
+ - Tests, more tests, and unit tests!
10
+
11
+ - Consider FIFOs? We can use FIFOs to mimic TCP internet, if we do this right.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.5
data/ext/extconf.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'mkmf'
2
+
3
+ #$CFLAGS << ' -fnested-functions'
4
+ $CFLAGS << ' -Wall'
5
+ $CFLAGS << ' -Werror'
6
+
7
+ dir_config('fusefs_lib.so')
8
+ if have_library('fuse_ino64') || have_library('fuse')
9
+ create_makefile('fusefs_lib')
10
+ else
11
+ puts "No FUSE install available"
12
+ end
data/ext/fusefs_fuse.c ADDED
@@ -0,0 +1,150 @@
1
+ /* fusefs_fuse.c */
2
+
3
+ /* This is rewriting most of the things that occur
4
+ * in fuse_main up through fuse_loop */
5
+
6
+ #define FUSE_USE_VERSION 26
7
+ #define _FILE_OFFSET_BITS 64
8
+
9
+ #include <fuse.h>
10
+ #include <fuse/fuse_lowlevel.h>
11
+ #include <stdio.h>
12
+ #include <string.h>
13
+ #include <stdlib.h>
14
+ #include <unistd.h>
15
+ #include <limits.h>
16
+ #include <errno.h>
17
+ #include <assert.h>
18
+ #include <stdint.h>
19
+ #include <sys/param.h>
20
+ #include <sys/uio.h>
21
+ #include <signal.h>
22
+
23
+ struct fuse *fuse_instance = NULL;
24
+ struct fuse_chan *fusech = NULL;
25
+ static char *mounted_at = NULL;
26
+
27
+ static int set_one_signal_handler(int signal, void (*handler)(int));
28
+
29
+ int fusefs_fd() {
30
+ if(fusech == NULL)
31
+ return -1;
32
+ return fuse_chan_fd(fusech);
33
+ }
34
+
35
+ int
36
+ fusefs_unmount() {
37
+ char buf[128];
38
+
39
+ if (mounted_at && fusech) {
40
+ fuse_unmount(mounted_at, fusech);
41
+ sprintf(buf, "/sbin/umount %s", mounted_at);
42
+ system(buf);
43
+ }
44
+ if (fuse_instance)
45
+ fuse_destroy(fuse_instance);
46
+ fuse_instance = NULL;
47
+ free(mounted_at);
48
+ fusech = NULL;
49
+
50
+ return 0;
51
+ }
52
+
53
+ static void
54
+ fusefs_ehandler() {
55
+ if (fuse_instance != NULL) {
56
+ fusefs_unmount();
57
+ }
58
+ }
59
+
60
+ int
61
+ fusefs_setup(char *mountpoint, const struct fuse_operations *op, struct fuse_args *opts) {
62
+ fusech = NULL;
63
+ if (fuse_instance != NULL) {
64
+ return 0;
65
+ }
66
+ if (mounted_at != NULL) {
67
+ return 0;
68
+ }
69
+
70
+ /* First, mount us */
71
+ fusech = fuse_mount(mountpoint, opts);
72
+ if (fusech == NULL) return 0;
73
+
74
+ fuse_instance = fuse_new(fusech, opts, op, sizeof(*op), NULL);
75
+ if (fuse_instance == NULL)
76
+ goto err_unmount;
77
+
78
+ /* Set signal handlers */
79
+ if (set_one_signal_handler(SIGHUP, fusefs_ehandler) == -1 ||
80
+ set_one_signal_handler(SIGINT, fusefs_ehandler) == -1 ||
81
+ set_one_signal_handler(SIGTERM, fusefs_ehandler) == -1 ||
82
+ set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
83
+ return 0;
84
+
85
+ atexit(fusefs_ehandler);
86
+
87
+ /* We've initialized it! */
88
+ mounted_at = strdup(mountpoint);
89
+ return 1;
90
+ err_unmount:
91
+ fuse_unmount(mountpoint, fusech);
92
+ return 0;
93
+ }
94
+
95
+ int
96
+ fusefs_uid() {
97
+ struct fuse_context *context = fuse_get_context();
98
+ if (context) return context->uid;
99
+ return -1;
100
+ }
101
+
102
+ int
103
+ fusefs_gid() {
104
+ struct fuse_context *context = fuse_get_context();
105
+ if (context) return context->gid;
106
+ return -1;
107
+ }
108
+
109
+ int
110
+ fusefs_process() {
111
+ /* This gets exactly 1 command out of fuse fd. */
112
+ /* Ideally, this is triggered after a select() returns */
113
+ if (fuse_instance != NULL) {
114
+ struct fuse_cmd *cmd;
115
+
116
+ if (fuse_exited(fuse_instance))
117
+ return 0;
118
+
119
+ cmd = fuse_read_cmd(fuse_instance);
120
+ if (cmd == NULL)
121
+ return 1;
122
+
123
+ fuse_process_cmd(fuse_instance, cmd);
124
+ }
125
+ return 1;
126
+ }
127
+
128
+
129
+ static int set_one_signal_handler(int signal, void (*handler)(int))
130
+ {
131
+ struct sigaction sa;
132
+ struct sigaction old_sa;
133
+
134
+ memset(&sa, 0, sizeof(struct sigaction));
135
+ sa.sa_handler = handler;
136
+ sigemptyset(&(sa.sa_mask));
137
+ sa.sa_flags = 0;
138
+
139
+ if (sigaction(signal, NULL, &old_sa) == -1) {
140
+ perror("FUSE: cannot get old signal handler");
141
+ return -1;
142
+ }
143
+
144
+ if (old_sa.sa_handler == SIG_DFL &&
145
+ sigaction(signal, &sa, NULL) == -1) {
146
+ perror("Cannot set signal handler");
147
+ return -1;
148
+ }
149
+ return 0;
150
+ }
data/ext/fusefs_fuse.h ADDED
@@ -0,0 +1,19 @@
1
+ /* fusefs_fuse.h */
2
+
3
+ /* This is rewriting most of the things that occur
4
+ * in fuse_main up through fuse_loop */
5
+
6
+ #ifndef __FUSEFS_FUSE_H_
7
+ #define __FUSEFS_FUSE_H_
8
+
9
+ struct fuse_args;
10
+
11
+ int fusefs_fd();
12
+ int fusefs_unmount();
13
+ int fusefs_ehandler();
14
+ int fusefs_setup(char *mountpoint, const struct fuse_operations *op, struct fuse_args *opts);
15
+ int fusefs_process();
16
+ int fusefs_uid();
17
+ int fusefs_gid();
18
+
19
+ #endif