Learning how to use FuseFS

January 29, 2008

Well, I started this blog about a year ago and haven’t written anything since. Ah, but now my writer’s block has been broken and here I am.

For a little while now, I’ve been interested in FUSE, but documentation has been scant and for the most part, inaccessible to me. There is even less documentation on Ruby’s bindings, FuseFS (a situation made worse by the existence of this song). The best example I’ve seen is Why the Lucky Stiff’s implementation of a filesystem for ActiveRecord objects.

Fortunately the package is reasonably well documented, and has some good sample code. Unfortunately, the business end of the library is in C, which complicates understanding what methods are doing what.

Here’s something that might help. We’re going to wrap all of methods of the supplied MetaDir (which mounts a Hash as a filesystem) in some logging calls. Now, I’m sure there’s a nicer way to do this, and you should blog about it.:P

   1  #!/usr/bin/env ruby
   2  require 'logger'
   3  require 'fusefs'
   4  
   5  METHODS_TO_IGNORE = [:__id__, :__send__, :send, :instance_variables, :puts]
   6  
   7  class TutorFS < FuseFS::MetaDir
   8    superclass.instance_methods.reject {|method_name|
   9      METHODS_TO_IGNORE.include? method_name.to_sym
  10    }.find_all {|method_name|
  11      method_name.to_s =~ /^[A-Za-z].*/
  12    }.each do |method_name|
  13      alias_method "old_#{method_name.to_s}".to_sym, method_name
  14      self.class_eval(%{
  15        def #{method_name}(*args, &block)
  16          @log.debug "Called #{method_name.to_s} with \#{args}"
  17          send(} + ":old_#{method_name}" +%{, *args, &block)
  18        end
  19      })
  20  
  21      puts "Wrapped :#{method_name}"
  22    end
  23  
  24    def initialize
  25      @log = Logger.new(STDOUT)
  26      @log.datetime_format = "%H:%M:%S"
  27      @log.level = Logger::DEBUG
  28      super
  29    end
  30  end
  31  
  32  if (File.basename($0) == File.basename(__FILE__))
  33    if (ARGV.size != 1)
  34      puts "Usage: #{$0} "
  35      exit
  36    end
  37  
  38    dirname = ARGV[0]
  39  
  40    unless File.directory?(dirname)
  41      puts "Usage: #{dirname} is not a directory."
  42      exit
  43    end
  44  
  45    root = TutorFS.new
  46  
  47    # Set the root FuseFS
  48    FuseFS.set_root(root)
  49  
  50    FuseFS.mount_under(dirname)
  51  
  52    FuseFS.run # This doesn't return until we're unmounted.
  53  end

When you mount this, it should give you access to the hash at the filesystem level. It should also start logging your messages and their arguments.

Advertisements