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/.gitignore +9 -0
- data/Gemfile +4 -0
- data/History.rdoc +20 -0
- data/README.rdoc +20 -15
- data/Rakefile +10 -17
- data/TODO.txt +1 -2
- data/lib/fuse/fusedir.rb +202 -0
- data/lib/fuse/rfusefs-fuse.rb +402 -482
- data/lib/fusefs/dirlink.rb +1 -1
- data/lib/fusefs/metadir.rb +240 -240
- data/lib/fusefs/pathmapper.rb +189 -188
- data/lib/rfusefs/version.rb +3 -0
- data/lib/rfusefs.rb +109 -301
- data/samples/demo.rb +9 -14
- data/samples/dictfs.rb +4 -14
- data/samples/hello.rb +1 -2
- data/spec/metadir_spec.rb +295 -0
- data/spec/pathmapper_spec.rb +112 -0
- data/spec/rfusefs_spec.rb +77 -76
- data/spec/sample_spec.rb +3 -2
- data/spec/spec_helper.rb +7 -1
- metadata +112 -124
- data/.gemtest +0 -0
- data/History.txt +0 -9
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -1
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
describe FuseFS::MetaDir do
|
5
|
+
|
6
|
+
context "in ruby" do
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@metadir = FuseFS::MetaDir.new()
|
10
|
+
@metadir.mkdir("/test")
|
11
|
+
@metadir.mkdir("/test/hello")
|
12
|
+
@metadir.mkdir("/test/hello/emptydir")
|
13
|
+
@metadir.write_to("/test/hello/hello.txt","Hello World!\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
context "general directory methods" do
|
17
|
+
it "should list directory contents" do
|
18
|
+
@metadir.contents("/").should =~ [ "test" ]
|
19
|
+
@metadir.contents("/test").should =~ [ "hello" ]
|
20
|
+
@metadir.contents("/test/hello").should =~ ["hello.txt", "emptydir" ]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should indicate paths which are/are not directories" do
|
24
|
+
@metadir.directory?("/test").should be_true
|
25
|
+
@metadir.directory?("/test/hello").should be_true
|
26
|
+
@metadir.directory?("/test/hello/hello.txt").should be_false
|
27
|
+
@metadir.directory?("/nodir").should be_false
|
28
|
+
@metadir.directory?("/test/nodir").should be_false
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should indicate paths which are/are not files" do
|
32
|
+
@metadir.file?("/test").should be_false
|
33
|
+
@metadir.file?("/test/nodir").should be_false
|
34
|
+
@metadir.file?("/test/hello").should be_false
|
35
|
+
@metadir.file?("/test/hello/hello.txt").should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should indicate the size of a file" do
|
39
|
+
@metadir.size("/test/hello/hello.txt").should be "Hello World!\n".length
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with write access" do
|
44
|
+
|
45
|
+
around(:each) do |example|
|
46
|
+
FuseFS::RFuseFS.context(fuse_context(),&example)
|
47
|
+
end
|
48
|
+
|
49
|
+
before(:each) do
|
50
|
+
FuseFS::reader_uid.should == Process.uid
|
51
|
+
FuseFS::reader_gid.should == Process.gid
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
it "should allow directory creation" do
|
56
|
+
@metadir.can_mkdir?("/test/otherdir").should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should allow file creation and update" do
|
60
|
+
@metadir.can_write?("/test/hello/newfile").should be_true
|
61
|
+
@metadir.can_write?("/test/hello/hello.txt").should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should read files" do
|
65
|
+
@metadir.read_file("/test/hello/hello.txt").should == "Hello World!\n"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should update existing files" do
|
69
|
+
@metadir.write_to("/test/hello/hello.txt","new contents")
|
70
|
+
@metadir.read_file("/test/hello/hello.txt").should == "new contents"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should not allow deletion of non empty directories" do
|
74
|
+
@metadir.can_rmdir?("/test/hello").should be_false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should delete directories" do
|
78
|
+
@metadir.rmdir("/test/hello/emptydir")
|
79
|
+
@metadir.contents("/test/hello").should =~ ["hello.txt"]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should allow and delete files" do
|
83
|
+
@metadir.can_delete?("/test/hello/hello.txt").should be_true
|
84
|
+
@metadir.delete("/test/hello/hello.txt")
|
85
|
+
@metadir.contents("/test/hello").should =~ ["emptydir"]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should move directories at same level" do
|
89
|
+
before = @metadir.contents("/test/hello")
|
90
|
+
@metadir.rename("/test/hello","/test/moved").should be_true
|
91
|
+
@metadir.directory?("/test/moved").should be_true
|
92
|
+
@metadir.contents("/test/moved").should =~ before
|
93
|
+
@metadir.read_file("/test/moved/hello.txt").should == "Hello World!\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should move directories between different paths" do
|
97
|
+
@metadir.mkdir("/test/other")
|
98
|
+
@metadir.mkdir("/test/other/more")
|
99
|
+
before = @metadir.contents("/test/hello")
|
100
|
+
@metadir.rename("/test/hello","/test/other/more/hello").should be_true
|
101
|
+
@metadir.contents("/test/other/more/hello").should =~ before
|
102
|
+
@metadir.read_file("/test/other/more/hello/hello.txt").should == "Hello World!\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
context "with readonly access" do
|
108
|
+
around(:each) do |example|
|
109
|
+
#Simulate a different userid..
|
110
|
+
FuseFS::RFuseFS.context(fuse_context(-1,-1),&example)
|
111
|
+
end
|
112
|
+
|
113
|
+
before(:each) do
|
114
|
+
FuseFS::reader_uid.should_not == Process.uid
|
115
|
+
FuseFS::reader_gid.should_not == Process.gid
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not allow directory creation" do
|
119
|
+
@metadir.can_mkdir?("/test/anydir").should be_false
|
120
|
+
@metadir.can_mkdir?("/test/hello/otherdir").should be_false
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should not allow file creation or write access" do
|
124
|
+
@metadir.can_write?("/test/hello/hello.txt").should be_false
|
125
|
+
@metadir.can_write?("/test/hello/newfile").should be_false
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should not allow file deletion" do
|
129
|
+
@metadir.can_delete?("/test/hello/hello.txt").should be_false
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should not allow directory deletion" do
|
133
|
+
@metadir.can_rmdir?("/test/emptydir").should be_false
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should not allow directory renames" do
|
137
|
+
@metadir.rename("/test/emptydir","/test/otherdir").should be_false
|
138
|
+
#TODO and make sure it doesn't rename
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should not allow file renames" do
|
142
|
+
@metadir.rename("test/hello/hello.txt","test/hello.txt2").should be_false
|
143
|
+
#TODO and make sure it doesn't rename
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "with subdirectory containing another FuseFS" do
|
148
|
+
around(:each) do |example|
|
149
|
+
FuseFS::RFuseFS.context(fuse_context(),&example)
|
150
|
+
end
|
151
|
+
|
152
|
+
before(:each) do
|
153
|
+
@fusefs = mock("mock_fusefs")
|
154
|
+
@metadir.mkdir("/test")
|
155
|
+
@metadir.mkdir("/test/fusefs",@fusefs)
|
156
|
+
end
|
157
|
+
|
158
|
+
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]
|
159
|
+
api_methods.each do |method|
|
160
|
+
it "should pass on #{method}" do
|
161
|
+
arity = FuseFS::FuseDir.instance_method(method).arity().abs - 1
|
162
|
+
args = Array.new(arity) { |i| i }
|
163
|
+
@fusefs.should_receive(method).with("/path/to/file",*args).and_return("anything")
|
164
|
+
@metadir.send(method,"/test/fusefs/path/to/file",*args)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should pass on :write_to" do
|
169
|
+
@fusefs.should_receive(:write_to).with("/path/to/file","new contents\n")
|
170
|
+
@metadir.write_to("/test/fusefs/path/to/file","new contents\n")
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should pass on :mkdir" do
|
174
|
+
@fusefs.should_receive(:mkdir).with("/path/to/file",nil).once().and_raise(ArgumentError)
|
175
|
+
@fusefs.should_receive(:mkdir).with("/path/to/file").once().and_return("true")
|
176
|
+
@metadir.mkdir("/test/fusefs/path/to/file")
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should rename within same directory" do
|
180
|
+
@fusefs.should_receive(:rename).with("/oldfile","/newfile")
|
181
|
+
@metadir.rename("/test/fusefs/oldfile","/test/fusefs/newfile")
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should pass rename down common directories" do
|
185
|
+
@fusefs.should_receive(:rename).with("/path/to/file" ,"/new/path/to/file")
|
186
|
+
@metadir.rename("/test/fusefs/path/to/file","/test/fusefs/new/path/to/file")
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should rename across directories if from_path is a FuseFS object that accepts extended rename" do
|
190
|
+
@fusefs.should_receive(:rename).with("/path/to/file","/nonfusepath",
|
191
|
+
an_instance_of(FuseFS::MetaDir)) do | myPath, extPath, extFS |
|
192
|
+
extFS.write_to(extPath,"look Mum, no hands!")
|
193
|
+
end
|
194
|
+
|
195
|
+
@metadir.rename("/test/fusefs/path/to/file","/test/nonfusepath").should be_true
|
196
|
+
@metadir.read_file("/test/nonfusepath").should == "look Mum, no hands!"
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should quietly return false if from_path is a FuseFS object that does not accept extended rename" do
|
200
|
+
@fusefs.should_receive(:rename).
|
201
|
+
with("/path/to/file","/nonfusepath",an_instance_of(FuseFS::MetaDir)).
|
202
|
+
and_raise(ArgumentError)
|
203
|
+
@metadir.rename("/test/fusefs/path/to/file","/test/nonfusepath").should be_false
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should not attempt rename file unless :can_write? the destination" do
|
208
|
+
@fusefs.should_receive(:can_write?).with("/newpath/to/file").and_return(false)
|
209
|
+
@metadir.write_to("/test/aFile","some contents")
|
210
|
+
@metadir.rename("/test/aFile","/test/fusefs/newpath/to/file").should be_false
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should not attempt rename directory unless :can_mkdir? the destination" do
|
214
|
+
@fusefs.should_receive(:can_mkdir?).with("/newpath/to/dir").and_return(false)
|
215
|
+
@metadir.mkdir("/test/aDir","some contents")
|
216
|
+
@metadir.rename("/test/aDir","/test/fusefs/newpath/to/dir").should be_false
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
context "in a mounted FUSE filesystem" do
|
223
|
+
before(:all) do
|
224
|
+
tmpdir = Pathname.new(Dir.tmpdir) + "rfusefs"
|
225
|
+
tmpdir.mkdir unless tmpdir.directory?
|
226
|
+
@mountpoint = tmpdir + "metadir_spec"
|
227
|
+
puts "#{@mountpoint}"
|
228
|
+
@mountpoint.mkdir unless @mountpoint.directory?
|
229
|
+
@metadir = FuseFS::MetaDir.new()
|
230
|
+
@metadir.mkdir("/test")
|
231
|
+
@metadir.write_to("/test/hello.txt","Hello World!\n")
|
232
|
+
FuseFS.mount(@metadir,@mountpoint)
|
233
|
+
@testdir = (@mountpoint + "test")
|
234
|
+
@testfile = (@testdir + "hello.txt")
|
235
|
+
#Give FUSE some time to get started
|
236
|
+
sleep(1)
|
237
|
+
end
|
238
|
+
|
239
|
+
after(:all) do
|
240
|
+
FuseFS.unmount(@mountpoint)
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should list directory contents" do
|
244
|
+
@testdir.entries().should =~ pathnames(".","..","hello.txt")
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should read files" do
|
248
|
+
@testfile.file?.should be_true
|
249
|
+
@testfile.read().should == "Hello World!\n"
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should create directories" do
|
253
|
+
newdir = @testdir + "newdir"
|
254
|
+
newdir.mkdir()
|
255
|
+
newdir.directory?.should be_true
|
256
|
+
@testdir.entries().should =~ pathnames(".","..","hello.txt","newdir")
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should create files" do
|
260
|
+
newfile = @testdir + "newfile"
|
261
|
+
newfile.open("w") do |file|
|
262
|
+
file << "A new file\n"
|
263
|
+
end
|
264
|
+
newfile.read.should == "A new file\n"
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should move directories" do
|
268
|
+
fromdir = @testdir + "fromdir"
|
269
|
+
fromdir.mkdir()
|
270
|
+
subfile = fromdir + "afile"
|
271
|
+
subfile.open("w") do |file|
|
272
|
+
file << "testfile\n"
|
273
|
+
end
|
274
|
+
|
275
|
+
movedir = (@mountpoint + "movedir")
|
276
|
+
movedir.directory?.should be_false
|
277
|
+
fromdir.rename(movedir)
|
278
|
+
movedir.directory?.should be_true
|
279
|
+
|
280
|
+
subfile = movedir + "afile"
|
281
|
+
subfile.file?.should be_true
|
282
|
+
subfile.read.should == "testfile\n"
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should move files" do
|
286
|
+
movefile = (@mountpoint + "moved.txt")
|
287
|
+
movefile.file?.should be_false
|
288
|
+
@testfile.should be_true
|
289
|
+
@testfile.rename(movefile)
|
290
|
+
movefile.read.should == "Hello World!\n"
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#Pathmapper is hard to test because it is difficult to mock Dir/Pathname/File etc...
|
2
|
+
require "spec_helper"
|
3
|
+
require "fusefs/pathmapper"
|
4
|
+
|
5
|
+
describe FuseFS::PathMapperFS do
|
6
|
+
before(:all) do
|
7
|
+
@tmpdir = mktmpdir("pathmapper")
|
8
|
+
#create directory
|
9
|
+
pathmap(@tmpdir + "hello.txt","/textfiles/hello")
|
10
|
+
pathmap(@tmpdir + "mysong.mp3","/artist/album/mysong.mp3")
|
11
|
+
pathmap(@tmpdir + "apicture.jpeg","/pictures/201103/apicture.jpg")
|
12
|
+
@pathmapFS = FuseFS::PathMapperFS.create(@tmpdir) do |file|
|
13
|
+
File.file?(file) ? IO.read(file.to_s) : nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "in ruby" do
|
18
|
+
|
19
|
+
context "standard mapping" do
|
20
|
+
|
21
|
+
it "should map files and directories" do
|
22
|
+
@pathmapFS.directory?("/").should be_true
|
23
|
+
@pathmapFS.directory?("/textfiles").should be_true
|
24
|
+
@pathmapFS.directory?("/pictures/201103").should be_true
|
25
|
+
@pathmapFS.file?("/textfiles/hello").should be_true
|
26
|
+
@pathmapFS.file?("/artist/album/mysong.mp3").should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should list the mapped contents of directories" do
|
30
|
+
@pathmapFS.contents("/").should =~ [ "textfiles","artist","pictures" ]
|
31
|
+
@pathmapFS.contents("/artist").should =~ [ "album" ]
|
32
|
+
@pathmapFS.contents("/textfiles").should =~ [ "hello" ]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should report the size of a file" do
|
36
|
+
@pathmapFS.size("/textfiles/hello").should == 16
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should report the atime,mtime and ctime of the mapped file" do
|
40
|
+
atime,mtime,ctime = @pathmapFS.times("/pictures/201103/apicture.jpg")
|
41
|
+
picture = @tmpdir + "apicture.jpeg"
|
42
|
+
atime.should == picture.atime()
|
43
|
+
mtime.should == picture.mtime()
|
44
|
+
ctime.should == picture.ctime()
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "writing to a pathmapped FS"
|
49
|
+
context "using raw access"
|
50
|
+
|
51
|
+
context "a real Fuse mounted filesystem" do
|
52
|
+
before(:all) do
|
53
|
+
@mountpoint = Pathname.new(Dir.tmpdir) + "rfusefs-pathmapper"
|
54
|
+
@mountpoint.mkdir unless @mountpoint.directory?
|
55
|
+
@pathmapFS.use_raw_file_access = true
|
56
|
+
FuseFS.mount(@pathmapFS,@mountpoint)
|
57
|
+
sleep(1)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should map files and directories" do
|
61
|
+
(@mountpoint + "textfiles").directory?.should be_true
|
62
|
+
(@mountpoint + "pictures/201103").directory?.should be_true
|
63
|
+
(@mountpoint + "textfiles/hello").file?.should be_true
|
64
|
+
(@mountpoint + "artist/album/mysong.mp3").file?.should be_true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should list the mapped contents of directories" do
|
68
|
+
(@mountpoint + "textfiles").entries.should =~ pathnames(".","..","hello")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should represent the stat information of the underlying files" do
|
72
|
+
hellopath=(@mountpoint + "textfiles/hello")
|
73
|
+
realpath=(@tmpdir + "hello.txt")
|
74
|
+
mappedstat = hellopath.stat
|
75
|
+
realstat = realpath.stat
|
76
|
+
mappedstat.size.should == realstat.size
|
77
|
+
puts "#{realstat.atime.to_f},#{mappedstat.atime.to_f}"
|
78
|
+
mappedstat.atime.should == realstat.atime
|
79
|
+
mappedstat.mtime.should == realstat.mtime
|
80
|
+
mappedstat.ctime.should == realstat.ctime
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should read the files" do
|
84
|
+
hellopath = (@mountpoint + "textfiles/hello")
|
85
|
+
hellopath.read.should == "/textfiles/hello"
|
86
|
+
hellopath.open do |f|
|
87
|
+
f.seek(2)
|
88
|
+
f.read(3).should == "ext"
|
89
|
+
end
|
90
|
+
hellopath.sysopen do |f|
|
91
|
+
f.sysseek(1)
|
92
|
+
f.sysread(3).should == "tex"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
after(:all) do
|
98
|
+
FuseFS.unmount(@mountpoint)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
after(:all) do
|
108
|
+
FileUtils.rm_rf(@tmpdir.to_s)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
end
|