rfusefs 1.0.3 → 1.1.0.rc202009.34

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,21 +0,0 @@
1
- require 'spec_helper'
2
- require 'rfusefs'
3
- require 'tmpdir'
4
- require 'pathname'
5
-
6
- describe "a mounted FuseFS" do
7
- let(:mountpoint) { Pathname.new(Dir.mktmpdir("rfusefs_mount_unmount")) }
8
-
9
- after(:each) { FileUtils.rmdir mountpoint }
10
-
11
- it "should get mounted and unmounted callbacks" do
12
- mock_fs = FuseFS::FuseDir.new()
13
- expect(mock_fs).to receive(:mounted)
14
- expect(mock_fs).to receive(:unmounted)
15
-
16
- t = Thread.new { sleep 0.5 ; puts "exiting" ; FuseFS.exit }
17
- FuseFS.start(mock_fs,mountpoint)
18
- t.join
19
- end
20
- end
21
-
@@ -1,417 +0,0 @@
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
- require 'tmpdir'
5
- require 'pathname'
6
- require 'sys/filesystem'
7
- require 'ffi-xattr/extensions'
8
-
9
- class PMFixture
10
- attr_reader :tmpdir
11
-
12
- def initialize()
13
- #Note - these names define the filesystem stats so if you change them those tests will break
14
- end
15
-
16
- def tmpdir
17
- @tmpdir ||= Pathname.new(Dir.mktmpdir("rfusefs_pathmapper"))
18
- end
19
-
20
- def real_path(file)
21
- tmpdir + file
22
- end
23
-
24
- def pathmap(file,mapped_path, content = mapped_path, options = {})
25
- real_file = tmpdir + file
26
- real_file.open("w") do |f|
27
- f << content
28
- end
29
- fs.map_file(real_file,mapped_path,options)
30
- end
31
-
32
- def fs
33
- @fs ||= FuseFS::PathMapperFS.new()
34
- end
35
-
36
- def mount()
37
- return @mountpoint if @mountpoint
38
- @mountpoint = Pathname.new(Dir.mktmpdir("rfusefs_pathmapper_mnt"))
39
- FuseFS.mount(fs,@mountpoint)
40
- sleep(0.5)
41
- @mountpoint
42
- end
43
-
44
- def cleanup
45
- if @mountpoint
46
- FuseFS.unmount(@mountpoint)
47
- sleep(0.5)
48
- FileUtils.rmdir(@mountpoint)
49
- end
50
- FileUtils.rm_r(@tmpdir)
51
- end
52
- end
53
-
54
-
55
- describe FuseFS::PathMapperFS do
56
-
57
- let(:fixture) { PMFixture.new() }
58
- let(:pathmap_fs) { fixture.fs }
59
- let(:tmpdir) { fixture.tmpdir }
60
- let(:mountpoint) { fixture.mount }
61
-
62
- before(:each) do
63
- fixture.pathmap("hello.txt","/textfiles/hello")
64
- fixture.pathmap("mysong.mp3","/artist/album/mysong.mp3")
65
- fixture.pathmap("apicture.jpeg","/pictures/201103/apicture.jpg")
66
- end
67
-
68
- after(:each) do
69
- fixture.cleanup
70
- end
71
-
72
- context "fusefs api" do
73
-
74
- it "maps files and directories" do
75
- expect(pathmap_fs.directory?("/")).to be_truthy
76
- expect(pathmap_fs.directory?("/textfiles")).to be_truthy
77
- expect(pathmap_fs.directory?("/pictures/201103")).to be_truthy
78
- expect(pathmap_fs.file?("/textfiles/hello")).to be_truthy
79
- expect(pathmap_fs.directory?("/textfiles/hello")).to be_falsey
80
- expect(pathmap_fs.file?("/artist/album/mysong.mp3")).to be_truthy
81
- expect(pathmap_fs.directory?("/artist/album/mysong.mp3")).to be_falsey
82
- expect(pathmap_fs.file?("/some/unknown/path")).to be_falsey
83
- expect(pathmap_fs.directory?("/some/unknown/path")).to be_falsey
84
- end
85
-
86
- it "lists the mapped contents of directories" do
87
- expect(pathmap_fs.contents("/")).to match_array([ "textfiles","artist","pictures" ])
88
- expect(pathmap_fs.contents("/artist")).to match_array([ "album" ])
89
- expect(pathmap_fs.contents("/textfiles")).to match_array([ "hello" ])
90
- end
91
-
92
- it "reports the size of a file" do
93
- expect(pathmap_fs.size("/textfiles/hello")).to eq(16)
94
- end
95
-
96
- it "reads the contents of a file" do
97
- expect(pathmap_fs.read_file("/textfiles/hello")).to eq("/textfiles/hello")
98
- end
99
-
100
- it "does not allow writes" do
101
- expect(pathmap_fs.can_write?("/textfiles/hello")).to be_falsey
102
- end
103
-
104
- it "reports the atime,mtime and ctime of the mapped file" do
105
- atime,mtime,ctime = pathmap_fs.times("/pictures/201103/apicture.jpg")
106
- picture = tmpdir + "apicture.jpeg"
107
- expect(atime).to eq(picture.atime())
108
- expect(mtime).to eq(picture.mtime())
109
- expect(ctime).to eq(picture.ctime())
110
- end
111
-
112
- context "with extended attributes" do
113
- let (:hello_realpath) {fixture.real_path("hello.txt")}
114
- let (:hello_xattr) { Xattr.new(hello_realpath) }
115
- let (:pm_file_xattr) { pathmap_fs.xattr("/textfiles/hello") }
116
- let (:pm_dir_xattr) { pathmap_fs.xattr("/textfiles") }
117
-
118
- before(:each) do
119
- # attribute set on real file
120
- hello_xattr["user.file_attr"] = "fileValue"
121
-
122
- # additional attribute on file
123
- pathmap_fs.node("/textfiles/hello")[:xattr] =
124
- { "user.add_attr" => "addValue" }
125
-
126
- # additional attribute on directory
127
- pathmap_fs.node("/textfiles")[:xattr] =
128
- { "user.dir_attr" => "dirValue" }
129
-
130
- end
131
-
132
- it "should list extended attributes" do
133
- expect(pm_file_xattr.keys).to include("user.file_attr")
134
- expect(pm_file_xattr.keys).to include("user.add_attr")
135
- expect(pm_file_xattr.keys.size).to eq(2)
136
- end
137
-
138
- it "should read extended attributes from underlying file" do
139
- expect(pm_file_xattr["user.file_attr"]).to eq("fileValue")
140
- end
141
-
142
- it "should read additional attributes" do
143
- # make sure additional attributes are not on the real file
144
- expect(hello_xattr.list).not_to include("user.add_attr")
145
-
146
- expect(pm_file_xattr["user.add_attr"]).to eq("addValue")
147
- end
148
-
149
- it "should write extended attributes to the underlying file" do
150
- pm_file_xattr["user.file_attr"] = "written"
151
- expect(hello_xattr["user.file_attr"]).to eq("written")
152
- end
153
-
154
- it "should remove extended attributes from the underlying file" do
155
- pm_file_xattr.delete("user.file_attr")
156
- expect(hello_xattr.list).not_to include("user.file_attr")
157
- end
158
-
159
- it "raise EACCES when writing to additional attributes" do
160
- expect {pm_file_xattr["user.add_attr"] = "newValue"}.to raise_error(Errno::EACCES)
161
- end
162
-
163
- it "raise EACCES when removing additional attributes" do
164
- expect {pm_file_xattr.delete("user.add_attr")}.to raise_error(Errno::EACCES)
165
- end
166
-
167
- it "should list additional attributes from virtual directories" do
168
- expect(pm_dir_xattr.keys).to include("user.dir_attr")
169
- expect(pm_dir_xattr.keys.size).to eq(1)
170
- end
171
-
172
- it "should read additional attributes from virtual directories" do
173
- expect(pm_dir_xattr["user.dir_attr"]).to eq("dirValue")
174
-
175
- end
176
-
177
- it "should raise EACCES when writing additional attributes on virtual directories" do
178
- expect {pm_dir_xattr["user.dir_attr"] = "newValue"}.to raise_error(Errno::EACCES)
179
- end
180
-
181
- it "should raise EACCES when deleting additional attributes on virtual directories" do
182
- expect {pm_dir_xattr.delete("user.dir_attr")}.to raise_error(Errno::EACCES)
183
- end
184
-
185
- it "should accept xattr as option to #map_file" do
186
- fixture.pathmap("mapped_xattr.txt","/textfiles/mapped_xattr","content",
187
- :xattr => { "user.xattr" => "map_file" })
188
- expect(pathmap_fs.xattr("/textfiles/mapped_xattr")["user.xattr"]).to eq("map_file")
189
- end
190
- end
191
-
192
- context "filesystem statistics" do
193
-
194
- it "reports accumulated stats about mapped files" do
195
- used_space, used_nodes, max_space, max_nodes = pathmap_fs.statistics("/pictures/201103/apicture.jpg")
196
- expect(used_space).to eq(69)
197
- expect(used_nodes).to eq(9)
198
- expect(max_space).to be_nil
199
- expect(max_nodes).to be_nil
200
- end
201
- end
202
-
203
- context "writing to a pathmapped FS" do
204
- before(:each) do
205
- pathmap_fs.allow_write=true
206
- pathmap_fs.write_to("textfiles/hello","updated content")
207
- end
208
-
209
- it "updates the contents of the real file" do
210
- hello_path = tmpdir + "hello.txt"
211
- expect(hello_path.read).to eq("updated content")
212
- end
213
-
214
- it "updates the contents of the mapped file" do
215
- expect(pathmap_fs.read_file("textfiles/hello")).to eq("updated content")
216
- end
217
-
218
- it "changes the reported file size" do
219
- expect(pathmap_fs.size("textfiles/hello")).to eq(15)
220
- end
221
-
222
- it "changes the filesystem statistics" do
223
- used_space, used_nodes, max_space, max_nodes = pathmap_fs.statistics("/pictures/201103/apicture.jpg")
224
- expect(used_space).to eq(68)
225
- end
226
- end
227
-
228
- end
229
-
230
- context "a real Fuse mounted filesystem" do
231
- before(:each) do
232
- pathmap_fs.allow_write=true
233
- end
234
-
235
- it "maps files and directories" do
236
- expect((mountpoint + "textfiles").directory?).to be_truthy
237
- expect((mountpoint + "textfiles/hello").file?).to be_truthy
238
- end
239
-
240
- it "lists the mapped contents of directories" do
241
- expect((mountpoint + "textfiles").entries).to match_array(pathnames(".","..","hello"))
242
- end
243
-
244
- it "represents the stat information of the underlying files" do
245
- hellopath=(mountpoint + "textfiles/hello")
246
- realpath=(tmpdir + "hello.txt")
247
- mappedstat = hellopath.stat
248
- realstat = realpath.stat
249
- expect(mappedstat.size).to eq(realstat.size)
250
- expect(mappedstat.atime).to eq(realstat.atime)
251
- expect(mappedstat.mtime).to eq(realstat.mtime)
252
- expect(mappedstat.ctime).to eq(realstat.ctime)
253
- end
254
-
255
- it "reads the files" do
256
- hellopath= mountpoint + "textfiles/hello"
257
- expect(hellopath.read).to eq("/textfiles/hello")
258
- end
259
-
260
- it "writes the files" do
261
- hellopath= mountpoint + "textfiles/hello"
262
- real_path = tmpdir + "hello.txt"
263
- hellopath.open("w") do |f|
264
- f.print "updated content"
265
- end
266
- expect(hellopath.read).to eq("updated content")
267
- expect(real_path.read).to eq("updated content")
268
- end
269
-
270
- context "extended attributes" do
271
- let (:hello_realpath) {fixture.real_path("hello.txt")}
272
- let (:hello_xattr) { hello_realpath.xattr }
273
- let (:file_xattr) { (mountpoint + "textfiles/hello").xattr }
274
- let (:dir_xattr) { (mountpoint + "textfiles").xattr }
275
-
276
- before(:each) do
277
- # attribute set on real file
278
- hello_xattr["user.file_attr"] = "fileValue"
279
-
280
- # additional attribute on file
281
- pathmap_fs.node("/textfiles/hello")[:xattr] =
282
- { "user.add_attr" => "addValue" }
283
-
284
- # additional attribute on directory
285
- pathmap_fs.node("/textfiles")[:xattr] =
286
- { "user.dir_attr" => "dirValue" }
287
-
288
- end
289
-
290
- it "should list extended attributes" do
291
- expect(file_xattr.list).to include("user.file_attr")
292
- expect(file_xattr.list).to include("user.add_attr")
293
- expect(file_xattr.list.size).to eq(2)
294
- end
295
-
296
- it "should read extended attributes from underlying file" do
297
- expect(file_xattr["user.file_attr"]).to eq("fileValue")
298
- end
299
-
300
- it "should read additional attributes" do
301
- expect(file_xattr["user.add_attr"]).to eq("addValue")
302
- end
303
-
304
- it "should write extended attributes to the underlying file" do
305
- file_xattr["user.file_attr"] = "written"
306
- expect(hello_xattr["user.file_attr"]).to eq("written")
307
- end
308
-
309
- it "should remove extended attributes from the underlying file" do
310
- file_xattr.remove("user.file_attr")
311
- expect(hello_xattr.list).not_to include("user.file_attr")
312
- end
313
-
314
- it "raise EACCES when writing to additional attributes" do
315
- expect {file_xattr["user.add_attr"] = "newValue"}.to raise_error(Errno::EACCES)
316
- end
317
-
318
- it "raise EACCES when removing additional attributes" do
319
- expect {file_xattr.remove("user.add_attr")}.to raise_error(Errno::EACCES)
320
- end
321
-
322
- it "should list additional attributes from virtual directories" do
323
- expect(dir_xattr.list).to include("user.dir_attr")
324
- expect(dir_xattr.list.size).to eq(1)
325
- end
326
-
327
- it "should read additional attributes from virtual directories" do
328
- expect(dir_xattr["user.dir_attr"]).to eq("dirValue")
329
- end
330
-
331
- it "should raise EACCES when writing additional attributes on virtual directories" do
332
- expect {dir_xattr["user.dir_attr"] = "newValue"}.to raise_error(Errno::EACCES)
333
- end
334
-
335
- it "should raise EACCES when deleting additional attributes on virtual directories" do
336
- expect {dir_xattr.remove("user.dir_attr")}.to raise_error(Errno::EACCES)
337
- end
338
-
339
- end
340
-
341
- context "filesystem statistics" do
342
- before(:each) do
343
- fixture.pathmap("bigfile.txt","/textfiles/bigfile","x" * 2048)
344
- end
345
-
346
- it "reports stats for files" do
347
- statfs = Sys::Filesystem.stat(mountpoint.to_path)
348
- # These are fixed
349
- expect(statfs.block_size).to eq(1024)
350
- expect(statfs.fragment_size).to eq(1024)
351
-
352
- # These are dependant on the tests above creating files/directories
353
- expect(statfs.files).to eq(10)
354
- statfs.files_available == 10
355
-
356
- # assume test are less than 1 block, so dependant on bigfile above
357
- expect(statfs.blocks).to eq(2)
358
- expect(statfs.blocks_available).to eq(0)
359
- expect(statfs.blocks_free).to eq(0)
360
- end
361
-
362
- it "reports stats for files after writing" do
363
-
364
- (mountpoint + "textfiles/bigfile").open("w") { |f| f.print("y" * 4096) }
365
- statfs = Sys::Filesystem.stat(mountpoint.to_path)
366
- expect(statfs.files).to eq(10)
367
- expect(statfs.blocks).to eq(4)
368
-
369
- end
370
-
371
- end
372
- end
373
-
374
- context "a real Fuse mount with raw file access" do
375
-
376
- before(:each) do
377
- pathmap_fs.use_raw_file_access = true
378
- pathmap_fs.allow_write = true
379
- end
380
-
381
- it "reads files" do
382
- hello_path = (mountpoint + "textfiles/hello")
383
- hello_path.open do |f|
384
- f.seek(2)
385
- expect(f.read(3)).to eq("ext")
386
- end
387
-
388
- hello_path.sysopen do |f|
389
- f.sysseek(1)
390
- expect(f.sysread(3)).to eq("tex")
391
- end
392
- end
393
-
394
- it "writes files" do
395
- hello_path = (mountpoint + "textfiles/hello")
396
- real_path = tmpdir + "hello.txt"
397
- hello_path.open("r+") do |f|
398
- f.sysseek(2)
399
- f.syswrite("zzz")
400
- f.sysseek(0)
401
- expect(f.sysread(6)).to eq("/tzzzf")
402
- end
403
-
404
- expect(real_path.read).to eq("/tzzzfiles/hello")
405
- end
406
-
407
- it "reports filesystem statistics after raw write" do
408
- hello_path = (mountpoint + "textfiles/hello")
409
- hello_path.open("w") do |f|
410
- f.syswrite("z" * 2048)
411
- end
412
-
413
- statfs = Sys::Filesystem.stat(mountpoint.to_path)
414
- expect(statfs.blocks).to eq(2)
415
- end
416
- end
417
- end
@@ -1,505 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FuseFS do
4
-
5
- TEST_FILE = "/aPath/aFile"
6
- TEST_DIR = "/aPath"
7
- ROOT_PATH = "/"
8
- Struct.new("FuseFileInfo",:flags,:fh)
9
-
10
- describe "an empty Root object" do
11
- before(:each) do
12
- @fuse = FuseFS::Fuse::Root.new(Object.new())
13
- end
14
-
15
- it "should return an appropriate Stat for the root directory" do
16
- stat = @fuse.getattr(nil,ROOT_PATH)
17
- expect(stat).to respond_to(:dev)
18
- expect(stat.mode & RFuse::Stat::S_IFDIR).not_to eq(0)
19
- expect(stat.mode & RFuse::Stat::S_IFREG).to eq(0)
20
- expect(permissions(stat.mode)).to eq(0555)
21
- end
22
-
23
- it "should have an empty root directory" do
24
- filler = double("entries_filler")
25
- expect(filler).to receive(:push).with(".",nil,0)
26
- expect(filler).to receive(:push).with("..",nil,0)
27
- @fuse.readdir(nil,"/",filler,nil,nil)
28
- end
29
-
30
- it "should raise ENOENT for other paths" do
31
- expect { @fuse.getattr(nil,"/somepath") }.to raise_error(Errno::ENOENT)
32
- end
33
-
34
- it "should not allow new files or directories" do
35
- expect { @fuse.mknod(nil,"/afile",0100644,0,0) }.to raise_error(Errno::EACCES)
36
- expect { @fuse.mkdir(nil,"/adir",0040555) }.to raise_error(Errno::EACCES)
37
- end
38
- end
39
-
40
- describe "a FuseFS filesystem" do
41
- before(:each) do
42
- @mock_fuse = FuseFS::FuseDir.new()
43
- @fuse = FuseFS::Fuse::Root.new(@mock_fuse)
44
- end
45
-
46
- context("handling signals") do
47
- it "should pass on signals" do
48
- expect(@mock_fuse).to receive(:sighup) { }
49
- fuse = FuseFS::Fuse::Root.new(@mock_fuse)
50
- fuse.sighup
51
- end
52
- end
53
-
54
- describe :readdir do
55
- before(:each) do
56
- expect(@mock_fuse).to receive(:contents).with("/apath").and_return(["afile"])
57
- end
58
-
59
- it "should add . and .. to the results of :contents when listing a directory" do
60
- filler = double("entries_filler")
61
- expect(filler).to receive(:push).with(".",nil,0)
62
- expect(filler).to receive(:push).with("..",nil,0)
63
- expect(filler).to receive(:push).with("afile",nil,0)
64
- @fuse.readdir(nil,"/apath",filler,nil,nil)
65
- end
66
-
67
- end
68
-
69
- describe :getattr do
70
-
71
- #Root directory is special (ish) so we need to run these specs twice.
72
- [ROOT_PATH,TEST_DIR].each do |dir|
73
-
74
- context "of a directory #{ dir }" do
75
-
76
- before(:each) do
77
- allow(@mock_fuse).to receive(:file?).and_return(false)
78
- expect(@mock_fuse).to receive(:directory?).with(dir).at_most(:once).and_return(true)
79
- @checkfile = (dir == "/" ? "" : dir ) + FuseFS::Fuse::Root::CHECK_FILE
80
- end
81
-
82
- it "should return a Stat like object representing a directory" do
83
- expect(@mock_fuse).to receive(:can_write?).with(@checkfile).at_most(:once).and_return(false)
84
- expect(@mock_fuse).to receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(false)
85
- stat = @fuse.getattr(nil,dir)
86
- #Apparently find relies on nlink accurately listing the number of files/directories or nlink being 1
87
- expect(stat.nlink).to eq(1)
88
- expect(filetype(stat.mode)).to eq(RFuse::Stat::S_IFDIR)
89
- expect(permissions(stat.mode)).to eq(0555)
90
- end
91
-
92
-
93
- it "should return writable mode if can_mkdir?" do
94
- expect(@mock_fuse).to receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(true)
95
-
96
- stat = @fuse.getattr(nil,dir)
97
- expect(permissions(stat.mode)).to eq(0777)
98
- end
99
-
100
- it "should return writable mode if can_write?" do
101
- expect(@mock_fuse).to receive(:can_write?).with(@checkfile).at_most(:once).and_return(true)
102
-
103
- stat = @fuse.getattr(nil,dir)
104
- expect(permissions(stat.mode)).to eq(0777)
105
-
106
- end
107
-
108
- it "should return times in the result if available" do
109
- expect(@mock_fuse).to receive(:times).with(dir).and_return([10,20,30])
110
- stat = @fuse.getattr(nil,dir)
111
- expect(stat.atime).to eq(10)
112
- expect(stat.mtime).to eq(20)
113
- expect(stat.ctime).to eq(30)
114
- end
115
- end
116
- end
117
-
118
- describe "a file" do
119
-
120
- before(:each) do
121
- @file="/aPath/aFile"
122
- allow(@mock_fuse).to receive(:directory?).and_return(false)
123
- expect(@mock_fuse).to receive(:file?).with(@file).at_most(:once).and_return(true)
124
- end
125
-
126
-
127
- it "should return a Stat like object representing a file" do
128
- stat = @fuse.getattr(nil,@file)
129
- expect(stat.mode & RFuse::Stat::S_IFDIR).to eq(0)
130
- expect(stat.mode & RFuse::Stat::S_IFREG).not_to eq(0)
131
- expect(permissions(stat.mode)).to eq(0444)
132
- end
133
-
134
- it "should indicate executable mode if executable?" do
135
- expect(@mock_fuse).to receive(:executable?).with(@file).and_return(true)
136
- stat = @fuse.getattr(nil,@file)
137
- expect(permissions(stat.mode)).to eq(0555)
138
- end
139
-
140
- it "should indicate writable mode if can_write?" do
141
- expect(@mock_fuse).to receive(:can_write?).with(@file).and_return(true)
142
- stat = @fuse.getattr(nil,@file)
143
- expect(permissions(stat.mode)).to eq(0666)
144
- end
145
-
146
- it "should by 777 mode if can_write? and exectuable?" do
147
- expect(@mock_fuse).to receive(:can_write?).with(@file).and_return(true)
148
- expect(@mock_fuse).to receive(:executable?).with(@file).and_return(true)
149
- stat = @fuse.getattr(nil,@file)
150
- expect(permissions(stat.mode)).to eq(0777)
151
- end
152
-
153
- it "should include size in the result if available" do
154
- expect(@mock_fuse).to receive(:size).with(@file).and_return(234)
155
- stat = @fuse.getattr(nil,@file)
156
- expect(stat.size).to eq(234)
157
- end
158
-
159
- it "should include times in the result if available" do
160
- expect(@mock_fuse).to receive(:times).with(@file).and_return([22,33,44])
161
- stat = @fuse.getattr(nil,@file)
162
- expect(stat.atime).to eq(22)
163
- expect(stat.mtime).to eq(33)
164
- expect(stat.ctime).to eq(44)
165
- end
166
- end
167
-
168
- it "should raise ENOENT for a path that does not exist" do
169
- expect(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
170
- expect(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
171
- expect{stat = @fuse.getattr(nil,TEST_FILE) }.to raise_error(Errno::ENOENT)
172
- end
173
- end
174
-
175
- context "creating files and directories" do
176
-
177
- it ":mknod should raise EACCES unless :can_write?" do
178
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
179
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
180
- expect(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(false)
181
- expect{@fuse.mknod(nil,TEST_FILE,0100644,0,0)}.to raise_error(Errno::EACCES)
182
- end
183
-
184
- it ":mkdir should raise EACCES unless :can_mkdir?" do
185
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
186
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
187
- expect(@mock_fuse).to receive(:can_mkdir?).with(TEST_FILE).and_return(false)
188
- expect{@fuse.mkdir(nil,TEST_FILE,004555)}.to raise_error(Errno::EACCES)
189
- end
190
-
191
- it ":mknod should raise EACCES unless mode requests a regular file" do
192
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
193
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
194
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
195
- expect{@fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFLNK | 0644,0,0)}.to raise_error(Errno::EACCES)
196
- end
197
-
198
- it ":mknod should result in getattr returning a Stat like object representing an empty file" do
199
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
200
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
201
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
202
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
203
-
204
- stat = @fuse.getattr(nil,TEST_FILE)
205
- expect(filetype(stat.mode)).to eq(RFuse::Stat::S_IFREG)
206
- expect(stat.size).to eq(0)
207
- end
208
-
209
- it "should create zero length files" do
210
- ffi = Struct::FuseFileInfo.new()
211
- ffi.flags = Fcntl::O_WRONLY
212
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
213
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
214
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
215
- expect(@mock_fuse).to receive(:write_to).once.with(TEST_FILE,"")
216
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
217
- @fuse.open(nil,TEST_FILE,ffi)
218
- @fuse.flush(nil,TEST_FILE,ffi)
219
- @fuse.release(nil,TEST_FILE,ffi)
220
- end
221
-
222
- it ":mkdir should not raise error if can_mkdir?" do
223
- expect(@mock_fuse).to receive(:can_mkdir?).with(TEST_FILE).and_return(true)
224
- @fuse.mkdir(nil,TEST_FILE,004555)
225
- end
226
-
227
- end
228
-
229
- context "reading files" do
230
- it "should read the contents of a file" do
231
- ffi = Struct::FuseFileInfo.new()
232
- ffi.flags = Fcntl::O_RDONLY
233
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(true)
234
- allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("Hello World\n")
235
- @fuse.open(nil,TEST_FILE,ffi)
236
- #to me fuse is backwards -- size, offset!
237
- expect(@fuse.read(nil,TEST_FILE,5,0,ffi)).to eq("Hello")
238
- expect(@fuse.read(nil,TEST_FILE,4,6,ffi)).to eq("Worl")
239
- expect(@fuse.read(nil,TEST_FILE,10,8,ffi)).to eq("rld\n")
240
- @fuse.flush(nil,TEST_FILE,ffi)
241
- @fuse.release(nil,TEST_FILE,ffi)
242
- end
243
- end
244
-
245
- context "writing files" do
246
- it "should overwrite a file opened WR_ONLY" do
247
- ffi = Struct::FuseFileInfo.new()
248
- ffi.flags = Fcntl::O_WRONLY
249
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
250
- allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
251
- expect(@mock_fuse).to receive(:write_to).once().with(TEST_FILE,"My new contents\n")
252
- @fuse.open(nil,TEST_FILE,ffi)
253
- @fuse.ftruncate(nil,TEST_FILE,0,ffi)
254
- @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
255
- @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
256
- @fuse.flush(nil,TEST_FILE,ffi)
257
- #that's right flush can be called more than once.
258
- @fuse.flush(nil,TEST_FILE,ffi)
259
- #but then we can write some more and flush again
260
- @fuse.release(nil,TEST_FILE,ffi)
261
- end
262
-
263
- it "should append to a file opened WR_ONLY | APPEND" do
264
- ffi = Struct::FuseFileInfo.new()
265
- ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
266
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
267
- allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
268
- expect(@mock_fuse).to receive(:write_to).once().with(TEST_FILE,"I'm writing a file\nMy new contents\n")
269
- @fuse.open(nil,TEST_FILE,ffi)
270
- @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
271
- @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
272
- @fuse.flush(nil,TEST_FILE,ffi)
273
- #that's right flush can be called more than once. But we should only write-to the first time
274
- @fuse.flush(nil,TEST_FILE,ffi)
275
- @fuse.release(nil,TEST_FILE,ffi)
276
-
277
- end
278
-
279
- it "should do sensible things for files opened RDWR"
280
-
281
- it "should pass on buffered data when requested (fsync)"
282
-
283
- end
284
-
285
- context "raw reading" do
286
-
287
- it "should call the raw_read/raw_close if raw_open returns true" do
288
- ffi = Struct::FuseFileInfo.new()
289
- ffi.flags = Fcntl::O_RDONLY
290
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
291
- expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"r",true).and_return("raw")
292
- expect(@mock_fuse).to receive(:raw_read).with(TEST_FILE,5,0,"raw").and_return("12345")
293
- expect(@mock_fuse).to receive(:raw_read).with(TEST_FILE,5,5,"raw").and_return("67890")
294
- expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,"raw")
295
- @fuse.open(nil,TEST_FILE,ffi)
296
- expect(@fuse.read(nil,TEST_FILE,0,5,ffi)).to eq("12345")
297
- expect(@fuse.read(nil,TEST_FILE,5,5,ffi)).to eq("67890")
298
- @fuse.flush(nil,TEST_FILE,ffi)
299
- @fuse.release(nil,TEST_FILE,ffi)
300
- end
301
-
302
- end
303
-
304
- context "raw writing" do
305
- it "should call other raw_* methods if raw_open returns true" do
306
- ffi = Struct::FuseFileInfo.new()
307
- ffi.flags = Fcntl::O_WRONLY
308
- raw = Object.new()
309
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
310
- expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
311
- expect(@mock_fuse).to receive(:raw_truncate).with(TEST_FILE,0,raw)
312
- expect(@mock_fuse).to receive(:raw_write).with(TEST_FILE,0,5,"12345",raw).once().and_return(5)
313
- expect(@mock_fuse).to receive(:raw_write).with(TEST_FILE,5,5,"67890",raw).once().and_return(5)
314
- expect(@mock_fuse).to receive(:raw_sync).with(TEST_FILE, false, raw)
315
- expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,raw)
316
- @fuse.open(nil,TEST_FILE,ffi)
317
- @fuse.ftruncate(nil,TEST_FILE,0,ffi)
318
- expect(@fuse.write(nil,TEST_FILE,"12345",0,ffi)).to eq(5)
319
- @fuse.fsync(nil,TEST_FILE,0,ffi)
320
- expect(@fuse.write(nil,TEST_FILE,"67890",5,ffi)).to eq(5)
321
- @fuse.flush(nil,TEST_FILE,ffi)
322
- @fuse.release(nil,TEST_FILE,ffi)
323
- end
324
-
325
- it "should clean up created files" do
326
- ffi = Struct::FuseFileInfo.new()
327
- ffi.flags = Fcntl::O_WRONLY
328
- raw = Object.new()
329
- allow(@mock_fuse).to receive(:directory?).and_return(false)
330
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false,true)
331
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
332
- expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
333
- expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,raw)
334
- expect(@mock_fuse).to receive(:size).with(TEST_FILE).and_return(25)
335
-
336
- expect { @fuse.getattr(nil,TEST_FILE) }.to raise_error(Errno::ENOENT)
337
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
338
- @fuse.open(nil,TEST_FILE,ffi)
339
- @fuse.flush(nil,TEST_FILE,ffi)
340
- @fuse.release(nil,TEST_FILE,ffi)
341
- stat = @fuse.getattr(nil,TEST_FILE)
342
- stat.size = 25
343
- end
344
-
345
- it "should pass 'wa' to raw_open if fuse sends WRONLY | APPEND" do
346
- ffi = Struct::FuseFileInfo.new()
347
- ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
348
- raw = Object.new()
349
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
350
- expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"wa",true).and_return(raw)
351
- @fuse.open(nil,TEST_FILE,ffi)
352
- end
353
- end
354
-
355
- context "deleting files" do
356
- it "should raise EACCES unless :can_delete?" do
357
- expect(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(false)
358
- expect {@fuse.unlink(nil,TEST_FILE)}.to raise_error(Errno::EACCES)
359
- end
360
-
361
- it "should :delete without error if :can_delete?" do
362
- allow(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(true)
363
- expect(@mock_fuse).to receive(:delete).with(TEST_FILE)
364
- @fuse.unlink(nil,TEST_FILE)
365
- end
366
-
367
- it "should remove entries created with mknod that have never been opened" do
368
- allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
369
- allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
370
- allow(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(true)
371
- allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
372
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
373
-
374
- @fuse.unlink(nil,TEST_FILE)
375
- expect {@fuse.getattr(nil,TEST_FILE)}.to raise_error(Errno::ENOENT)
376
- end
377
- end
378
-
379
- context "deleting directories" do
380
- it "should raise EACCES unless :can_rmdir?" do
381
- expect(@mock_fuse).to receive(:can_rmdir?).with(TEST_DIR).and_return(false)
382
- expect{@fuse.rmdir(nil,TEST_DIR)}.to raise_error(Errno::EACCES)
383
- end
384
-
385
- it "should :rmdir without error if :can_rmdir?" do
386
- allow(@mock_fuse).to receive(:can_rmdir?).with(TEST_DIR).and_return(true)
387
- @fuse.rmdir(nil,TEST_DIR)
388
- end
389
- end
390
-
391
- context "touching files" do
392
- it "should call :touch in response to utime" do
393
- expect(@mock_fuse).to receive(:touch).with(TEST_FILE,220)
394
- @fuse.utime(nil,TEST_FILE,100,220)
395
- end
396
- end
397
-
398
- context "renaming files" do
399
- before(:each) do
400
- @oldfile = "/aPath/oldFile"
401
- @newfile = "/aNewFile"
402
- allow(@mock_fuse).to receive(:file?).with(@oldfile).and_return(true)
403
- allow(@mock_fuse).to receive(:directory?).with(@oldfile).and_return(false)
404
- end
405
- it "should raise EACCES unless :can_write? the new file" do
406
- allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
407
- expect(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(false)
408
- expect {@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
409
- end
410
-
411
- it "should raise EACCES unless :can_delete the old file" do
412
- allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
413
- expect(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(false)
414
- expect {@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
415
- end
416
-
417
- it "should copy and delete files" do
418
- allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
419
- allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
420
- expect(@mock_fuse).to receive(:read_file).with(@oldfile).and_return("some contents\n")
421
- expect(@mock_fuse).to receive(:write_to).with(@newfile,"some contents\n")
422
- expect(@mock_fuse).to receive(:delete).with(@oldfile)
423
- @fuse.rename(nil,@oldfile,@newfile)
424
- end
425
-
426
- it "should not copy and delete files if fs responds_to? :rename" do
427
- expect(@mock_fuse).to receive(:rename).with(@oldfile,@newfile).and_return(true)
428
- @fuse.rename(nil,@oldfile,@newfile)
429
- end
430
-
431
- it "should raise EACCES if moving a directory and rename not supported" do
432
- allow(@mock_fuse).to receive(:file?).with(@oldfile).and_return(false)
433
- allow(@mock_fuse).to receive(:directory?).with(@oldfile).and_return(true)
434
- allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
435
- allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
436
- expect{@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
437
- end
438
-
439
- end
440
- context "extended attributes" do
441
-
442
- let(:xattr) { double(:xattr) }
443
- before(:each) { allow(@mock_fuse).to receive(:xattr).with(TEST_FILE).and_return(xattr) }
444
-
445
- it "should list attributes via #keys on result of #xattr" do
446
- expect(xattr).to receive(:keys).and_return(["one","two"])
447
- expect(@fuse.listxattr(nil,TEST_FILE)).to eq([ "one","two" ])
448
- end
449
-
450
- it "should get attributes via #xattr.[]" do
451
- expect(xattr).to receive(:[]).with("user.one").and_return("one")
452
-
453
- expect(@fuse.getxattr(nil,TEST_FILE,"user.one")).to eq("one")
454
- end
455
-
456
- it "should set attributes via #xattr.[]=" do
457
- expect(xattr).to receive(:[]=).with("user.two","two")
458
-
459
- @fuse.setxattr(nil,TEST_FILE,"user.two","two",0)
460
- end
461
-
462
- it "should remove attributes via #xattr.delete" do
463
- expect(xattr).to receive(:delete).with("user.three")
464
-
465
- @fuse.removexattr(nil,TEST_FILE,"user.three")
466
- end
467
-
468
- it "should raise ENODATA when #xattr.[] returns nil" do
469
-
470
- expect(xattr).to receive(:[]).with("user.xxxx").and_return(nil)
471
- expect{@fuse.getxattr(nil,TEST_FILE,"user.xxxx") }.to raise_error(Errno::ENODATA)
472
- end
473
- end
474
-
475
- context "#statfs" do
476
- # used space, used files, total_space, total_files
477
- let(:stats) { [ 1000 * 1024, 5, 1200 * 1024, 12 ] }
478
- it "should convert simple array into StatVfs" do
479
-
480
- expect(@mock_fuse).to receive(:statistics).with(TEST_FILE).and_return(stats)
481
-
482
- result = @fuse.statfs(nil,TEST_FILE)
483
- expect(result).to be_kind_of(RFuse::StatVfs)
484
- expect(result.f_bsize).to eq(1024)
485
- expect(result.f_blocks).to eq(1200)
486
- expect(result.f_bavail).to eq(200)
487
- expect(result.f_files).to eq(12)
488
- expect(result.f_ffree).to eq(7)
489
- end
490
-
491
- it "passes on raw statistics" do
492
- statvfs = Object.new()
493
- expect(@mock_fuse).to receive(:statistics).with(TEST_FILE).and_return(statvfs)
494
-
495
- expect(@fuse.statfs(nil,TEST_FILE)).to equal(statvfs)
496
- end
497
-
498
- end
499
- end
500
-
501
- describe "a FuseFS filesystem with gid/uid specific behaviour" do
502
- it "should provide context uid and gid for all API methods"
503
- end
504
-
505
- end