class FuseFS::Fuse::Root
Implements RFuseFS
via RFuse The path supplied to these methods is generally validated by FUSE itself with a prior “getattr” call so we do not revalidate here. sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
Constants
- CHECK_FILE
Public Class Methods
# File lib/fuse/rfusefs-fuse.rb, line 511 def self.context(ctx,&block) begin Thread.current[:fusefs_reader_uid] = ctx.uid Thread.current[:fusefs_reader_gid] = ctx.gid yield ensure Thread.current[:fusefs_reader_uid] = nil Thread.current[:fusefs_reader_gid] = nil end end
# File lib/fuse/rfusefs-fuse.rb, line 121 def initialize(root) @root = root @created_files = { } # Keep track of changes to file counts and sizes made via Fuse - for #statfs @adj_nodes = 0 @adj_size = 0 #Define method missing for our filesystem #so we can just call all the API methods as required. def @root.method_missing(method,*args) # our filesystem might implement method_missing itself super rescue NoMethodError DEFAULT_FS.send(method,*args) end # Define sig<name> methods to handle signals sigmethods = Signal.list.keys.map { |sn| "sig#{sn.downcase}".to_sym }.select { |sm| @root.respond_to?(sm) } def_delegators(:@root,*sigmethods) end
Public Instance Methods
# File lib/fuse/rfusefs-fuse.rb, line 348 def flush(ctx,path,ffi) return wrap_context(ctx,__method__,path,ffi) if ctx fh = ffi.fh if fh && !fh.raw && fh.modified? #write contents to the file and mark it unmodified @root.write_to(path,fh.flush()) #if it was created with mknod it now exists in the filesystem... @created_files.delete(path) end end
# File lib/fuse/rfusefs-fuse.rb, line 333 def fsync(ctx,path,datasync,ffi) return wrap_context(ctx,__method__,path,datasync,ffi) if ctx fh = ffi.fh if fh && fh.raw if FuseFS::RFUSEFS_COMPATIBILITY @root.raw_sync(path,datasync != 0,fh.raw) else @root.raw_sync(path,datasync != 0) end else flush(nil,path,ffi) end end
ftruncate - eg called after opening a file for write without append sizes are adjusted at file close
# File lib/fuse/rfusefs-fuse.rb, line 219 def ftruncate(ctx,path,offset,ffi) return wrap_context(ctx,__method__,path,offset,ffi) if ctx fh = ffi.fh if fh.raw @root.raw_truncate(path,offset,fh.raw) if (offset <= 0) fh.contents = "" else fh.contents = fh.contents[0..offset] end end end
# File lib/fuse/rfusefs-fuse.rb, line 159 def getattr(ctx,path) return wrap_context(ctx,__method__,path) if ctx uid = Process.uid gid = Process.gid if path == "/" || @root.directory?(path) #set "w" flag based on can_mkdir? || can_write? to path + "/._rfuse_check" write_test_path = (path == "/" ? "" : path) + CHECK_FILE mode = (@root.can_mkdir?(write_test_path) || @root.can_write?(write_test_path)) ? 0777 : 0555 atime,mtime,ctime = @root.times(path) #nlink is set to 1 because apparently this makes find work. return RFuse::Stat.directory(mode,{ :uid => uid, :gid => gid, :nlink => 1, :atime => atime, :mtime => mtime, :ctime => ctime }) elsif @created_files.has_key?(path) return @created_files[path] elsif @root.file?(path) #Set mode from can_write and executable mode = 0444 mode |= 0222 if @root.can_write?(path) mode |= 0111 if @root.executable?(path) size = size(path) atime,mtime,ctime = @root.times(path) return RFuse::Stat.file(mode,{ :uid => uid, :gid => gid, :size => size, :atime => atime, :mtime => mtime, :ctime => ctime }) else raise Errno::ENOENT.new(path) end end
# File lib/fuse/rfusefs-fuse.rb, line 439 def getxattr(ctx,path,name) return wrap_context(ctx,__method__,path,name) if ctx result = @root.xattr(path)[name] raise Errno::ENODATA.new("No attribute #{name}") unless result result.to_s end
# File lib/fuse/rfusefs-fuse.rb, line 446 def listxattr(ctx,path) return wrap_context(ctx,__method__,path) if ctx @root.xattr(path).keys end
# File lib/fuse/rfusefs-fuse.rb, line 190 def mkdir(ctx,path,mode) return wrap_context(ctx,__method__,path,mode) if ctx unless @root.can_mkdir?(path) raise Errno::EACCES.new(path) end @root.mkdir(path) @adj_nodes += 1 end
# File lib/fuse/rfusefs-fuse.rb, line 202 def mknod(ctx,path,mode,major,minor) return wrap_context(ctx,__method__,path,mode,major,minor) if ctx unless ((RFuse::Stat::S_IFMT & mode) == RFuse::Stat::S_IFREG ) && @root.can_write?(path) raise Errno::EACCES.new(path) end now = Time.now stat = RFuse::Stat.file(mode,{ :uid => Process.uid, :gid => Process.gid, :atime => now, :mtime => now, :ctime => now }) @created_files[path] = stat @adj_nodes += 1 end
# File lib/fuse/rfusefs-fuse.rb, line 503 def mounted() @root.mounted() end
Open. Create a FileHandler and store in fuse file info This will be returned to us in read/write No O_CREATE (mknod first?), no O_TRUNC (truncate first)
# File lib/fuse/rfusefs-fuse.rb, line 258 def open(ctx,path,ffi) return wrap_context(ctx,__method__,path,ffi) if ctx fh = FileHandle.new(path,ffi.flags) #Save the value return from raw_open to be passed back in raw_read/write etc.. if (FuseFS::RFUSEFS_COMPATIBILITY) fh.raw = @root.raw_open(path,fh.raw_mode,true) else fh.raw = @root.raw_open(path,fh.raw_mode) end unless fh.raw if fh.rdonly? fh.contents = @root.read_file(path) elsif fh.writing? unless @root.can_write?(path) raise Errno::EACCES.new(path) end if @created_files.has_key?(path) fh.create else if fh.rdwr? || fh.append? fh.contents = @root.read_file(path) else #wronly && !append #We should get a truncate 0, but might as well play it safe fh.contents = "" end end else raise Errno::ENOPERM.new(path) end end #If we get this far, save our filehandle in the FUSE structure ffi.fh=fh end
# File lib/fuse/rfusefs-fuse.rb, line 296 def read(ctx,path,size,offset,ffi) return wrap_context(ctx,__method__,path,size,offset,ffi) if ctx fh = ffi.fh if fh.raw if FuseFS::RFUSEFS_COMPATIBILITY return @root.raw_read(path,offset,size,fh.raw) else return @root.raw_read(path,offset,size) end elsif offset >= 0 return fh.read(offset,size) else #TODO: Raise? what does a negative offset mean return "" end rescue EOFError return "" end
# File lib/fuse/rfusefs-fuse.rb, line 143 def readdir(ctx,path,filler,offset,ffi) return wrap_context(ctx,__method__,path,filler,offset,ffi) if ctx #Always have "." and ".." filler.push(".",nil,0) filler.push("..",nil,0) files = @root.contents(path) files.each do | filename | filler.push(filename,nil,0) end end
# File lib/fuse/rfusefs-fuse.rb, line 360 def release(ctx,path,ffi) return wrap_context(ctx,__method__,path,ffi) if ctx fh = ffi.fh if fh && fh.raw if (FuseFS::RFUSEFS_COMPATIBILITY) @root.raw_close(path,fh.raw) else @root.raw_close(path) end # if was handled as raw, then assume the file has now been created (or not) @created_files.delete(path) else # Probably just had flush called, but no harm calling it again flush(nil,path,ffi) end end
# File lib/fuse/rfusefs-fuse.rb, line 451 def removexattr(ctx,path,name) return wrap_context(ctx,__method__,path,name) if ctx @root.xattr(path).delete(name) end
def symlink(path,as) end
# File lib/fuse/rfusefs-fuse.rb, line 417 def rename(ctx,from,to) return wrap_context(ctx,__method__,from,to) if ctx if @root.rename(from,to) # nothing to do elsif @root.file?(from) && @root.can_write?(to) && @root.can_delete?(from) contents = @root.read_file(from) @root.write_to(to,contents) @root.delete(from) else raise Errno::EACCES.new("Unable to move directory #{from}") end end
# File lib/fuse/rfusefs-fuse.rb, line 405 def rmdir(ctx,path) return wrap_context(ctx,__method__,path) if ctx unless @root.can_rmdir?(path) raise Errno::EACCES.new(path) end @root.rmdir(path) end
def link(path,as) end
# File lib/fuse/rfusefs-fuse.rb, line 434 def setxattr(ctx,path,name,value,flags) return wrap_context(ctx,__method__,path,name,value,flags) if ctx @root.xattr(path)[name]=value end
Some random numbers to show with df command bsize preferred block size = 1K unless @root provides something different frsize = bsize (but apparently unused) blocks = total number of blocks bfree = number of free blocks bavail = bfree if mounted -o allow_other files = count of all files ffree - count of free file inode
# File lib/fuse/rfusefs-fuse.rb, line 475 def statfs(ctx,path) return wrap_context(ctx,__method__,path) if ctx block_size = 1024 stats = @root.statistics(path) case stats when Array used_space, used_files, total_space, total_files = stats used_files ||= 0 used_space ||= 0 total_files ||= used_files total_space ||= used_space result = RFuse::StatVfs.new( "bsize" => block_size, "frsize" => block_size, "blocks" => total_space / block_size, "bfree" => (total_space - used_space)/block_size, "bavail" => (total_space - used_space)/block_size, "files" => total_files, "ffree" => (total_files - used_files) ) return result else #expected to quack like rfuse:statvfs return stats end end
@private - no doc
# File lib/fuse/rfusefs-fuse.rb, line 523 def to_s "RFuseFS::#{@root}" end
truncate a file outside of open files
# File lib/fuse/rfusefs-fuse.rb, line 236 def truncate(ctx,path,offset) return wrap_context(ctx,__method__,path,offset) if ctx unless @root.can_write?(path) raise Errno::EACESS.new(path) end current_size = size(path) unless @root.raw_truncate(path,offset) contents = @root.read_file(path) if (offset <= 0) @root.write_to(path,"") elsif offset < contents.length @root.write_to(path,contents[0..offset] ) end end @adj_size = @adj_size - current_size + (offset <= 0 ? 0 : offset) end
# File lib/fuse/rfusefs-fuse.rb, line 392 def unlink(ctx,path) return wrap_context(ctx,__method__,path) if ctx unless @root.can_delete?(path) raise Errno::EACCES.new(path) end @adj_size = @adj_size - size(path) @created_files.delete(path) @root.delete(path) end
# File lib/fuse/rfusefs-fuse.rb, line 507 def unmounted() @root.unmounted() end
def chown(path,uid,gid) end
# File lib/fuse/rfusefs-fuse.rb, line 385 def utime(ctx,path,actime,modtime) return wrap_context(ctx,__method__,path,actime,modtime) if ctx #Touch... @root.touch(path,modtime) if @root.respond_to?(:touch) end
# File lib/fuse/rfusefs-fuse.rb, line 317 def write(ctx,path,buf,offset,ffi) return wrap_context(ctx,__method__,path,buf,offset,ffi) if ctx fh = ffi.fh if fh.raw if FuseFS::RFUSEFS_COMPATIBILITY return @root.raw_write(path,offset,buf.length,buf,fh.raw) else @root.raw_write(path,offset,buf.length,buf) return buf.length end else return fh.write(offset,buf) end end
Private Instance Methods
# File lib/fuse/rfusefs-fuse.rb, line 533 def size(path) @root.respond_to?(:size) ? @root.size(path) : @root.read_file(path).length end
# File lib/fuse/rfusefs-fuse.rb, line 529 def wrap_context(ctx,method,*args) self.class.context(ctx) { send(method,nil,*args) } end