rfusefs 1.0.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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