rfusefs 0.8.0 → 1.0.0.RC0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rfusefs.rb CHANGED
@@ -1,318 +1,126 @@
1
1
  # RFuseFS.rb
2
- #gem 'rfuse-ng' , "=0.4.0"
2
+ require 'fuse/fusedir'
3
3
  require 'fuse/rfusefs-fuse'
4
+ require 'rfusefs/version'
4
5
 
5
- # This is FuseFS compatible module built over RFuse-NG
6
+ # This is FuseFS compatible module built over RFuse
6
7
 
7
8
  module FuseFS
8
- VERSION = "0.8.0"
9
- @mounts = { }
10
-
11
- # Start the FuseFS root at mountpoint with opts. *RFuseFS* extension
12
- # @param mountpoint [String] {mount_under}
13
- # @param root [Object] see {set_root}
14
- # @param opts [Array<String>] FUSE options see {mount_under}
15
- def FuseFS.start(mountpoint,root,*opts)
16
- print "Starting FuseFS #{root} at #{mountpoint} with #{opts}\n"
17
- Signal.trap("TERM") { FuseFS.exit() }
18
- Signal.trap("INT") { FuseFS.exit() }
19
- FuseFS.set_root(root)
20
- FuseFS.mount_under(mountpoint,*opts)
21
- FuseFS.run()
22
- FuseFS.unmount()
23
- end
24
-
25
- # Forks {start} so you can access your filesystem with ruby File
26
- # operations (eg for testing). *RFuseFS* extension
27
- def FuseFS.mount(mountpoint,root = nil,*opts)
28
-
29
- pid = Kernel.fork do
30
- FuseFS.start(mountpoint, root,*opts)
31
- end
32
- @mounts[mountpoint] = pid
33
- pid
34
- end
35
-
36
- # Unmount a filesystem
37
- # @param mountpoint [String] If nil?, unmounts the filesystem started with {start}
38
- # otherwise signals the forked process started with {mount}
39
- # to exit and unmount. *RFuseFS* extension
40
- def FuseFS.unmount(mountpoint=nil)
41
-
42
- if (mountpoint)
43
- if @mounts.has_key?(mountpoint)
44
- pid = @mounts[mountpoint]
45
- print "Sending TERM to forked FuseFS (#{pid})\n"
46
- Process.kill("TERM",pid)
47
- Process.waitpid(pid)
48
- else
49
- raise "Unknown mountpoint #{mountpoint}"
50
- end
51
- else
52
- #Local unmount, make sure we only try to unmount once
53
- if @fuse
54
- print "Unmounting #{@fuse.mountname}\n"
55
- @fuse.unmount()
56
- end
57
- @fuse = nil
58
- end
59
- end
60
-
61
- # Set the root virtual directory
62
- # @param root [Object] an object implementing a subset of {FuseFS::API}
63
- def FuseFS.set_root(root)
64
- @root=root
65
- end
66
-
67
- # This will cause FuseFS to virtually mount itself under the given path. {set_root} must have
68
- # been called previously.
69
- # @param path [String] an existing directory where the filesystem will be virtually mounted
70
- # @param opts [Array<String>] are FUSE options. Most likely, you will only want 'allow_other'
71
- # or 'allow_root'. The two are mutually exclusive in FUSE, but allow_other
72
- # will let other users, including root, access your filesystem. allow_root
73
- # will only allow root to access it.
74
- #
75
- # Also available for FuseFS users are:
76
- # default_permissions, max_read=N, fsname=NAME.
77
- #
78
- # For more information, see http://fuse.sourceforge.net
79
- def FuseFS.mount_under(path,*opts)
80
- @fuse = RFuseFS.new(path,opts,[],@root)
81
- end
82
-
83
- # This is the main loop waiting on then executing filesystem operations from the
84
- # kernel.
85
- #
86
- # @note Running in a separate thread is generally not useful. In particular
87
- # you cannot access your filesystem using ruby File operations.
88
- def FuseFS.run
89
- unless @fuse
90
- raise "fuse is not mounted"
91
- end
92
-
93
- begin
94
- io = IO.for_fd(@fuse.fd)
95
- rescue Errno::EBADF
96
- raise "fuse not mounted"
97
- end
98
-
99
- @running = true
100
- while @running
101
- begin
102
- #We wake up every 2 seconds to check we are still running.
103
- IO.select([io],[],[],2)
104
- if @fuse.process() < 0
105
- @running = false
106
- end
107
- rescue Errno::EBADF
108
- @running = false
109
- rescue Interrupt
110
- #do nothing
111
- end
112
- end
113
- end
114
-
115
- # Exit the run loop and teardown FUSE
116
- # Most useful from Signal.trap() or Kernel.at_exit()
117
- def FuseFS.exit
118
- @running = false
119
-
120
- if @fuse
121
- print "Exitting FUSE #{@fuse.mountname}\n"
122
- @fuse.exit
123
- end
124
- end
125
-
126
- # When the filesystem is accessed, the accessor's uid is returned
127
- # You can use this in determining your permissions, or even provide different files
128
- # for different users.
129
- def self.reader_uid
130
- Thread.current[:fusefs_reader_uid]
131
- end
132
-
133
- # When the filesystem is accessed, the accessor's gid is returned
134
- def self.reader_gid
135
- Thread.current[:fusefs_reader_gid]
136
- end
137
-
138
- # Not supported in RFuseFS (yet). The original FuseFS had special handling for editor
139
- # swap/backup but this does not seem to be required, eg for the demo filesystems.
140
- # If it is required it can be implemented in a filesystem
141
- def self.handle_editor(bool)
142
- #do nothing
143
- end
144
-
145
- # Defines convenience methods for path manipulation. You should typically inherit
146
- # from here in your own directory projects
147
- class FuseDir
148
-
149
- # base,rest = split_path(path)
150
- # @return [Array<String,String>] base,rest. base is the first directory in
151
- # path, and rest is nil> or the remaining path.
152
- # Typically if rest is not nil? you should
153
- # recurse the paths
154
- def split_path(path)
155
- cur, *rest = path.scan(/[^\/]+/)
156
- if rest.empty?
157
- [ cur, nil ]
158
- else
159
- [ cur, File::SEPARATOR + File.join(rest) ]
160
- end
161
- end
162
-
163
- # base,*rest = scan_path(path)
164
- # @return [Array<String>] all directory and file elements in path. Useful
165
- # when encapsulating an entire fs into one object
166
- def scan_path(path)
167
- path.scan(/[^\/]+/)
9
+ @mounts = { }
10
+
11
+ # Start the FuseFS root at mountpoint with opts.
12
+ # @param [Object] root see {set_root}
13
+ # @param mountpoint [String] {mount_under}
14
+ # @param [String...] opts FUSE mount options see {mount_under}
15
+ # @note RFuseFS extension
16
+ # @return [void]
17
+ def FuseFS.start(root,mountpoint,*opts)
18
+ print "Starting FuseFS #{root} at #{mountpoint} with #{opts}\n"
19
+ Signal.trap("TERM") { FuseFS.exit() }
20
+ Signal.trap("INT") { FuseFS.exit() }
21
+ FuseFS.set_root(root)
22
+ FuseFS.mount_under(mountpoint,*opts)
23
+ FuseFS.run
24
+ FuseFS.unmount()
168
25
  end
169
- end
170
-
171
-
172
- # This class is equivalent to using Object.new() as the virtual directory
173
- # for target for FuseFS.start(). It exists only to document the API
174
- #
175
- # == Method call sequences
176
- #
177
- # === Stat (getattr)
178
- #
179
- # FUSE itself will generally stat referenced files and validate the results
180
- # before performing any file/directory operations so this sequence is called
181
- # very often
182
- #
183
- # 1. {#directory?} is checked first
184
- # * {#can_write?} OR {#can_mkdir?} with .\_rfusefs_check\_ to determine write permissions
185
- # * {#times} is called to determine atime,mtime,ctime info for the directory
186
- #
187
- # 2. {#file?} is checked next
188
- # * {#can_write?}, {#executable?}, {#size}, {#times} are called to fill out the details
189
- #
190
- # 3. otherwise we tell FUSE that the path does not exist
191
- #
192
- # === List directory
193
- #
194
- # FUSE confirms the path is a directory (via stat above) before we call {#contents}
195
- #
196
- # FUSE will generally go on to stat each directory entry in the results
197
- #
198
- # === Reading files
199
- #
200
- # FUSE confirms path is a file before we call {#read_file}
201
- #
202
- # For fine control of file access see {#raw_open}, {#raw_read}, {#raw_close}
203
- #
204
- # === Writing files
205
- #
206
- # FUSE confirms path for the new file is a directory
207
- #
208
- # * {#can_write?} is checked at file open
209
- # * {#write_to} is called when the file is flushed or closed
210
- #
211
- # See also {#raw_open}, {#raw_truncate}, {#raw_write}, {#raw_close}
212
- #
213
- # === Deleting files
214
- #
215
- # FUSE confirms path is a file before we call {#can_delete?} then {#delete}
216
- #
217
- # === Creating directories
218
- #
219
- # FUSE confirms parent is a directory before we call {#can_mkdir?} then {#mkdir}
220
- #
221
- # === Deleting directories
222
- #
223
- # FUSE confirms path is a directory before we call {#can_rmdir?} then {#rmdir}
224
- #
225
- # === Renaming files and directories
226
- #
227
- # FUSE confirms the rename is valid (eg. not renaming a directory to a file)
228
- #
229
- # * Try {#rename} to see if the virtual directory wants to handle this itself
230
- # * If rename returns false/nil then we try to copy/delete (files only) ie.
231
- # * {#file?}(from), {#can_write?}(to), {#can_delete?}(from) and if all true
232
- # * {#read_file}(from), {#write_to}(to), {#delete}(from)
233
- # * otherwise reject the rename
234
- class API < FuseDir
235
-
236
- # @return [Boolean] true if path is a directory
237
- def directory?(path);end
238
-
239
- # @return [Boolean] true if path is a file
240
- def file?(path);end
241
-
242
- # @return [Array<String>] array of file and directory names within path
243
- def contents(path);return [];end
244
-
245
- # @return [Boolean] true if path is an executable file
246
- def executable?(path);end
247
-
248
- # File size
249
- # @return [Fixnum] the size in byte of a file (lots of applications rely on this being accurate )
250
- def size(path);return 0;end
251
-
252
- # File time information. RFuseFS extension.
253
- # @return [Array<Fixnum>] a 3 element array [ atime, mtime. ctime ] (good for rsync etc)
254
- def times(path);return INIT_TIMES;end
255
-
256
- # @return [String] the contents of the file at path
257
- def read_file(path);end
258
-
259
- # @return [Boolean] true if the user can write to file at path
260
- def can_write?(path);end
261
-
262
- # Write the contents of str to file at path
263
- def write_to(path,str);end
264
26
 
265
- # @return [Boolean] true if the user can delete the file at path
266
- def can_delete?(path);end
267
-
268
- # Delete the file at path
269
- def delete(path);end
270
-
271
- # @return [Boolean] true if user can make a directory at path
272
- def can_mkdir?(path);end
273
-
274
- # Make a directory at path
275
- def mkdir(path);end
276
-
277
- # @return [Boolean] true if user can remove a directory at path
278
- def can_rmdir?(path);end
27
+ # Forks {FuseFS.start} so you can access your filesystem with ruby File
28
+ # operations (eg for testing).
29
+ # @note This is an *RFuseFS* extension
30
+ # @return [void]
31
+ def FuseFS.mount(root,mountpoint,*opts)
32
+
33
+ pid = Kernel.fork do
34
+ FuseFS.start(root,mountpoint,*opts)
35
+ end
36
+ @mounts[mountpoint] = pid
37
+ pid
38
+ end
279
39
 
280
- # Remove the directory at path
281
- def rmdir(path);end
40
+ # Unmount a filesystem
41
+ # @param mountpoint [String] If nil?, unmounts the filesystem started with {start}
42
+ # otherwise signals the forked process started with {mount}
43
+ # to exit and unmount.
44
+ # @note RFuseFS extension
45
+ # @return [void]
46
+ def FuseFS.unmount(mountpoint=nil)
47
+
48
+ if (mountpoint)
49
+ if @mounts.has_key?(mountpoint)
50
+ pid = @mounts[mountpoint]
51
+ print "Sending TERM to forked FuseFS (#{pid})\n"
52
+ Process.kill("TERM",pid)
53
+ Process.waitpid(pid)
54
+ else
55
+ raise "Unknown mountpoint #{mountpoint}"
56
+ end
57
+ else
58
+ #Local unmount, make sure we only try to unmount once
59
+ if @fuse && @fuse.mounted?
60
+ print "Unmounting #{@fuse.mountname}\n"
61
+ @fuse.unmount()
62
+ end
63
+ @fuse = nil
64
+ end
65
+ end
282
66
 
283
- # Neat toy. Called when a file is touched or has its timestamp explicitly modified
284
- def touch(path,modtime);end
67
+ # Set the root virtual directory
68
+ # @param root [Object] an object implementing a subset of {FuseFS::API}
69
+ # @return [void]
70
+ def FuseFS.set_root(root)
71
+ @fs=RFuseFS.new(root)
72
+ end
285
73
 
286
- # Move a file or directory.
287
- # @return [Object] non nil/false to indicate the rename has been handled,
288
- # otherwise will fallback to copy/delete
289
- def rename(from_path,to_path);end
74
+ # This will cause FuseFS to virtually mount itself under the given path. {set_root} must have
75
+ # been called previously.
76
+ # @param [String] mountpoint an existing directory where the filesystem will be virtually mounted
77
+ # @param [Array<String>] args
78
+ # These are as expected by the "mount" command. Note in particular that the first argument
79
+ # is expected to be the mount point. For more information, see http://fuse.sourceforge.net
80
+ # and the manual pages for "mount.fuse"
81
+ def FuseFS.mount_under(mountpoint, *args)
82
+ @fuse = RFuse::FuseDelegator.new(@fs,mountpoint,*args)
83
+ end
290
84
 
291
- # Raw file access
292
- # @param mode [String] "r","w" or "rw", with "a" if file is opened for append
293
- # @return [Object] a non nil object if you want lower level control of file operations
294
- # Under RFuseFS this object will be passed back in to the other raw
295
- # methods as the optional parameter _raw_
296
- #
297
- def raw_open(path,mode);end
85
+ # This is the main loop waiting on then executing filesystem operations from the
86
+ # kernel.
87
+ #
88
+ # Note: Running in a separate thread is generally not useful. In particular
89
+ # you cannot access your filesystem using ruby File operations.
90
+ # @note RFuseFS extension
91
+ def FuseFS.run
92
+ @fuse.loop if @fuse.mounted?
93
+ end
298
94
 
299
- # RFuseFS extension.
300
- #
301
- # Truncate file at path (or filehandle raw) to offset bytes. Called immediately after a file is opened
302
- # for write without append.
303
- #
304
- # This method can also be invoked (without raw) outside of an open file context. See
305
- # FUSE documentation on truncate() vs ftruncate()
306
- def raw_truncate(path,off,raw=nil);end
95
+ # Exit the run loop and teardown FUSE
96
+ # Most useful from Signal.trap() or Kernel.at_exit()
97
+ def FuseFS.exit
98
+ @running = false
307
99
 
308
- # Read _sz_ bytes from file at path (or filehandle raw) starting at offset off
309
- def raw_read(path,off,sz,raw=nil);end
100
+ if @fuse
101
+ print "Exitting FUSE #{@fuse.mountname}\n"
102
+ @fuse.exit
103
+ end
104
+ end
310
105
 
311
- # Write _sz_ bytes from file at path (or filehandle raw) starting at offset off
312
- def raw_write(path,off,sz,buf,raw=nil);end
106
+ # @return [Fixnum] the calling process uid
107
+ # You can use this in determining your permissions, or even provide different files
108
+ # for different users.
109
+ def self.reader_uid
110
+ Thread.current[:fusefs_reader_uid]
111
+ end
313
112
 
314
- # Close the file previously opened at path (or filehandle raw)
315
- def raw_close(path,raw=nil);end
113
+ # @return [Fixnum] the calling process gid
114
+ def self.reader_gid
115
+ Thread.current[:fusefs_reader_gid]
116
+ end
316
117
 
317
- end
118
+ # Not supported in RFuseFS (yet). The original FuseFS had special handling for editor
119
+ # swap/backup but this does not seem to be required, eg for the demo filesystems.
120
+ # If it is required it can be implemented in a filesystem
121
+ # @deprecated
122
+ def self.handle_editor(bool)
123
+ #do nothing
124
+ end
318
125
  end
126
+
data/samples/demo.rb CHANGED
@@ -1,22 +1,12 @@
1
1
  require "rubygems"
2
2
  require 'rfusefs'
3
+ require 'fusefs/metadir'
4
+ require 'fusefs/dirlink'
3
5
 
4
6
  include FuseFS
5
7
 
6
8
  root = MetaDir.new
7
9
 
8
- # if (ARGV.size != 1)
9
- # puts "Usage: #{$0} <directory>"
10
- # exit
11
- # end
12
-
13
- dirname = ARGV.shift
14
-
15
- unless File.directory?(dirname)
16
- puts "Usage: #{$0} <directory>"
17
- exit
18
- end
19
-
20
10
  class Counter
21
11
  def initialize
22
12
  @counter = 0
@@ -59,6 +49,11 @@ root.write_to('/counter',Counter.new)
59
49
  root.write_to('/color',Randwords.new('red','blue','green','purple','yellow','bistre','burnt sienna','jade'))
60
50
  root.write_to('/animal',Randwords.new('duck','dog','cat','duck billed platypus','silly fella'))
61
51
 
62
- root.mkdir("/#{ENV['USER']}",DirLink.new(ENV['HOME']))
52
+ root.mkdir("/#{ENV['USER']}",FuseFS::DirLink.new(ENV['HOME']))
53
+
54
+ unless ARGV.length > 0 && File.directory?(ARGV[0])
55
+ puts "Usage: #{$0} <mountpoint> <mountoptions>"
56
+ exit
57
+ end
63
58
 
64
- FuseFS.start(dirname,root,'nolocalcaches', *ARGV)
59
+ FuseFS.start(root, *ARGV)
data/samples/dictfs.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  # dictfs.rb
2
- #
3
2
 
4
3
  require "rubygems"
5
4
  require 'fusefs'
6
5
  include FuseFS
7
6
 
7
+ #TODO: GG Don't know which "dict" this was referring to
8
8
  require 'dict'
9
9
 
10
10
  class DictFS < FuseFS::FuseDir
@@ -61,24 +61,14 @@ that file up on dict.org!
61
61
  end
62
62
 
63
63
  if (File.basename($0) == File.basename(__FILE__))
64
- if (ARGV.size != 1)
65
- puts "Usage: #{$0} <directory>"
66
- exit
67
- end
68
-
69
- dirname = ARGV.shift
70
-
71
- unless File.directory?(dirname)
72
- puts "Usage: #{dirname} is not a directory."
64
+ unless (ARGV.length > 0 && File.directory?(ARGV[0]))
65
+ puts "Usage: #{$0} <mountpoint> <mount_options>"
73
66
  exit
74
67
  end
75
68
 
76
69
  root = DictFS.new
77
70
 
78
71
  # Set the root FuseFS
79
- FuseFS.set_root(root)
80
-
81
- FuseFS.mount_under(dirname)
72
+ FuseFS.start(root,*ARGV)
82
73
 
83
- FuseFS.run # This doesn't return until we're unmounted.
84
74
  end
data/samples/hello.rb CHANGED
@@ -19,6 +19,5 @@ end
19
19
  if __FILE__ == $0
20
20
  require 'rfusefs'
21
21
  hellodir = HelloDir.new
22
- mountpoint = ARGV.shift
23
- FuseFS.start(mountpoint,hellodir)
22
+ FuseFS.start(hellodir,*ARGV)
24
23
  end