rfusefs 1.0.2 → 1.1.3

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.
@@ -1,134 +0,0 @@
1
- # sqlfs.rb
2
- #
3
- # The SQL-db proof of concept for FuseFS
4
- #
5
- # Author: Greg Millam
6
-
7
- require "rubygems"
8
- require 'fusefs'
9
-
10
- require 'mysql'
11
-
12
- class SqlFS < FuseFS::FuseDir
13
- class DBTable
14
- attr_accessor :name, :key, :fields
15
- end
16
- def initialize(host,user,pass,db)
17
- @sql = Mysql.connect(host,user,pass,db)
18
- @tables = Hash.new(nil)
19
-
20
- tables = @sql.query('show tables')
21
-
22
- tables.each do |i,|
23
- table = DBTable.new
24
- table.name = i
25
- table.fields = {}
26
- res = @sql.query("describe #{i}")
27
- res.each do |field,type,null,key,default,extra|
28
- table.fields[field] = type
29
- if (key =~ /pri/i)
30
- table.key = field
31
- end
32
- end
33
- @tables[i] = table if table.key
34
- end
35
- end
36
- def directory?(path)
37
- tname, key, field = scan_path(path)
38
- table = @tables[tname]
39
- case
40
- when tname.nil?
41
- true # This means "/"
42
- when table.nil?
43
- false
44
- when field
45
- false # Always a file
46
- when key
47
- res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
48
- res.num_rows > 0 # If there was a result, it exists.
49
- else
50
- true # It's just a table.
51
- end
52
- end
53
- def file?(path)
54
- tname, key, field = scan_path(path)
55
- table = @tables[tname]
56
- case
57
- when field.nil?
58
- false # Only field entries are files.
59
- when table.nil?
60
- false
61
- when ! @tables[tname].fields.include?(field)
62
- false # Invalid field.
63
- when field
64
- res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
65
- res.num_rows > 0
66
- end
67
- end
68
- def can_delete?(path)
69
- # This helps editors, but we don't really use it.
70
- true
71
- end
72
- def can_write?(path)
73
- # Since this is basically only for editing files,
74
- # we just call file?
75
- file?(path)
76
- end
77
- def contents(path)
78
- # since this is only called when directory? is true,
79
- # We'll assume valid entries.
80
- tname, key, field = scan_path(path)
81
- table = @tables[tname]
82
- case
83
- when tname.nil?
84
- @tables.keys.sort # Just the tables.
85
- when key
86
- table.fields.keys.sort
87
- else
88
- # I limit to 200 so 'ls' doesn't hang all the time :D
89
- res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} ORDER BY #{table.key} LIMIT 100")
90
- ret = []
91
- res.each do |val,one|
92
- ret << val if val.size > 0
93
- end
94
- ret
95
- end
96
- end
97
- def write_to(path,body)
98
- # Since this is only called after can_write?(), we assume
99
- # Valid fields.
100
- tname, key, field = scan_path(path)
101
- table = @tables[tname]
102
- res = @sql.query("UPDATE #{table.name} SET #{field} = '#{Mysql.escape_string(body)}' WHERE #{table.key} = '#{key}'")
103
- end
104
- def read_file(path)
105
- # Again, as this is only called after file?, assume valid fields.
106
- tname, key, field = scan_path(path)
107
- table = @tables[tname]
108
- res = @sql.query("SELECT #{field} FROM #{table.name} WHERE #{table.key} = '#{key}'")
109
- res.fetch_row[0]
110
- end
111
- end
112
-
113
- if (File.basename($0) == File.basename(__FILE__))
114
- if ARGV.size != 5
115
- puts "Usage: #{$0} <directory> <host> <user> <pass> <db>"
116
- exit
117
- end
118
-
119
- dirname, host, user, pass, db = ARGV
120
-
121
- if (! File.directory?(dirname))
122
- puts "#{dirname} is not a directory"
123
- end
124
-
125
- root = SqlFS.new(host,user,pass,db)
126
-
127
- # Set the root FuseFS
128
- FuseFS.set_root(root)
129
-
130
- # root.contents("/quotes")
131
-
132
- FuseFS.mount_under(dirname)
133
- FuseFS.run # This doesn't return until we're unmounted.
134
- end
@@ -1,168 +0,0 @@
1
- # yamlfs.rb
2
- #
3
-
4
- require "rubygems"
5
- require 'fusefs'
6
- include FuseFS
7
-
8
- require 'yaml'
9
-
10
- class YAMLFS < FuseFS::FuseDir
11
- def initialize(filename)
12
- @filename = filename
13
- begin
14
- @fs = YAML.load(IO.read(filename))
15
- rescue Exception
16
- @fs = Hash.new()
17
- end
18
- end
19
- def save
20
- File.open(@filename,'w') do |fout|
21
- fout.puts(YAML.dump(@fs))
22
- end
23
- end
24
- def contents(path)
25
- items = scan_path(path)
26
- node = items.inject(@fs) do |node,item|
27
- item ? node[item] : node
28
- end
29
- node.keys.sort
30
- end
31
- def directory?(path)
32
- items = scan_path(path)
33
- node = items.inject(@fs) do |node,item|
34
- item ? node[item] : node
35
- end
36
- node.is_a?(Hash)
37
- end
38
- def file?(path)
39
- items = scan_path(path)
40
- node = items.inject(@fs) do |node,item|
41
- item ? node[item] : node
42
- end
43
- node.is_a?(String)
44
- end
45
- def touch(path)
46
- puts "#{path} has been pushed like a button!"
47
- end
48
-
49
- # File reading
50
- def read_file(path)
51
- items = scan_path(path)
52
- node = items.inject(@fs) do |node,item|
53
- item ? node[item] : node
54
- end
55
- node.to_s
56
- end
57
-
58
- def size(path)
59
- read_file(path).size
60
- end
61
-
62
- # File writing
63
- def can_write?(path)
64
- items = scan_path(path)
65
- name = items.pop # Last is the filename.
66
- node = items.inject(@fs) do |node,item|
67
- item ? node[item] : node
68
- end
69
- node.is_a?(Hash)
70
- rescue Exception => er
71
- puts "Error! #{er}"
72
- end
73
- def write_to(path,body)
74
- items = scan_path(path)
75
- name = items.pop # Last is the filename.
76
- node = items.inject(@fs) do |node,item|
77
- item ? node[item] : node
78
- end
79
- node[name] = body
80
- self.save
81
- rescue Exception => er
82
- puts "Error! #{er}"
83
- end
84
-
85
- # Delete a file
86
- def can_delete?(path)
87
- items = scan_path(path)
88
- node = items.inject(@fs) do |node,item|
89
- item ? node[item] : node
90
- end
91
- node.is_a?(String)
92
- rescue Exception => er
93
- puts "Error! #{er}"
94
- end
95
- def delete(path)
96
- items = scan_path(path)
97
- name = items.pop # Last is the filename.
98
- node = items.inject(@fs) do |node,item|
99
- item ? node[item] : node
100
- end
101
- node.delete(name)
102
- self.save
103
- rescue Exception => er
104
- puts "Error! #{er}"
105
- end
106
-
107
- # mkdirs
108
- def can_mkdir?(path)
109
- items = scan_path(path)
110
- name = items.pop # Last is the filename.
111
- node = items.inject(@fs) do |node,item|
112
- item ? node[item] : node
113
- end
114
- node.is_a?(Hash)
115
- rescue Exception => er
116
- puts "Error! #{er}"
117
- end
118
- def mkdir(path)
119
- items = scan_path(path)
120
- name = items.pop # Last is the filename.
121
- node = items.inject(@fs) do |node,item|
122
- item ? node[item] : node
123
- end
124
- node[name] = Hash.new
125
- self.save
126
- end
127
-
128
- # rmdir
129
- def can_rmdir?(path)
130
- items = scan_path(path)
131
- node = items.inject(@fs) do |node,item|
132
- item ? node[item] : node
133
- end
134
- node.is_a?(Hash) && node.empty?
135
- end
136
- def rmdir(path)
137
- items = scan_path(path)
138
- name = items.pop # Last is the filename.
139
- node = items.inject(@fs) do |node,item|
140
- item ? node[item] : node
141
- end
142
- node.delete(name)
143
- self.save
144
- end
145
- end
146
-
147
- if (File.basename($0) == File.basename(__FILE__))
148
- if (ARGV.size < 2)
149
- puts "Usage: #{$0} <directory> <yamlfile> <options>"
150
- exit
151
- end
152
-
153
- dirname, yamlfile = ARGV.shift, ARGV.shift
154
-
155
- unless File.directory?(dirname)
156
- puts "Usage: #{dirname} is not a directory."
157
- exit
158
- end
159
-
160
- root = YAMLFS.new(yamlfile)
161
-
162
- # Set the root FuseFS
163
- FuseFS.set_root(root)
164
-
165
- FuseFS.mount_under(dirname, *ARGV)
166
-
167
- FuseFS.run # This doesn't return until we're unmounted.
168
- end
@@ -1,12 +0,0 @@
1
- require 'fusefs'
2
-
3
- describe "Using fusefs compatibility mode" do
4
- describe FuseFS do
5
-
6
- it "should indicate FuseFS compatibility" do
7
- FuseFS::RFUSEFS_COMPATIBILITY.should be_false
8
- end
9
-
10
- it "should use FuseFS compatible raw calls"
11
- end
12
- end
@@ -1,364 +0,0 @@
1
- require 'spec_helper'
2
- require 'tmpdir'
3
- require 'sys/filesystem'
4
- require 'ffi-xattr'
5
-
6
- describe FuseFS::MetaDir do
7
-
8
- context "in ruby" do
9
-
10
- before(:each) do
11
- @metadir = FuseFS::MetaDir.new()
12
- @metadir.mkdir("/test")
13
- @metadir.mkdir("/test/hello")
14
- @metadir.mkdir("/test/hello/emptydir")
15
- @metadir.write_to("/test/hello/hello.txt","Hello World!\n")
16
- end
17
-
18
- context "general directory methods" do
19
- it "should list directory contents" do
20
- @metadir.contents("/").should =~ [ "test" ]
21
- @metadir.contents("/test").should =~ [ "hello" ]
22
- @metadir.contents("/test/hello").should =~ ["hello.txt", "emptydir" ]
23
- end
24
-
25
- it "should indicate paths which are/are not directories" do
26
- @metadir.directory?("/test").should be_true
27
- @metadir.directory?("/test/hello").should be_true
28
- @metadir.directory?("/test/hello/hello.txt").should be_false
29
- @metadir.directory?("/nodir").should be_false
30
- @metadir.directory?("/test/nodir").should be_false
31
- end
32
-
33
- it "should indicate paths which are/are not files" do
34
- @metadir.file?("/test").should be_false
35
- @metadir.file?("/test/nodir").should be_false
36
- @metadir.file?("/test/hello").should be_false
37
- @metadir.file?("/test/hello/hello.txt").should be_true
38
- end
39
-
40
- it "should indicate the size of a file" do
41
- @metadir.size("/test/hello/hello.txt").should be "Hello World!\n".length
42
- end
43
-
44
- it "should report filesystem statistics" do
45
- @metadir.statistics("/").should == [ 13, 5, nil, nil ]
46
- end
47
- end
48
-
49
- context "with write access" do
50
-
51
- around(:each) do |example|
52
- FuseFS::RFuseFS.context(fuse_context(),&example)
53
- end
54
-
55
- before(:each) do
56
- FuseFS::reader_uid.should == Process.uid
57
- FuseFS::reader_gid.should == Process.gid
58
- end
59
-
60
-
61
- it "should allow directory creation" do
62
- @metadir.can_mkdir?("/test/otherdir").should be_true
63
- end
64
-
65
- it "should allow file creation and update" do
66
- @metadir.can_write?("/test/hello/newfile").should be_true
67
- @metadir.can_write?("/test/hello/hello.txt").should be_true
68
- end
69
-
70
- it "should read files" do
71
- @metadir.read_file("/test/hello/hello.txt").should == "Hello World!\n"
72
- end
73
-
74
- it "should update existing files" do
75
- @metadir.write_to("/test/hello/hello.txt","new contents")
76
- @metadir.read_file("/test/hello/hello.txt").should == "new contents"
77
- end
78
-
79
- it "should not allow deletion of non empty directories" do
80
- @metadir.can_rmdir?("/test/hello").should be_false
81
- end
82
-
83
- it "should delete directories" do
84
- @metadir.rmdir("/test/hello/emptydir")
85
- @metadir.contents("/test/hello").should =~ ["hello.txt"]
86
- end
87
-
88
- it "should allow and delete files" do
89
- @metadir.can_delete?("/test/hello/hello.txt").should be_true
90
- @metadir.delete("/test/hello/hello.txt")
91
- @metadir.contents("/test/hello").should =~ ["emptydir"]
92
- end
93
-
94
- it "should move directories at same level" do
95
- before = @metadir.contents("/test/hello")
96
- @metadir.rename("/test/hello","/test/moved").should be_true
97
- @metadir.directory?("/test/moved").should be_true
98
- @metadir.contents("/test/moved").should =~ before
99
- @metadir.read_file("/test/moved/hello.txt").should == "Hello World!\n"
100
- end
101
-
102
- it "should move directories between different paths" do
103
- @metadir.mkdir("/test/other")
104
- @metadir.mkdir("/test/other/more")
105
- before = @metadir.contents("/test/hello")
106
- @metadir.rename("/test/hello","/test/other/more/hello").should be_true
107
- @metadir.contents("/test/other/more/hello").should =~ before
108
- @metadir.read_file("/test/other/more/hello/hello.txt").should == "Hello World!\n"
109
- end
110
-
111
- it "should maintain filesystem statistics" do
112
- # remove a directory
113
- @metadir.rmdir("/test/hello/emptydir")
114
-
115
- # replace text for (the only) existing file
116
- @metadir.write_to("/test/hello/hello.txt","new text")
117
-
118
- @metadir.statistics("/").should == [ 8, 4, nil, nil ]
119
- end
120
- end
121
-
122
- context "with readonly access" do
123
- around(:each) do |example|
124
- #Simulate a different userid..
125
- FuseFS::RFuseFS.context(fuse_context(-1,-1),&example)
126
- end
127
-
128
- before(:each) do
129
- FuseFS::reader_uid.should_not == Process.uid
130
- FuseFS::reader_gid.should_not == Process.gid
131
- end
132
-
133
- it "should not allow directory creation" do
134
- @metadir.can_mkdir?("/test/anydir").should be_false
135
- @metadir.can_mkdir?("/test/hello/otherdir").should be_false
136
- end
137
-
138
- it "should not allow file creation or write access" do
139
- @metadir.can_write?("/test/hello/hello.txt").should be_false
140
- @metadir.can_write?("/test/hello/newfile").should be_false
141
- end
142
-
143
- it "should not allow file deletion" do
144
- @metadir.can_delete?("/test/hello/hello.txt").should be_false
145
- end
146
-
147
- it "should not allow directory deletion" do
148
- @metadir.can_rmdir?("/test/emptydir").should be_false
149
- end
150
-
151
- it "should not allow directory renames" do
152
- @metadir.rename("/test/emptydir","/test/otherdir").should be_false
153
- #TODO and make sure it doesn't rename
154
- end
155
-
156
- it "should not allow file renames" do
157
- @metadir.rename("test/hello/hello.txt","test/hello.txt2").should be_false
158
- #TODO and make sure it doesn't rename
159
- end
160
- end
161
-
162
- context "with subdirectory containing another FuseFS" do
163
- around(:each) do |example|
164
- FuseFS::RFuseFS.context(fuse_context(),&example)
165
- end
166
-
167
- before(:each) do
168
- @fusefs = mock("mock_fusefs")
169
- @metadir.mkdir("/test")
170
- @metadir.mkdir("/test/fusefs",@fusefs)
171
- end
172
-
173
- api_methods = [:directory?, :file?, :contents, :executable?, :size, :times, :read_file, :can_write?, :can_delete?, :delete, :can_mkdir?, :can_rmdir?, :rmdir, :touch, :raw_open, :raw_truncate, :raw_read, :raw_write, :raw_close]
174
- api_methods.each do |method|
175
- it "should pass on #{method}" do
176
- arity = FuseFS::FuseDir.instance_method(method).arity().abs - 1
177
- args = Array.new(arity) { |i| i }
178
- @fusefs.should_receive(method).with("/path/to/file",*args).and_return("anything")
179
- @metadir.send(method,"/test/fusefs/path/to/file",*args)
180
- end
181
- end
182
-
183
- it "should pass on :write_to" do
184
- @fusefs.should_receive(:write_to).with("/path/to/file","new contents\n")
185
- @metadir.write_to("/test/fusefs/path/to/file","new contents\n")
186
- end
187
-
188
- it "should pass on :mkdir" do
189
- @fusefs.should_receive(:mkdir).with("/path/to/file",nil).once().and_raise(ArgumentError)
190
- @fusefs.should_receive(:mkdir).with("/path/to/file").once().and_return("true")
191
- @metadir.mkdir("/test/fusefs/path/to/file")
192
- end
193
-
194
- it "should rename within same directory" do
195
- @fusefs.should_receive(:rename).with("/oldfile","/newfile")
196
- @metadir.rename("/test/fusefs/oldfile","/test/fusefs/newfile")
197
- end
198
-
199
- it "should pass rename down common directories" do
200
- @fusefs.should_receive(:rename).with("/path/to/file" ,"/new/path/to/file")
201
- @metadir.rename("/test/fusefs/path/to/file","/test/fusefs/new/path/to/file")
202
- end
203
-
204
- it "should rename across directories if from_path is a FuseFS object that accepts extended rename" do
205
- @fusefs.should_receive(:rename).with("/path/to/file","/nonfusepath",
206
- an_instance_of(FuseFS::MetaDir)) do | myPath, extPath, extFS |
207
- extFS.write_to(extPath,"look Mum, no hands!")
208
- end
209
-
210
- @metadir.rename("/test/fusefs/path/to/file","/test/nonfusepath").should be_true
211
- @metadir.read_file("/test/nonfusepath").should == "look Mum, no hands!"
212
- end
213
-
214
- it "should quietly return false if from_path is a FuseFS object that does not accept extended rename" do
215
- @fusefs.should_receive(:rename).
216
- with("/path/to/file","/nonfusepath",an_instance_of(FuseFS::MetaDir)).
217
- and_raise(ArgumentError)
218
- @metadir.rename("/test/fusefs/path/to/file","/test/nonfusepath").should be_false
219
-
220
- end
221
-
222
- it "should not attempt rename file unless :can_write? the destination" do
223
- @fusefs.should_receive(:can_write?).with("/newpath/to/file").and_return(false)
224
- @metadir.write_to("/test/aFile","some contents")
225
- @metadir.rename("/test/aFile","/test/fusefs/newpath/to/file").should be_false
226
- end
227
-
228
- it "should not attempt rename directory unless :can_mkdir? the destination" do
229
- @fusefs.should_receive(:can_mkdir?).with("/newpath/to/dir").and_return(false)
230
- @metadir.mkdir("/test/aDir","some contents")
231
- @metadir.rename("/test/aDir","/test/fusefs/newpath/to/dir").should be_false
232
- end
233
-
234
- it "should pass on #statistics" do
235
- @fusefs.should_receive(:statistics).with("/path/to/file")
236
-
237
- @metadir.statistics("test/fusefs/path/to/file")
238
- end
239
-
240
- it "should pass on #statistics for root" do
241
- @fusefs.should_receive(:statistics).with("/")
242
-
243
- @metadir.statistics("test/fusefs")
244
- end
245
- end
246
-
247
- end
248
- context "in a mounted FUSE filesystem" do
249
-
250
- let(:mountpoint) { Pathname.new(Dir.mktmpdir(["rfusefs","metadir"])) }
251
- let(:metadir) { FuseFS::MetaDir.new() }
252
- let(:testdir) { mountpoint + "test" }
253
- let(:testfile) { testdir + "hello.txt" }
254
-
255
- before(:all) do
256
- metadir.mkdir("/test")
257
- metadir.write_to("/test/hello.txt","Hello World!\n")
258
- metadir.xattr("/test/hello.txt")["user.test"] = "an extended attribute"
259
- metadir.xattr("/test")["user.test"] = "a dir attribute"
260
- FuseFS.mount(metadir,mountpoint)
261
- #Give FUSE some time to get started
262
- sleep(0.5)
263
- end
264
-
265
- after(:all) do
266
- FuseFS.unmount(mountpoint)
267
- sleep(0.5)
268
- FileUtils.rm_r(mountpoint)
269
- end
270
-
271
- it "should list directory contents" do
272
- testdir.entries().should =~ pathnames(".","..","hello.txt")
273
- end
274
-
275
- it "should read files" do
276
- testfile.file?.should be_true
277
- testfile.read().should == "Hello World!\n"
278
- end
279
-
280
- it "should read and write extended attributes from files" do
281
- x = Xattr.new(testfile.to_s)
282
- x["user.test"].should == "an extended attribute"
283
-
284
- x["user.new"] = "new"
285
-
286
- Xattr.new(testfile.to_s)["user.new"].should == "new"
287
- end
288
-
289
- it "should write extended attributes for directories" do
290
- x = Xattr.new(testdir.to_s)
291
-
292
- x["user.test"].should == "a dir attribute"
293
- x["user.new"] = "new dir"
294
-
295
- Xattr.new(testdir.to_s)["user.new"].should == "new dir"
296
- end
297
-
298
-
299
- it "should create directories" do
300
- newdir = testdir + "newdir"
301
- newdir.mkdir()
302
- newdir.directory?.should be_true
303
- testdir.entries().should =~ pathnames(".","..","hello.txt","newdir")
304
- end
305
-
306
- it "should create files" do
307
- newfile = testdir + "newfile"
308
- newfile.open("w") do |file|
309
- file << "A new file\n"
310
- end
311
- newfile.read.should == "A new file\n"
312
- end
313
-
314
- it "should move directories" do
315
- fromdir = testdir + "fromdir"
316
- fromdir.mkdir()
317
- subfile = fromdir + "afile"
318
- subfile.open("w") do |file|
319
- file << "testfile\n"
320
- end
321
-
322
- movedir = (mountpoint + "movedir")
323
- movedir.directory?.should be_false
324
- fromdir.rename(movedir)
325
- movedir.directory?.should be_true
326
-
327
- subfile = movedir + "afile"
328
- subfile.file?.should be_true
329
- subfile.read.should == "testfile\n"
330
- end
331
-
332
- it "should move files" do
333
- movefile = (mountpoint + "moved.txt")
334
- movefile.file?.should be_false
335
- testfile.should be_true
336
- testfile.rename(movefile)
337
- movefile.read.should == "Hello World!\n"
338
- end
339
-
340
-
341
- it "should report filesystem statistics" do
342
- bigfile = testdir + "bigfile"
343
- bigfile.open("w") do |file|
344
- file << ("x" * 2048)
345
- end
346
-
347
- statfs = Sys::Filesystem.stat(mountpoint.to_s)
348
-
349
- # These are fixed
350
- statfs.block_size.should == 1024
351
- statfs.fragment_size.should == 1024
352
-
353
- # These are dependant on the tests above creating files/directories
354
- statfs.files.should == 8
355
- statfs.files_available == 8
356
-
357
- # assume test are less than 1 block, so dependant on bigfile above
358
- statfs.blocks.should == 2
359
- statfs.blocks_available.should == 0
360
- statfs.blocks_free.should == 0
361
- end
362
- end
363
-
364
- end