rfusefs 1.0.2.RC1 → 1.0.2.RC2
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 +1 -0
- data/lib/fuse/rfusefs-fuse.rb +8 -6
- data/lib/rfusefs/version.rb +1 -1
- data/spec/rfusefs_spec.rb +369 -349
- metadata +5 -2
data/README.rdoc
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
* https://rubygems.org/gems/rfusefs
|
4
4
|
* https://github.com/lwoggardner/rfusefs
|
5
5
|
|
6
|
+
{<img src="https://badge.fury.io/rb/rfusefs.png" alt="Gem Version" />}[http://badge.fury.io/rb/rfusefs]
|
6
7
|
== DESCRIPTION
|
7
8
|
|
8
9
|
RFuseFS is a port of the FuseFS[http://rubygems.org/gems/fusefs/]
|
data/lib/fuse/rfusefs-fuse.rb
CHANGED
@@ -93,14 +93,14 @@ module FuseFS
|
|
93
93
|
# Implements RFuseFS
|
94
94
|
# The path supplied to these methods is generally validated by FUSE itself
|
95
95
|
# with a prior "getattr" call so we do not revalidate here.
|
96
|
-
# http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
|
96
|
+
# http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
|
97
97
|
class RFuseFS
|
98
98
|
CHECK_FILE="/._rfuse_check_"
|
99
99
|
|
100
100
|
def initialize(root)
|
101
101
|
@root = root
|
102
102
|
@created_files = { }
|
103
|
-
|
103
|
+
|
104
104
|
# Keep track of changes to file counts and sizes made via Fuse - for #statfs
|
105
105
|
@adj_nodes = 0
|
106
106
|
@adj_size = 0
|
@@ -123,7 +123,7 @@ module FuseFS
|
|
123
123
|
filler.push(".",nil,0)
|
124
124
|
filler.push("..",nil,0)
|
125
125
|
|
126
|
-
files = @root.contents(path)
|
126
|
+
files = @root.contents(path)
|
127
127
|
|
128
128
|
files.each do | filename |
|
129
129
|
filler.push(filename,nil,0)
|
@@ -263,7 +263,7 @@ module FuseFS
|
|
263
263
|
raise Errno::ENOPERM.new(path)
|
264
264
|
end
|
265
265
|
end
|
266
|
-
|
266
|
+
|
267
267
|
#If we get this far, save our filehandle in the FUSE structure
|
268
268
|
ffi.fh=fh
|
269
269
|
end
|
@@ -304,7 +304,7 @@ module FuseFS
|
|
304
304
|
return fh.write(offset,buf)
|
305
305
|
end
|
306
306
|
end
|
307
|
-
|
307
|
+
|
308
308
|
def fsync(ctx,path,datasync,ffi)
|
309
309
|
return wrap_context(ctx,__method__,path,datasync,ffi) if ctx
|
310
310
|
fh = ffi.fh
|
@@ -343,6 +343,8 @@ module FuseFS
|
|
343
343
|
else
|
344
344
|
@root.raw_close(path)
|
345
345
|
end
|
346
|
+
# if was handled as raw, then assume the file has now been created (or not)
|
347
|
+
@created_files.delete(path)
|
346
348
|
else
|
347
349
|
# Probably just had flush called, but no harm calling it again
|
348
350
|
flush(nil,path,ffi)
|
@@ -448,7 +450,7 @@ module FuseFS
|
|
448
450
|
def statfs(ctx,path)
|
449
451
|
return wrap_context(ctx,__method__,path) if ctx
|
450
452
|
block_size = 1024
|
451
|
-
|
453
|
+
|
452
454
|
stats = @root.statistics(path)
|
453
455
|
case stats
|
454
456
|
when Array
|
data/lib/rfusefs/version.rb
CHANGED
data/spec/rfusefs_spec.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe FuseFS do
|
4
|
-
|
5
|
-
TEST_FILE = "/aPath/aFile"
|
4
|
+
|
5
|
+
TEST_FILE = "/aPath/aFile"
|
6
6
|
TEST_DIR = "/aPath"
|
7
7
|
ROOT_PATH = "/"
|
8
8
|
Struct.new("FuseFileInfo",:flags,:fh)
|
9
|
-
|
9
|
+
|
10
10
|
describe "an empty FuseFS object" do
|
11
11
|
before(:each) do
|
12
12
|
@fuse = FuseFS::RFuseFS.new(Object.new())
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "should return an appropriate Stat for the root directory" do
|
16
16
|
stat = @fuse.getattr(nil,ROOT_PATH)
|
17
17
|
stat.should respond_to(:dev)
|
@@ -19,24 +19,24 @@ describe FuseFS do
|
|
19
19
|
(stat.mode & RFuse::Stat::S_IFREG).should == 0
|
20
20
|
permissions(stat.mode).should == 0555
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should have an empty root directory" do
|
24
24
|
filler = mock("entries_filler")
|
25
25
|
filler.should_receive(:push).with(".",nil,0)
|
26
26
|
filler.should_receive(:push).with("..",nil,0)
|
27
27
|
@fuse.readdir(nil,"/",filler,nil,nil)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it "should raise ENOENT for other paths" do
|
31
31
|
lambda { @fuse.getattr(nil,"/somepath") }.should raise_error(Errno::ENOENT)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it "should not allow new files or directories" do
|
35
35
|
lambda { @fuse.mknod(nil,"/afile",0100644,0,0) }.should raise_error(Errno::EACCES)
|
36
36
|
lambda { @fuse.mkdir(nil,"/adir",0040555) }.should raise_error(Errno::EACCES)
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
describe "a FuseFS filesystem" do
|
41
41
|
before(:each) do
|
42
42
|
@mock_fuse = FuseFS::FuseDir.new()
|
@@ -47,7 +47,7 @@ describe FuseFS do
|
|
47
47
|
before(:each) do
|
48
48
|
@mock_fuse.should_receive(:contents).with("/apath").and_return(["afile"])
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
it "should add . and .. to the results of :contents when listing a directory" do
|
52
52
|
filler = mock("entries_filler")
|
53
53
|
filler.should_receive(:push).with(".",nil,0)
|
@@ -55,22 +55,22 @@ describe FuseFS do
|
|
55
55
|
filler.should_receive(:push).with("afile",nil,0)
|
56
56
|
@fuse.readdir(nil,"/apath",filler,nil,nil)
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
describe :getattr do
|
62
|
-
|
62
|
+
|
63
63
|
#Root directory is special (ish) so we need to run these specs twice.
|
64
64
|
[ROOT_PATH,TEST_DIR].each do |dir|
|
65
|
-
|
65
|
+
|
66
66
|
context "of a directory #{ dir }" do
|
67
|
-
|
67
|
+
|
68
68
|
before(:each) do
|
69
69
|
@mock_fuse.stub!(:file?).and_return(false)
|
70
70
|
@mock_fuse.should_receive(:directory?).with(dir).at_most(:once).and_return(true)
|
71
71
|
@checkfile = (dir == "/" ? "" : dir ) + FuseFS::RFuseFS::CHECK_FILE
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it "should return a Stat like object representing a directory" do
|
75
75
|
@mock_fuse.should_receive(:can_write?).with(@checkfile).at_most(:once).and_return(false)
|
76
76
|
@mock_fuse.should_receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(false)
|
@@ -80,398 +80,418 @@ describe FuseFS do
|
|
80
80
|
filetype(stat.mode).should == RFuse::Stat::S_IFDIR
|
81
81
|
permissions(stat.mode).should == 0555
|
82
82
|
end
|
83
|
-
|
84
|
-
|
83
|
+
|
84
|
+
|
85
85
|
it "should return writable mode if can_mkdir?" do
|
86
|
-
|
87
|
-
|
86
|
+
@mock_fuse.should_receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(true)
|
87
|
+
|
88
88
|
stat = @fuse.getattr(nil,dir)
|
89
89
|
permissions(stat.mode).should == 0777
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it "should return writable mode if can_write?" do
|
93
93
|
@mock_fuse.should_receive(:can_write?).with(@checkfile).at_most(:once).and_return(true)
|
94
|
-
|
94
|
+
|
95
95
|
stat = @fuse.getattr(nil,dir)
|
96
96
|
permissions(stat.mode).should == 0777
|
97
|
-
|
97
|
+
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
it "should return times in the result if available" do
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
106
|
end
|
107
107
|
end
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
describe "a file" do
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
116
157
|
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
158
|
end
|
159
|
-
|
159
|
+
|
160
160
|
it "should raise ENOENT for a path that does not exist" do
|
161
|
-
|
162
|
-
|
163
|
-
|
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
164
|
end
|
165
165
|
end
|
166
|
-
|
166
|
+
|
167
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
168
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
219
|
end
|
220
|
-
|
220
|
+
|
221
221
|
context "reading files" do
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
235
|
end
|
236
|
-
|
236
|
+
|
237
237
|
context "writing files" do
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
274
|
|
275
275
|
end
|
276
|
-
|
276
|
+
|
277
277
|
context "raw reading" do
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
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
|
+
|
293
294
|
end
|
294
|
-
|
295
|
+
|
295
296
|
context "raw writing" do
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
367
388
|
end
|
368
|
-
|
389
|
+
|
369
390
|
context "renaming files" do
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
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
|
381
402
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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
|
387
408
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
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
|
396
417
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
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
|
401
422
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
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
|
409
430
|
|
410
431
|
end
|
411
432
|
context "extended attributes" do
|
412
433
|
|
413
|
-
|
414
|
-
|
434
|
+
let(:xattr) { mock(:xattr) }
|
435
|
+
before(:each) { @mock_fuse.stub!(:xattr).with(TEST_FILE).and_return(xattr) }
|
415
436
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
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
|
420
441
|
|
421
|
-
|
422
|
-
|
442
|
+
it "should get attributes via #xattr.[]" do
|
443
|
+
xattr.should_receive(:[]).with("user.one").and_return("one")
|
423
444
|
|
424
|
-
|
425
|
-
|
445
|
+
@fuse.getxattr(nil,TEST_FILE,"user.one").should == "one"
|
446
|
+
end
|
426
447
|
|
427
|
-
|
428
|
-
|
448
|
+
it "should set attributes via #xattr.[]=" do
|
449
|
+
xattr.should_receive(:[]=).with("user.two","two")
|
429
450
|
|
430
|
-
|
431
|
-
|
451
|
+
@fuse.setxattr(nil,TEST_FILE,"user.two","two",0)
|
452
|
+
end
|
432
453
|
|
433
|
-
|
434
|
-
|
454
|
+
it "should remove attributes via #xattr.delete" do
|
455
|
+
xattr.should_receive(:delete).with("user.three")
|
435
456
|
|
436
|
-
|
437
|
-
|
457
|
+
@fuse.removexattr(nil,TEST_FILE,"user.three")
|
458
|
+
end
|
438
459
|
|
439
|
-
|
460
|
+
it "should raise ENODATA when #xattr.[] returns nil" do
|
440
461
|
|
441
|
-
|
442
|
-
|
443
|
-
|
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
|
444
465
|
end
|
445
466
|
|
446
467
|
context "#statfs" do
|
447
|
-
|
448
|
-
|
449
|
-
|
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
|
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
|
461
471
|
|
462
|
-
|
463
|
-
statvfs = Object.new()
|
464
|
-
@mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(statvfs)
|
472
|
+
@mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(stats)
|
465
473
|
|
466
|
-
|
467
|
-
|
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
|
468
489
|
|
469
490
|
end
|
470
491
|
end
|
471
|
-
|
492
|
+
|
472
493
|
describe "a FuseFS filesystem with gid/uid specific behaviour" do
|
473
494
|
it "should provide context uid and gid for all API methods"
|
474
495
|
end
|
475
|
-
end
|
476
|
-
|
477
496
|
|
497
|
+
end
|
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.RC2
|
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-02-
|
12
|
+
date: 2014-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rfuse
|
@@ -191,6 +191,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
191
191
|
- - ! '>='
|
192
192
|
- !ruby/object:Gem::Version
|
193
193
|
version: '0'
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
hash: -1145013380842573975
|
194
197
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
198
|
none: false
|
196
199
|
requirements:
|