class FuseFS::PathMapperFS

A FuseFS that maps files from their original location into a new path eg tagged audio files can be mapped by title etc…

Attributes

allow_write[RW]

should filesystem support writing through to the real files @return [Boolean]

default is false
stats[R]

@return [StatsHelper] accumulated filesystem statistics

use_raw_file_access[RW]

should raw file access should be used - useful for binary files @return [Boolean]

default is false

Public Class Methods

create(dir,options={ },&block) click to toggle source

Creates a new Path Mapper filesystem over an existing directory @param [String] dir @param [Hash] options @yieldparam [String] file path to map @yieldreturn [String] @see initialize @see map_directory

# File lib/fusefs/pathmapper.rb, line 190
def PathMapperFS.create(dir,options={ },&block)
    pm_fs = self.new(options)
    pm_fs.map_directory(dir,&block)
    return pm_fs
end
new(options = { }) click to toggle source

Create a new Path Mapper filesystem @param [Hash] options @option options [Boolean] :use_raw_file_access @option options [Boolean] :allow_write @option options [Integer] :max_space available space for writes (for df) @option options [Integer] :max_nodes available nodes for writes (for df)

# File lib/fusefs/pathmapper.rb, line 202
def initialize(options = { })
    @stats = StatsHelper.new()
    @stats.max_space = options[:max_space]
    @stats.max_nodes = options[:max_nodes]
    @root = MNode.new(nil,@stats)
    @use_raw_file_access = options[:use_raw_file_access]
    @allow_write = options[:allow_write]
end
open_mode(raw_mode) click to toggle source

Convert FuseFS raw_mode strings back to IO open mode strings

# File lib/fusefs/pathmapper.rb, line 152
def self.open_mode(raw_mode)
    case raw_mode
    when "r"
        "r"
    when "ra"
        "r" #not really sensible..
    when "rw"
        "r+"
    when "rwa"
        "a+"
    when "w"
        "w"
    when "wa"
        "a"
    end
end

Public Instance Methods

can_write?(path) click to toggle source

@!visibility private We can only write to existing files because otherwise we don't have anything to back it

# File lib/fusefs/pathmapper.rb, line 299
def can_write?(path)
    @allow_write && file?(path)
end
cleanup(&block) click to toggle source

Deletes files and directories. Yields each {#node} in the filesystem and deletes it if the block returns true

Useful if your filesystem is periodically remapping the entire contents and you need to delete entries that have not been touched in the latest scan

@yieldparam [Hash] filesystem node @yieldreturn [true,false] should this node be deleted

# File lib/fusefs/pathmapper.rb, line 268
def cleanup(&block)
   recursive_cleanup(@root,&block)
end
contents(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 280
def contents(path)
    node(path).files.keys
end
directory?(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 274
def directory?(path)
    possible_dir = node(path)
    possible_dir && possible_dir.directory?
end
file?(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 285
def file?(path)
    filename = unmap(path)
    filename && File.file?(filename)
end
mapDirectory(*dirs)
Alias for: map_directory
mapFile(real_path,new_path,options = {})
Alias for: map_file
map_directory(*dirs) { |file| ... } click to toggle source

Recursively find all files and map according to the given block @param [String…] dirs directories to list @yieldparam [String] file path to map @yieldreturn [String] the mapped path @yieldreturn nil to skip mapping this file

# File lib/fusefs/pathmapper.rb, line 216
def map_directory(*dirs)
    require 'find'
    Find.find(*dirs) do |file|
        new_path = yield file
        map_file(file,new_path) if new_path
    end
end
Also aliased as: mapDirectory
map_file(real_path,new_path,options = {}) click to toggle source

Add (or replace) a mapped file

@param [String] real_path pointing at the real file location @param [String] new_path the mapped path @param [Hash<Symbol,Object>] options metadata for this path @option options [Hash<String,String>] :xattr hash to be used as extended attributes @return [MNode]

a node representing the mapped path. See {#node}
# File lib/fusefs/pathmapper.rb, line 234
def map_file(real_path,new_path,options = {})
    make_node(new_path).init_file(real_path,options)
end
Also aliased as: mapFile
mkdir(path,options = {}) click to toggle source

Note we don't impleemnt can_mkdir? so this can only be called by code. Really only useful to create empty directories

# File lib/fusefs/pathmapper.rb, line 306
def mkdir(path,options = {})
    make_node(path).init_dir(options)
end
node(path) click to toggle source

Retrieve in memory node for a mapped path

@param [String] path @return [MNode] in memory node at path @return nil if path does not exist in the filesystem

# File lib/fusefs/pathmapper.rb, line 244
def node(path)
    path_components = scan_path(path)

    #not actually injecting anything here, we're just following the hash of hashes...
    path_components.inject(@root) { |dir,file|
        break unless dir.files[file]
        dir.files[file]
    }
end
raw_close(path,file=nil) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 394
def raw_close(path,file=nil)
    file = @openfiles.delete(path) unless file

    if file && !file.closed?
        begin
            flags = file.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE
            if flags == Fcntl::O_WRONLY || flags == Fcntl::O_RDWR
                #update stats
                node = node(path)
                node.updated if node
            end
        ensure
            file.close
        end
    end

end
raw_open(path,mode,rfusefs = nil) click to toggle source

@!visibility private Will create, store and return a File object for the underlying file for subsequent use with the raw_read/raw_close methods expects file? to return true before this method is called

# File lib/fusefs/pathmapper.rb, line 343
def raw_open(path,mode,rfusefs = nil)

    return false unless @use_raw_file_access

    return false if mode.include?("w") && (!@allow_write)

    @openfiles ||= Hash.new() unless rfusefs

    real_path = unmap(path)

    unless real_path
        if rfusefs
            raise Errno::ENOENT.new(path)
        else
            #fusefs will go on to call file?
            return false
        end
    end

    file =  File.new(real_path,PathMapperFS.open_mode(mode))

    @openfiles[path] = file unless rfusefs

    return file
end
raw_read(path,off,sz,file=nil) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 370
def raw_read(path,off,sz,file=nil)
    file = @openfiles[path] unless file
    file.sysseek(off)
    file.sysread(sz)
end
raw_sync(path,datasync,file=nil) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 384
def raw_sync(path,datasync,file=nil)
    file = @openfiles[path] unless file
    if datasync
        file.fdatasync
    else
        file.sync
    end
end
raw_write(path,offset,sz,buf,file=nil) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 377
def raw_write(path,offset,sz,buf,file=nil)
    file = @openfiles[path] unless file
    file.sysseek(offset)
    file.syswrite(buf[0,sz])
end
read_file(path) click to toggle source

@!visibility private only called if option :raw_reads is not set

# File lib/fusefs/pathmapper.rb, line 292
def read_file(path)
    IO.read(unmap(path))
end
size(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 318
def size(path)
    File.size(unmap(path))
end
statistics(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 413
def statistics(path)
    @stats.to_statistics
end
times(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 323
def times(path)
    realpath = unmap(path)
    if (realpath)
        stat = File.stat(realpath)
        return [ stat.atime, stat.mtime, stat.ctime ]
    else
        # We're a directory
        return [0,0,0]
    end
end
unmap(path) click to toggle source

Takes a mapped file name and returns the original real_path

# File lib/fusefs/pathmapper.rb, line 255
def unmap(path)
    node = node(path)
    (node && node.file?) ? node.real_path : nil
end
write_to(path,contents) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 311
def write_to(path,contents)
    node = node(path)
    File.open(node.real_path,"w") { |f| f.print(contents) }
    node.updated
end
xattr(path) click to toggle source

@!visibility private

# File lib/fusefs/pathmapper.rb, line 335
def xattr(path)
    result = node(path).xattr
end

Private Instance Methods

make_node(path) click to toggle source
# File lib/fusefs/pathmapper.rb, line 419
def make_node(path)
    #split path into components
    components = path.to_s.scan(/[^\/]+/)
    components.inject(@root) { |parent_dir, file|
        parent_dir.files[file] ||= MNode.new(parent_dir,@stats)
    }
end
recursive_cleanup(dir_node) { |child| ... } click to toggle source
# File lib/fusefs/pathmapper.rb, line 427
def recursive_cleanup(dir_node,&block)
    dir_node.files.delete_if do |path,child|
        del = if child.file?
            yield child
        else
            recursive_cleanup(child,&block)
            child.files.size == 0
        end
        child.deleted if del
        del
    end
end