rfusefs 1.0.2.RC0 → 1.0.2.RC1
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/README.rdoc +5 -4
- data/Rakefile +3 -0
- data/lib/fuse/fusedir.rb +106 -22
- data/lib/fuse/rfusefs-fuse.rb +98 -27
- data/lib/fusefs/metadir.rb +46 -4
- data/lib/fusefs/pathmapper.rb +121 -20
- data/lib/rfusefs/version.rb +1 -1
- data/lib/rfusefs.rb +6 -3
- data/rfusefs.gemspec +3 -1
- data/samples/demo.rb +4 -6
- data/samples/hello.rb +1 -4
- data/spec/metadir_spec.rb +69 -0
- data/spec/pathmapper_spec.rb +276 -61
- data/spec/rfusefs_spec.rb +73 -17
- metadata +36 -4
data/spec/pathmapper_spec.rb
CHANGED
@@ -3,40 +3,47 @@ require "spec_helper"
|
|
3
3
|
require "fusefs/pathmapper"
|
4
4
|
require 'tmpdir'
|
5
5
|
require 'pathname'
|
6
|
+
require 'sys/filesystem'
|
7
|
+
require 'ffi-xattr/extensions'
|
6
8
|
|
7
9
|
class PMFixture
|
8
10
|
attr_reader :tmpdir
|
9
11
|
|
10
12
|
def initialize()
|
11
|
-
|
12
|
-
pathmap(@tmpdir + "hello.txt","/textfiles/hello")
|
13
|
-
pathmap(@tmpdir + "mysong.mp3","/artist/album/mysong.mp3")
|
14
|
-
pathmap(@tmpdir + "apicture.jpeg","/pictures/201103/apicture.jpg")
|
13
|
+
#Note - these names define the filesystem stats so if you change them those tests will break
|
15
14
|
end
|
16
15
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
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
|
20
28
|
end
|
29
|
+
fs.map_file(real_file,mapped_path,options)
|
21
30
|
end
|
22
31
|
|
23
32
|
def fs
|
24
|
-
@fs ||= FuseFS::PathMapperFS.
|
25
|
-
File.file?(file) ? IO.read(file.to_s) : nil
|
26
|
-
end
|
33
|
+
@fs ||= FuseFS::PathMapperFS.new()
|
27
34
|
end
|
28
35
|
|
29
36
|
def mount()
|
30
37
|
return @mountpoint if @mountpoint
|
31
38
|
@mountpoint = Pathname.new(Dir.mktmpdir("rfusefs_pathmapper_mnt"))
|
32
39
|
FuseFS.mount(fs,@mountpoint)
|
33
|
-
sleep(0.5)
|
40
|
+
sleep(0.5)
|
34
41
|
@mountpoint
|
35
42
|
end
|
36
43
|
|
37
44
|
def cleanup
|
38
45
|
if @mountpoint
|
39
|
-
FuseFS.unmount(@mountpoint)
|
46
|
+
FuseFS.unmount(@mountpoint)
|
40
47
|
sleep(0.5)
|
41
48
|
FileUtils.rmdir(@mountpoint)
|
42
49
|
end
|
@@ -46,134 +53,333 @@ end
|
|
46
53
|
|
47
54
|
|
48
55
|
describe FuseFS::PathMapperFS do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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")
|
53
66
|
end
|
54
67
|
|
55
68
|
after(:each) do
|
56
|
-
|
69
|
+
fixture.cleanup
|
57
70
|
end
|
58
71
|
|
59
72
|
context "fusefs api" do
|
60
73
|
|
61
74
|
it "maps files and directories" do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
71
84
|
end
|
72
85
|
|
73
86
|
it "lists the mapped contents of directories" do
|
74
|
-
|
75
|
-
|
76
|
-
|
87
|
+
pathmap_fs.contents("/").should =~ [ "textfiles","artist","pictures" ]
|
88
|
+
pathmap_fs.contents("/artist").should =~ [ "album" ]
|
89
|
+
pathmap_fs.contents("/textfiles").should =~ [ "hello" ]
|
77
90
|
end
|
78
91
|
|
79
92
|
it "reports the size of a file" do
|
80
|
-
|
93
|
+
pathmap_fs.size("/textfiles/hello").should == 16
|
81
94
|
end
|
82
95
|
|
83
96
|
it "reads the contents of a file" do
|
84
|
-
|
97
|
+
pathmap_fs.read_file("/textfiles/hello").should == "/textfiles/hello"
|
85
98
|
end
|
86
99
|
|
87
100
|
it "does not allow writes" do
|
88
|
-
|
101
|
+
pathmap_fs.can_write?("/textfiles/hello").should be_false
|
89
102
|
end
|
90
103
|
|
91
104
|
it "reports the atime,mtime and ctime of the mapped file" do
|
92
|
-
atime,mtime,ctime =
|
93
|
-
picture =
|
105
|
+
atime,mtime,ctime = pathmap_fs.times("/pictures/201103/apicture.jpg")
|
106
|
+
picture = tmpdir + "apicture.jpeg"
|
94
107
|
atime.should == picture.atime()
|
95
108
|
mtime.should == picture.mtime()
|
96
109
|
ctime.should == picture.ctime()
|
97
110
|
end
|
98
111
|
|
99
|
-
|
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
|
100
202
|
|
101
203
|
context "writing to a pathmapped FS" do
|
102
204
|
before(:each) do
|
103
|
-
|
104
|
-
|
205
|
+
pathmap_fs.allow_write=true
|
206
|
+
pathmap_fs.write_to("textfiles/hello","updated content")
|
105
207
|
end
|
106
208
|
|
107
209
|
it "updates the contents of the real file" do
|
108
|
-
hello_path =
|
210
|
+
hello_path = tmpdir + "hello.txt"
|
109
211
|
hello_path.read.should == "updated content"
|
110
212
|
end
|
111
213
|
|
112
214
|
it "updates the contents of the mapped file" do
|
113
|
-
|
215
|
+
pathmap_fs.read_file("textfiles/hello").should == "updated content"
|
114
216
|
end
|
115
217
|
|
116
218
|
it "changes the reported file size" do
|
117
|
-
|
219
|
+
pathmap_fs.size("textfiles/hello").should == 15
|
118
220
|
end
|
119
221
|
|
120
|
-
it "changes the filesystem statistics"
|
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
|
121
226
|
end
|
122
227
|
|
123
228
|
end
|
124
229
|
|
125
230
|
context "a real Fuse mounted filesystem" do
|
126
231
|
before(:each) do
|
127
|
-
|
128
|
-
@mountpoint = @fixture.mount
|
232
|
+
pathmap_fs.allow_write=true
|
129
233
|
end
|
130
234
|
|
131
235
|
it "maps files and directories" do
|
132
|
-
(
|
133
|
-
(
|
236
|
+
(mountpoint + "textfiles").directory?.should be_true
|
237
|
+
(mountpoint + "textfiles/hello").file?.should be_true
|
134
238
|
end
|
135
239
|
|
136
240
|
it "lists the mapped contents of directories" do
|
137
|
-
(
|
241
|
+
(mountpoint + "textfiles").entries.should =~ pathnames(".","..","hello")
|
138
242
|
end
|
139
243
|
|
140
244
|
it "represents the stat information of the underlying files" do
|
141
|
-
hellopath=(
|
142
|
-
realpath=(
|
245
|
+
hellopath=(mountpoint + "textfiles/hello")
|
246
|
+
realpath=(tmpdir + "hello.txt")
|
143
247
|
mappedstat = hellopath.stat
|
144
248
|
realstat = realpath.stat
|
145
249
|
mappedstat.size.should == realstat.size
|
146
|
-
mappedstat.atime.should == realstat.atime
|
250
|
+
mappedstat.atime.should == realstat.atime
|
147
251
|
mappedstat.mtime.should == realstat.mtime
|
148
252
|
mappedstat.ctime.should == realstat.ctime
|
149
253
|
end
|
150
254
|
|
151
255
|
it "reads the files" do
|
152
|
-
hellopath=
|
256
|
+
hellopath= mountpoint + "textfiles/hello"
|
153
257
|
hellopath.read.should == "/textfiles/hello"
|
154
258
|
end
|
155
259
|
|
156
260
|
it "writes the files" do
|
157
|
-
hellopath=
|
158
|
-
real_path =
|
261
|
+
hellopath= mountpoint + "textfiles/hello"
|
262
|
+
real_path = tmpdir + "hello.txt"
|
159
263
|
hellopath.open("w") do |f|
|
160
264
|
f.print "updated content"
|
161
|
-
end
|
265
|
+
end
|
162
266
|
hellopath.read.should == "updated content"
|
163
267
|
real_path.read.should == "updated content"
|
164
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
|
165
372
|
end
|
166
373
|
|
167
374
|
context "a real Fuse mount with raw file access" do
|
168
375
|
|
169
376
|
before(:each) do
|
170
|
-
|
171
|
-
|
172
|
-
@mountpoint = @fixture.mount
|
377
|
+
pathmap_fs.use_raw_file_access = true
|
378
|
+
pathmap_fs.allow_write = true
|
173
379
|
end
|
174
380
|
|
175
381
|
it "reads files" do
|
176
|
-
hello_path = (
|
382
|
+
hello_path = (mountpoint + "textfiles/hello")
|
177
383
|
hello_path.open do |f|
|
178
384
|
f.seek(2)
|
179
385
|
f.read(3).should == "ext"
|
@@ -186,17 +392,26 @@ describe FuseFS::PathMapperFS do
|
|
186
392
|
end
|
187
393
|
|
188
394
|
it "writes files" do
|
189
|
-
hello_path = (
|
190
|
-
real_path =
|
395
|
+
hello_path = (mountpoint + "textfiles/hello")
|
396
|
+
real_path = tmpdir + "hello.txt"
|
191
397
|
hello_path.open("r+") do |f|
|
192
398
|
f.sysseek(2)
|
193
399
|
f.syswrite("zzz")
|
194
400
|
f.sysseek(0)
|
195
401
|
f.sysread(6).should == "/tzzzf"
|
196
|
-
end
|
402
|
+
end
|
197
403
|
|
198
|
-
real_path.read.should == "/tzzzfiles/hello"
|
404
|
+
real_path.read.should == "/tzzzfiles/hello"
|
199
405
|
end
|
200
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
|
201
416
|
end
|
202
417
|
end
|
data/spec/rfusefs_spec.rb
CHANGED
@@ -197,10 +197,23 @@ describe FuseFS do
|
|
197
197
|
filetype(stat.mode).should == RFuse::Stat::S_IFREG
|
198
198
|
stat.size.should == 0
|
199
199
|
end
|
200
|
-
|
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
|
+
|
201
214
|
it ":mkdir should not raise error if can_mkdir?" do
|
202
215
|
@mock_fuse.should_receive(:can_mkdir?).with(TEST_FILE).and_return(true)
|
203
|
-
@fuse.mkdir(nil,TEST_FILE,004555)
|
216
|
+
@fuse.mkdir(nil,TEST_FILE,004555)
|
204
217
|
end
|
205
218
|
|
206
219
|
end
|
@@ -254,9 +267,11 @@ describe FuseFS do
|
|
254
267
|
@fuse.release(nil,TEST_FILE,ffi)
|
255
268
|
|
256
269
|
end
|
257
|
-
|
270
|
+
|
258
271
|
it "should do sensible things for files opened RDWR"
|
259
|
-
|
272
|
+
|
273
|
+
it "should pass on buffered data when requested (fsync)"
|
274
|
+
|
260
275
|
end
|
261
276
|
|
262
277
|
context "raw reading" do
|
@@ -278,19 +293,21 @@ describe FuseFS do
|
|
278
293
|
end
|
279
294
|
|
280
295
|
context "raw writing" do
|
281
|
-
it "should call
|
296
|
+
it "should call other raw_* methods if raw_open returns true" do
|
282
297
|
ffi = Struct::FuseFileInfo.new()
|
283
|
-
ffi.flags = Fcntl::O_WRONLY
|
298
|
+
ffi.flags = Fcntl::O_WRONLY
|
284
299
|
raw = Object.new()
|
285
300
|
@mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
|
286
301
|
@mock_fuse.should_receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
|
287
302
|
@mock_fuse.should_receive(:raw_truncate).with(TEST_FILE,0,raw)
|
288
303
|
@mock_fuse.should_receive(:raw_write).with(TEST_FILE,0,5,"12345",raw).once().and_return(5)
|
289
304
|
@mock_fuse.should_receive(:raw_write).with(TEST_FILE,5,5,"67890",raw).once().and_return(5)
|
305
|
+
@mock_fuse.should_receive(:raw_sync).with(TEST_FILE, false, raw)
|
290
306
|
@mock_fuse.should_receive(:raw_close).with(TEST_FILE,raw)
|
291
307
|
@fuse.open(nil,TEST_FILE,ffi)
|
292
308
|
@fuse.ftruncate(nil,TEST_FILE,0,ffi)
|
293
309
|
@fuse.write(nil,TEST_FILE,"12345",0,ffi).should == 5
|
310
|
+
@fuse.fsync(nil,TEST_FILE,0,ffi)
|
294
311
|
@fuse.write(nil,TEST_FILE,"67890",5,ffi).should == 5
|
295
312
|
@fuse.flush(nil,TEST_FILE,ffi)
|
296
313
|
@fuse.release(nil,TEST_FILE,ffi)
|
@@ -393,24 +410,63 @@ describe FuseFS do
|
|
393
410
|
end
|
394
411
|
context "extended attributes" do
|
395
412
|
|
396
|
-
let(:xattr) {
|
413
|
+
let(:xattr) { mock(:xattr) }
|
397
414
|
before(:each) { @mock_fuse.stub!(:xattr).with(TEST_FILE).and_return(xattr) }
|
398
415
|
|
399
|
-
it "should
|
400
|
-
|
401
|
-
|
402
|
-
@fuse.getxattr(nil,TEST_FILE,"user.one").should == "xattr one"
|
403
|
-
@fuse.setxattr(nil,TEST_FILE,"user.two","xattr two")
|
404
|
-
xattr["user.two"].should == "xattr two"
|
405
|
-
@fuse.listxattr(nil,TEST_FILE).should =~ [ "user.one", "user.two" ]
|
406
|
-
@fuse.removexattr(nil,TEST_FILE,"user.two")
|
407
|
-
xattr.keys.should =~ [ "user.one" ]
|
416
|
+
it "should list attributes via #keys on result of #xattr" do
|
417
|
+
xattr.should_receive(:keys).and_return(["one","two"])
|
418
|
+
@fuse.listxattr(nil,TEST_FILE).should == [ "one","two" ]
|
408
419
|
end
|
409
420
|
|
410
|
-
it "should
|
421
|
+
it "should get attributes via #xattr.[]" do
|
422
|
+
xattr.should_receive(:[]).with("user.one").and_return("one")
|
423
|
+
|
424
|
+
@fuse.getxattr(nil,TEST_FILE,"user.one").should == "one"
|
425
|
+
end
|
426
|
+
|
427
|
+
it "should set attributes via #xattr.[]=" do
|
428
|
+
xattr.should_receive(:[]=).with("user.two","two")
|
429
|
+
|
430
|
+
@fuse.setxattr(nil,TEST_FILE,"user.two","two",0)
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should remove attributes via #xattr.delete" do
|
434
|
+
xattr.should_receive(:delete).with("user.three")
|
435
|
+
|
436
|
+
@fuse.removexattr(nil,TEST_FILE,"user.three")
|
437
|
+
end
|
438
|
+
|
439
|
+
it "should raise ENODATA when #xattr.[] returns nil" do
|
440
|
+
|
441
|
+
xattr.should_receive(:[]).with("user.xxxx").and_return(nil)
|
411
442
|
lambda{@fuse.getxattr(nil,TEST_FILE,"user.xxxx") }.should raise_error(Errno::ENODATA)
|
412
443
|
end
|
413
444
|
end
|
445
|
+
|
446
|
+
context "#statfs" do
|
447
|
+
# used space, used files, total_space, total_files
|
448
|
+
let(:stats) { [ 1000 * 1024, 5, 1200 * 1024, 12 ] }
|
449
|
+
it "should convert simple array into StatVfs" do
|
450
|
+
|
451
|
+
@mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(stats)
|
452
|
+
|
453
|
+
result = @fuse.statfs(nil,TEST_FILE)
|
454
|
+
result.should be_kind_of(RFuse::StatVfs)
|
455
|
+
result.f_bsize.should == 1024
|
456
|
+
result.f_blocks.should == 1200
|
457
|
+
result.f_bavail.should == 200
|
458
|
+
result.f_files.should == 12
|
459
|
+
result.f_ffree.should == 7
|
460
|
+
end
|
461
|
+
|
462
|
+
it "passes on raw statistics" do
|
463
|
+
statvfs = Object.new()
|
464
|
+
@mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(statvfs)
|
465
|
+
|
466
|
+
@fuse.statfs(nil,TEST_FILE).should equal(statvfs)
|
467
|
+
end
|
468
|
+
|
469
|
+
end
|
414
470
|
end
|
415
471
|
|
416
472
|
describe "a FuseFS filesystem with gid/uid specific behaviour" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rfusefs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.2.
|
4
|
+
version: 1.0.2.RC1
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rfuse
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.0.
|
21
|
+
version: 1.0.5RC0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.0.
|
29
|
+
version: 1.0.5RC0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,6 +107,38 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: sys-filesystem
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: ffi-xattr
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.1.1
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.1.1
|
110
142
|
description: A more Ruby like way to write FUSE filesystems - inspired by (compatible
|
111
143
|
with) FuseFS, implemented over RFuse
|
112
144
|
email:
|