rfusefs 0.8.0 → 1.0.0.RC0

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.
@@ -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