rfusefs 0.8.0 → 1.0.0.RC0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,497 +1,417 @@
1
1
  # RFuseFS - FuseFS over RFuse
2
- require 'rfuse_ng'
2
+ require 'rfuse'
3
3
  require 'fcntl'
4
4
 
5
5
  module FuseFS
6
- #Which raw api should we use?
7
- RFUSEFS_COMPATIBILITY = true unless FuseFS.const_defined?(:RFUSEFS_COMPATIBILITY)
8
-
9
-
10
- # File/Directory attributes
11
- class Stat
12
- S_IFMT = 0170000 # Format mask
13
- S_IFDIR = 0040000 # Directory.
14
- S_IFCHR = 0020000 # Character device.
15
- S_IFBLK = 0060000 # Block device.
16
- S_IFREG = 0100000 # Regular file.
17
- S_IFIFO = 0010000 # FIFO.
18
- S_IFLNK = 0120000 # Symbolic link.
19
- S_IFSOCK = 0140000 # Socket.
20
-
21
- def self.directory(mode=0,values = { })
22
- return self.new(S_IFDIR,mode,values)
23
- end
24
-
25
- def self.file(mode=0,values = { })
26
- return self.new(S_IFREG,mode,values)
27
- end
28
-
29
- attr_accessor :uid,:gid,:mode,:size,:atime,:mtime,:ctime
30
- attr_accessor :dev,:ino,:nlink,:rdev,:blksize,:blocks
31
-
32
- def initialize(type,permissions,values = { })
33
- values[:mode] = ((type & S_IFMT) | (permissions & 07777))
34
- @uid,@gid,@size,@mode,@atime,@mtime,@ctime,@dev,@ino,@nlink,@rdev,@blksize,@blocks = Array.new(13,0)
35
- values.each_pair do |k,v|
36
- instance_variable_set("@#{ k }",v)
37
- end
38
- end
39
- end
40
-
41
- # Filesystem attributes (eg for df output)
42
- class StatVfs
43
- attr_accessor :f_bsize,:f_frsize,:f_blocks,:f_bfree,:f_bavail
44
- attr_accessor :f_files,:f_ffree,:f_favail,:f_fsid,:f_flag,:f_namemax
45
- #values can be symbols or strings but drop the pointless f_ prefix
46
- def initialize(values={ })
47
- @f_bsize, @f_frsize, @f_blocks, @f_bfree, @f_bavail, @f_files, @f_ffree, @f_favail,@f_fsid, @f_flag,@f_namemax = Array.new(13,0)
48
- values.each_pair do |k,v|
49
- instance_variable_set("@f_#{ k }",v)
50
- end
51
- end
52
- end
53
-
54
- class FileHandle
55
- @@fh = 0
56
- attr_reader :id,:flags,:path
57
- attr_accessor :raw,:contents
58
- def initialize(path,flags)
59
- @id = (@@fh += 1)
60
- @flags = flags
61
- @path = path
62
- @modified = false
63
- @contents = ""
64
- end
65
-
66
- def read(offset,size)
67
- contents[offset,size]
68
- end
69
-
70
- def write(offset,data)
71
- if append? || offset >= contents.length
72
- #ignore offset
73
- contents << data
74
- else
75
- contents[offset,data.length]=data
76
- end
77
- @modified = true
78
- return data.length
79
- end
80
-
81
- def flush
82
- @modified = false
83
- contents
84
- end
85
-
86
- def modified?
87
- @modified
88
- end
89
-
90
- def accmode
91
- flags & Fcntl::O_ACCMODE
92
- end
93
-
94
- def rdwr?
95
- accmode == Fcntl::O_RDWR
96
- end
97
-
98
- def wronly?
99
- accmode == Fcntl::O_WRONLY
100
- end
101
-
102
- def rdonly?
103
- accmode == Fcntl::O_RDONLY
104
- end
105
-
106
- def append?
107
- writing? && (flags & Fcntl::O_APPEND != 0)
108
- end
109
-
110
- def reading?
111
- rdonly? || rdwr?
112
- end
113
-
114
- def writing?
115
- wronly? || rdwr?
116
- end
117
-
118
- def raw_mode
119
- mode_str = case accmode
120
- when Fcntl::O_RDWR; "rw"
121
- when Fcntl::O_RDONLY; "r"
122
- when Fcntl::O_WRONLY; "w"
123
- end
124
-
125
- mode_str << "a" if append?
126
- return mode_str
127
- end
128
- end
129
-
130
- #This is the class associated with the rfuse_ng extension
131
- #We use a delegator here so we can test the RFuseFSAPI
132
- #without actually mounting FUSE
133
- class RFuseFS < RFuse::Fuse
134
- CHECK_FILE="/._rfuse_check_"
135
-
136
- #Wrap all the rfuse methods in a context block
137
- [:readdir,:getattr,:mkdir,:mknod,
138
- :truncate,:open,:read,:write,:flush,:release,
139
- :utime,:rmdir,:unlink,:rename].each do |method|
140
- method = method.id2name
141
- class_eval(<<-EOM, "(__FUSE_DELEGATE__)",1 )
142
- def #{method} (ctx,*args,&block)
143
- begin
144
- RFuseFS.context(ctx) do
145
- puts "==> #{ self }.#{ method }(\#{args.inspect })" if $DEBUG
146
- result = @delegate.send(:#{method},*args,&block)
147
- puts "<== #{ self }.#{ method }() => \#{ result.inspect }" if $DEBUG
148
- result
149
- end
150
- rescue Exception => ex
151
- $@.delete_if{|s| /^\\(__FUSE_DELEGATE__\\):/ =~s}
152
- puts(ex.message)
153
- Kernel::raise
154
- end
155
- end
156
- EOM
157
- end
158
-
159
- def initialize(mnt,kernelopt,libopt,root)
160
- @delegate = RFuseFSAPI.new(root)
161
- super(mnt.to_s,kernelopt,libopt)
162
-
163
- end
164
-
165
- def init(ctx,rfuseconninfo)
166
- #print "Init #{rfuseconninfo.inspect}\n"
167
- return nil
168
- end
169
-
170
- private
171
- def self.context(ctx)
172
- begin
173
- Thread.current[:fusefs_reader_uid] = ctx.uid
174
- Thread.current[:fusefs_reader_gid] = ctx.gid
175
- yield if block_given?
176
- ensure
177
- Thread.current[:fusefs_reader_uid] = nil
178
- Thread.current[:fusefs_reader_gid] = nil
179
- end
180
- end
181
- end #class RFuseFS
182
-
183
- # Implements the FuseFS api.
184
- # The path supplied to these methods is generally validated by FUSE itself
185
- # with a prior "getattr" call so we do not revalidate here.
186
- # http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
187
- class RFuseFSAPI
188
-
189
- #If not implemented by our filesystem these values are returned
190
- API_METHODS = {
191
- :can_write? => false,
192
- :write_to => nil,
193
- :can_delete? => false,
194
- :delete => nil,
195
- :can_mkdir? => false,
196
- :mkdir => nil,
197
- :can_rmdir? => false,
198
- :rmdir => nil,
199
- :touch => nil,
200
- :rename => nil,
201
- :raw_truncate => nil,
202
- :raw_open => nil,
203
- :raw_read => nil,
204
- :raw_write => nil,
205
- :raw_close => nil,
206
- :size => 0,
207
- :times => Array.new(3,0),
208
- :contents => Array.new(),
209
- :file? => false,
210
- :directory? => false,
211
- :executable? => false
212
- }
213
-
214
- def initialize(root)
215
- @root = root
216
- @created_files = { }
217
-
218
- #Define method missing for our filesystem
219
- #so we can just call all the API methods as required.
220
- def @root.method_missing(method,*args)
221
- if API_METHODS.has_key?(method)
222
- return API_METHODS[method]
223
- else
224
- super
6
+ #Which raw api should we use?
7
+ RFUSEFS_COMPATIBILITY = true unless FuseFS.const_defined?(:RFUSEFS_COMPATIBILITY)
8
+
9
+ class FileHandle
10
+ @@fh = 0
11
+ attr_reader :id,:flags,:path
12
+ attr_accessor :raw,:contents
13
+ def initialize(path,flags)
14
+ @id = (@@fh += 1)
15
+ @flags = flags
16
+ @path = path
17
+ @modified = false
18
+ @contents = ""
225
19
  end
226
-
227
- end
228
- end
229
-
230
-
231
- def readdir(path,filler,offset,ffi)
232
-
233
- #Always have "." and ".."
234
- filler.push(".",nil,0)
235
- filler.push("..",nil,0)
236
-
237
- @root.contents(path).each do | filename |
238
- filler.push(filename,nil,0)
239
- end
240
-
241
- end
242
-
243
- def getattr(path)
244
- uid = Process.gid
245
- gid = Process.uid
246
-
247
- if path == "/" || @root.directory?(path)
248
- #set "w" flag based on can_mkdir? || can_write? to path + "/._rfuse_check"
249
- write_test_path = (path == "/" ? "" : path) + RFuseFS::CHECK_FILE
250
-
251
- mode = (@root.can_mkdir?(write_test_path) || @root.can_write?(write_test_path)) ? 0777 : 0555
252
- atime,mtime,ctime = @root.times(path)
253
- #nlink is set to 1 because apparently this makes find work.
254
- return Stat.directory(mode,{ :uid => uid, :gid => gid, :nlink => 1, :atime => atime, :mtime => mtime, :ctime => ctime })
255
- elsif @created_files.has_key?(path)
256
- now = Time.now.to_i
257
- return Stat.file(@created_files[path],{ :uid => uid, :gid => gid, :atime => now, :mtime => now, :ctime => now })
258
- elsif @root.file?(path)
259
- #Set mode from can_write and executable
260
- mode = 0444
261
- mode |= 0222 if @root.can_write?(path)
262
- mode |= 0111 if @root.executable?(path)
263
- size = @root.size(path)
264
- atime,mtime,ctime = @root.times(path)
265
- return Stat.file(mode,{ :uid => uid, :gid => gid, :size => size, :atime => atime, :mtime => mtime, :ctime => ctime })
266
- else
267
- raise Errno::ENOENT.new(path)
268
- end
269
-
270
- end #getattr
271
-
272
- def mkdir(path,mode)
273
-
274
- unless @root.can_mkdir?(path)
275
- raise Errno::EACCES.new(path)
276
- end
277
-
278
- @root.mkdir(path)
279
- end #mkdir
280
-
281
- def mknod(path,mode,dev)
282
-
283
- unless ((Stat::S_IFMT & mode) == Stat::S_IFREG ) && @root.can_write?(path)
284
- raise Errno::EACCES.new(path)
285
- end
286
-
287
- @created_files[path] = mode
288
- end #mknod
289
-
290
- #ftruncate - eg called after opening a file for write without append
291
- def ftruncate(path,offset,ffi)
292
- fh = ffi.fh
293
-
294
- if fh.raw
295
- @root.raw_truncate(path,offset,fh.raw)
296
- elsif (offset <= 0)
297
- fh.contents = ""
298
- else
299
- fh.contents = fh.contents[0..offset]
300
- end
301
- end
302
-
303
- #truncate a file outside of open files
304
- def truncate(path,offset)
305
-
306
- unless @root.can_write?(path)
307
- raise Errno::EACESS.new(path)
308
- end
309
-
310
- unless @root.raw_truncate(path,offset)
311
- contents = @root.read_file(path)
312
- if (offset <= 0)
313
- @root.write_to(path,"")
314
- elsif offset < contents.length
315
- @root.write_to(path,contents[0..offset] )
20
+
21
+ def read(offset,size)
22
+ contents[offset,size]
316
23
  end
317
- end
318
- end #truncate
319
-
320
- # Open. Create a FileHandler and store in fuse file info
321
- # This will be returned to us in read/write
322
- # No O_CREATE (mknod first?), no O_TRUNC (truncate first)
323
- def open(path,ffi)
324
- fh = FileHandle.new(path,ffi.flags)
325
-
326
- #Save the value return from raw_open to be passed back in raw_read/write etc..
327
- if (FuseFS::RFUSEFS_COMPATIBILITY)
328
- fh.raw = @root.raw_open(path,fh.raw_mode,true)
329
- else
330
- fh.raw = @root.raw_open(path,fh.raw_mode)
331
- end
332
-
333
- unless fh.raw
334
-
335
- if fh.rdonly?
336
- fh.contents = @root.read_file(path)
337
- elsif fh.rdwr? || fh.wronly?
338
- unless @root.can_write?(path)
339
- raise Errno::EACCES.new(path)
340
- end
341
-
342
- if @created_files.has_key?(path)
343
- #we have an empty file
344
- fh.contents = "";
345
- else
346
- if fh.rdwr? || fh.append?
347
- fh.contents = @root.read_file(path)
348
- else #wronly && !append
349
- #We should get a truncate 0, but might as well play it safe
350
- fh.contents = ""
24
+
25
+ def write(offset,data)
26
+ if append? || offset >= contents.length
27
+ #ignore offset
28
+ contents << data
29
+ else
30
+ contents[offset,data.length]=data
351
31
  end
352
- end
353
- else
354
- raise Errno::ENOPERM.new(path)
32
+ @modified = true
33
+ return data.length
355
34
  end
356
- end
357
- #If we get this far, save our filehandle in the FUSE structure
358
- ffi.fh=fh
359
-
360
- end
361
-
362
- def read(path,size,offset,ffi)
363
- fh = ffi.fh
364
-
365
- if fh.raw
366
- if FuseFS::RFUSEFS_COMPATIBILITY
367
- return @root.raw_read(path,offset,size,fh.raw)
368
- else
369
- return @root.raw_read(path,offset,size)
35
+
36
+ def flush
37
+ @modified = false
38
+ contents
370
39
  end
371
- elsif offset >= 0
372
- return fh.read(offset,size)
373
- else
374
- #TODO: Raise? what does a negative offset mean
375
- return ""
376
- end
377
-
378
-
379
- end
380
-
381
- def write(path,buf,offset,ffi)
382
- fh = ffi.fh
383
-
384
- if fh.raw
385
- if FuseFS::RFUSEFS_COMPATIBILITY
386
- return @root.raw_write(path,offset,buf.length,buf,fh.raw)
387
- else
388
- @root.raw_write(path,offset,buf.length,buf)
389
- return buf.length
40
+
41
+ def modified?
42
+ @modified
390
43
  end
391
- else
392
- return fh.write(offset,buf)
393
- end
394
-
395
- end
396
-
397
- def flush(path,ffi)
398
- fh = ffi.fh
399
-
400
- if !fh.raw && fh.modified?
401
- #write contents to the file and mark it unmodified
402
- @root.write_to(path,fh.flush())
403
- #if it was created with mknod it now exists in the filesystem...
404
- @created_files.delete(path)
405
- end
406
-
407
- end
408
44
 
409
- def release(path,ffi)
410
-
411
- flush(path,ffi)
412
-
413
- fh = ffi.fh
414
- if fh.raw
415
- if (FuseFS::RFUSEFS_COMPATIBILITY)
416
- @root.raw_close(path,fh.raw)
417
- else
418
- @root.raw_close(path)
419
- end
420
- end
421
-
422
- end
423
-
424
- #def chmod(path,mode)
425
- #end
426
-
427
- #def chown(path,uid,gid)
428
- #end
429
-
430
- def utime(path,actime,modtime)
431
- #Touch...
432
- if @root.respond_to?(:touch)
433
- @root.touch(path,modtime)
434
- end
435
- end
436
-
437
- def unlink(path)
438
- unless @root.can_delete?(path)
439
- raise Errno::EACCES.new(path)
440
- end
441
- @created_files.delete(path)
442
- @root.delete(path)
45
+ def accmode
46
+ flags & Fcntl::O_ACCMODE
47
+ end
48
+
49
+ def rdwr?
50
+ accmode == Fcntl::O_RDWR
51
+ end
52
+
53
+ def wronly?
54
+ accmode == Fcntl::O_WRONLY
55
+ end
56
+
57
+ def rdonly?
58
+ accmode == Fcntl::O_RDONLY
59
+ end
60
+
61
+ def append?
62
+ writing? && (flags & Fcntl::O_APPEND != 0)
63
+ end
64
+
65
+ def reading?
66
+ rdonly? || rdwr?
67
+ end
68
+
69
+ def writing?
70
+ wronly? || rdwr?
71
+ end
72
+
73
+ def raw_mode
74
+ mode_str = case accmode
75
+ when Fcntl::O_RDWR; "rw"
76
+ when Fcntl::O_RDONLY; "r"
77
+ when Fcntl::O_WRONLY; "w"
78
+ end
79
+
80
+ mode_str << "a" if append?
81
+ return mode_str
82
+ end
443
83
  end
444
-
445
- def rmdir(path)
446
- unless @root.can_rmdir?(path)
447
- raise Errno::EACCES.new(path)
448
- end
449
- @root.rmdir(path)
84
+
85
+ # Implements RFuseFS
86
+ # The path supplied to these methods is generally validated by FUSE itself
87
+ # with a prior "getattr" call so we do not revalidate here.
88
+ # http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
89
+ class RFuseFS
90
+ CHECK_FILE="/._rfuse_check_"
91
+
92
+ def initialize(root)
93
+ @root = root
94
+ @created_files = { }
95
+
96
+ #Define method missing for our filesystem
97
+ #so we can just call all the API methods as required.
98
+ def @root.method_missing(method,*args)
99
+ # our filesystem might implement method_missing itself
100
+ super
101
+ rescue NoMethodError
102
+ DEFAULT_FS.send(method,*args)
103
+ end
104
+ end
105
+
106
+ def readdir(ctx,path,filler,offset,ffi)
107
+
108
+ return wrap_context(ctx,__method__,path,filler,offset,ffi) if ctx
109
+
110
+ #Always have "." and ".."
111
+ filler.push(".",nil,0)
112
+ filler.push("..",nil,0)
113
+
114
+ files = @root.contents(path)
115
+
116
+ files.each do | filename |
117
+ filler.push(filename,nil,0)
118
+ end
119
+
120
+ end
121
+
122
+ def getattr(ctx,path)
123
+
124
+ return wrap_context(ctx,__method__,path) if ctx
125
+
126
+ uid = Process.gid
127
+ gid = Process.uid
128
+
129
+ if path == "/" || @root.directory?(path)
130
+ #set "w" flag based on can_mkdir? || can_write? to path + "/._rfuse_check"
131
+ write_test_path = (path == "/" ? "" : path) + CHECK_FILE
132
+
133
+ mode = (@root.can_mkdir?(write_test_path) || @root.can_write?(write_test_path)) ? 0777 : 0555
134
+ atime,mtime,ctime = @root.times(path)
135
+ #nlink is set to 1 because apparently this makes find work.
136
+ return RFuse::Stat.directory(mode,{ :uid => uid, :gid => gid, :nlink => 1, :atime => atime, :mtime => mtime, :ctime => ctime })
137
+ elsif @created_files.has_key?(path)
138
+ now = Time.now.to_i
139
+ return RFuse::Stat.file(@created_files[path],{ :uid => uid, :gid => gid, :atime => now, :mtime => now, :ctime => now })
140
+ elsif @root.file?(path)
141
+ #Set mode from can_write and executable
142
+ mode = 0444
143
+ mode |= 0222 if @root.can_write?(path)
144
+ mode |= 0111 if @root.executable?(path)
145
+ size = @root.size(path)
146
+ atime,mtime,ctime = @root.times(path)
147
+ return RFuse::Stat.file(mode,{ :uid => uid, :gid => gid, :size => size, :atime => atime, :mtime => mtime, :ctime => ctime })
148
+ else
149
+ raise Errno::ENOENT.new(path)
150
+ end
151
+
152
+ end #getattr
153
+
154
+ def mkdir(ctx,path,mode)
155
+
156
+ return wrap_context(ctx,__method__,path,mode) if ctx
157
+
158
+ unless @root.can_mkdir?(path)
159
+ raise Errno::EACCES.new(path)
160
+ end
161
+
162
+ @root.mkdir(path)
163
+ end #mkdir
164
+
165
+ def mknod(ctx,path,mode,major,minor)
166
+
167
+ return wrap_context(ctx,__method__,path,mode,major,minor) if ctx
168
+
169
+ unless ((RFuse::Stat::S_IFMT & mode) == RFuse::Stat::S_IFREG ) && @root.can_write?(path)
170
+ raise Errno::EACCES.new(path)
171
+ end
172
+
173
+ @created_files[path] = mode
174
+ end #mknod
175
+
176
+ #ftruncate - eg called after opening a file for write without append
177
+ def ftruncate(ctx,path,offset,ffi)
178
+
179
+ return wrap_context(ctx,__method__,path,offset,ffi) if ctx
180
+
181
+ fh = ffi.fh
182
+
183
+ if fh.raw
184
+ @root.raw_truncate(path,offset,fh.raw)
185
+ elsif (offset <= 0)
186
+ fh.contents = ""
187
+ else
188
+ fh.contents = fh.contents[0..offset]
189
+ end
190
+ end
191
+
192
+ #truncate a file outside of open files
193
+ def truncate(ctx,path,offset)
194
+ return wrap_context(ctx,__method__,path,offset) if ctx
195
+
196
+ unless @root.can_write?(path)
197
+ raise Errno::EACESS.new(path)
198
+ end
199
+
200
+ unless @root.raw_truncate(path,offset)
201
+ contents = @root.read_file(path)
202
+ if (offset <= 0)
203
+ @root.write_to(path,"")
204
+ elsif offset < contents.length
205
+ @root.write_to(path,contents[0..offset] )
206
+ end
207
+ end
208
+ end #truncate
209
+
210
+ # Open. Create a FileHandler and store in fuse file info
211
+ # This will be returned to us in read/write
212
+ # No O_CREATE (mknod first?), no O_TRUNC (truncate first)
213
+ def open(ctx,path,ffi)
214
+ return wrap_context(ctx,__method__,path,ffi) if ctx
215
+ fh = FileHandle.new(path,ffi.flags)
216
+
217
+ #Save the value return from raw_open to be passed back in raw_read/write etc..
218
+ if (FuseFS::RFUSEFS_COMPATIBILITY)
219
+ fh.raw = @root.raw_open(path,fh.raw_mode,true)
220
+ else
221
+ fh.raw = @root.raw_open(path,fh.raw_mode)
222
+ end
223
+
224
+ unless fh.raw
225
+
226
+ if fh.rdonly?
227
+ fh.contents = @root.read_file(path)
228
+ elsif fh.rdwr? || fh.wronly?
229
+ unless @root.can_write?(path)
230
+ raise Errno::EACCES.new(path)
231
+ end
232
+
233
+ if @created_files.has_key?(path)
234
+ #we have an empty file
235
+ fh.contents = "";
236
+ else
237
+ if fh.rdwr? || fh.append?
238
+ fh.contents = @root.read_file(path)
239
+ else #wronly && !append
240
+ #We should get a truncate 0, but might as well play it safe
241
+ fh.contents = ""
242
+ end
243
+ end
244
+ else
245
+ raise Errno::ENOPERM.new(path)
246
+ end
247
+ end
248
+ #If we get this far, save our filehandle in the FUSE structure
249
+ ffi.fh=fh
250
+
251
+ end
252
+
253
+ def read(ctx,path,size,offset,ffi)
254
+ return wrap_context(ctx,__method__,path,size,offset,ffi) if ctx
255
+
256
+ fh = ffi.fh
257
+
258
+ if fh.raw
259
+ if FuseFS::RFUSEFS_COMPATIBILITY
260
+ return @root.raw_read(path,offset,size,fh.raw)
261
+ else
262
+ return @root.raw_read(path,offset,size)
263
+ end
264
+ elsif offset >= 0
265
+ return fh.read(offset,size)
266
+ else
267
+ #TODO: Raise? what does a negative offset mean
268
+ return ""
269
+ end
270
+ rescue EOFError
271
+ return ""
272
+ end
273
+
274
+ def write(ctx,path,buf,offset,ffi)
275
+ return wrap_context(ctx,__method__,path,buf,offset,ffi) if ctx
276
+ fh = ffi.fh
277
+
278
+ if fh.raw
279
+ if FuseFS::RFUSEFS_COMPATIBILITY
280
+ return @root.raw_write(path,offset,buf.length,buf,fh.raw)
281
+ else
282
+ @root.raw_write(path,offset,buf.length,buf)
283
+ return buf.length
284
+ end
285
+ else
286
+ return fh.write(offset,buf)
287
+ end
288
+
289
+ end
290
+
291
+ def flush(ctx,path,ffi)
292
+ return wrap_context(ctx,__method__,path,ffi) if ctx
293
+ fh = ffi.fh
294
+
295
+ if fh && !fh.raw && fh.modified?
296
+ #write contents to the file and mark it unmodified
297
+ @root.write_to(path,fh.flush())
298
+ #if it was created with mknod it now exists in the filesystem...
299
+ @created_files.delete(path)
300
+ end
301
+
302
+ end
303
+
304
+ def release(ctx,path,ffi)
305
+ return wrap_context(ctx,__method__,path,ffi) if ctx
306
+
307
+ flush(nil,path,ffi)
308
+
309
+ fh = ffi.fh
310
+ if fh && fh.raw
311
+ if (FuseFS::RFUSEFS_COMPATIBILITY)
312
+ @root.raw_close(path,fh.raw)
313
+ else
314
+ @root.raw_close(path)
315
+ end
316
+ end
317
+
318
+ end
319
+
320
+ #def chmod(path,mode)
321
+ #end
322
+
323
+ #def chown(path,uid,gid)
324
+ #end
325
+
326
+ def utime(ctx,path,actime,modtime)
327
+ return wrap_context(ctx,__method__,path,actime,modtime) if ctx
328
+
329
+ #Touch...
330
+ if @root.respond_to?(:touch)
331
+ @root.touch(path,modtime)
332
+ end
333
+ end
334
+
335
+ def unlink(ctx,path)
336
+ return wrap_context(ctx,__method__,path) if ctx
337
+
338
+ unless @root.can_delete?(path)
339
+ raise Errno::EACCES.new(path)
340
+ end
341
+ @created_files.delete(path)
342
+ @root.delete(path)
343
+ end
344
+
345
+ def rmdir(ctx,path)
346
+ return wrap_context(ctx,__method__,path) if ctx
347
+
348
+ unless @root.can_rmdir?(path)
349
+ raise Errno::EACCES.new(path)
350
+ end
351
+ @root.rmdir(path)
352
+ end
353
+
354
+ #def symlink(path,as)
355
+ #end
356
+
357
+ def rename(ctx,from,to)
358
+ return wrap_context(ctx,__method__,from,to) if ctx
359
+
360
+ if @root.rename(from,to)
361
+ # nothing to do
362
+ elsif @root.file?(from) && @root.can_write?(to) && @root.can_delete?(from)
363
+ contents = @root.read_file(from)
364
+ @root.write_to(to,contents)
365
+ @root.delete(from)
366
+ else
367
+ raise Errno::EACCES.new("Unable to move directory #{from}")
368
+ end
369
+ end
370
+
371
+ #def link(path,as)
372
+ #end
373
+
374
+ # def setxattr(path,name,value,size,flags)
375
+ # end
376
+
377
+ # def getxattr(path,name,size)
378
+ # end
379
+
380
+ # def listxattr(path,size)
381
+ # end
382
+
383
+ # def removexattr(path,name)
384
+ # end
385
+
386
+ #def opendir(path,ffi)
387
+ #end
388
+
389
+ #def releasedir(path,ffi)
390
+ #end
391
+
392
+ #def fsyncdir(path,meta,ffi)
393
+ #end
394
+
395
+ # Some random numbers to show with df command
396
+ #def statfs(path)
397
+ #end
398
+
399
+ def self.context(ctx,&block)
400
+ begin
401
+ Thread.current[:fusefs_reader_uid] = ctx.uid
402
+ Thread.current[:fusefs_reader_gid] = ctx.gid
403
+ yield
404
+ ensure
405
+ Thread.current[:fusefs_reader_uid] = nil
406
+ Thread.current[:fusefs_reader_gid] = nil
407
+ end
450
408
  end
451
-
452
- #def symlink(path,as)
453
- #end
454
-
455
- def rename(from,to)
456
- if @root.rename(from,to)
457
- # nothing to do
458
- elsif @root.file?(from) && @root.can_write?(to) && @root.can_delete?(from)
459
- contents = @root.read_file(from)
460
- @root.write_to(to,contents)
461
- @root.delete(from)
462
- else
463
- raise Errno::EACCES.new("Unable to move directory #{from}")
464
- end
409
+
410
+ private
411
+
412
+ def wrap_context(ctx,method,*args)
413
+ self.class.context(ctx) { send(method,nil,*args) }
465
414
  end
466
-
467
- #def link(path,as)
468
- #end
469
-
470
- # def setxattr(path,name,value,size,flags)
471
- # end
472
-
473
- # def getxattr(path,name,size)
474
- # end
475
-
476
- # def listxattr(path,size)
477
- # end
478
-
479
- # def removexattr(path,name)
480
- # end
481
-
482
- #def opendir(path,ffi)
483
- #end
484
-
485
- #def releasedir(path,ffi)
486
- #end
487
-
488
- #def fsyncdir(path,meta,ffi)
489
- #end
490
-
491
- # Some random numbers to show with df command
492
- #def statfs(path)
493
- #end
494
-
495
- end #class RFuseFSAPI
496
-
415
+
416
+ end #class RFuseFS
497
417
  end #Module FuseFS