rfusefs 0.8.0 → 1.0.0.RC0

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