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