FFI Bindings for Libfuse

gem install ffi-libfuse -v 0.0.1.pre



Ruby FFI Binding for libfuse

Writing a FUSE Filesystem

Create a class that implements the abstract methods of {FFI::Libfuse::Main} and {FFI::Libfuse::FuseOperations}

Call {FFI::Libfuse.fuse_main} to start the filesystem

require 'ffi/libfuse'

class MyFS
  # include helpers to abstract away from the native C callbacks to more idiomatic Ruby
  include FFI::Libfuse::Adapter::Ruby
  # ... FUSE callbacks .... quacks like a FFI:Libfuse::FuseOperations
  def getattr(*args)
  def readdir(*args)

FFI::Libfuse::fuse_main(operations: MyFS.new) if __FILE__ == $0

Fuse2/Fuse3 compatibility

FFI::Libfuse will prefer Fuse3 over Fuse2 by default. See {FFI::Libfuse::LIBFUSE}

For writing filesystems with backwards/forwards compatibility between fuse version see {FFI::Libfuse::Adapter::Fuse2Compat} and {FFI::Libfuse::Adapter::Fuse3Support}


macFUSE (previously OSXFuse) supports a superset of the Fuse2 api so FFI::Libfuse is intended to work in that environment.


Most Ruby filesystems are unlikely to benefit from multi-threaded operation so {FFI::Libfuse.fuse_main} as shown above injects the '-s' (single-thread) option by default.

Pass the original options in directly if multi-threaded operation is desired for your filesystem

FFI::Libfuse::fuse_main($0,*ARGV, operations: MyFS.new) if __FILE__ == $0

The {FFI::Libfuse::ThreadPool} can be configured with -o max_threads=<n>,max_idle_threads=<n> options

Callbacks that are about to block (and release the GVL for MRI) should call {FFI::Libfuse::ThreadPool.busy}.

A typical scenario would be a filesystem where some callbacks are blocking on network IO.

def read(*args)
 # prep, validate args etc.. (MRI holding the GVL anyway)
 # Now make some REST or other network call to read the data

Note Fuse itself has conditions under which filesystem callbacks will be serialized. In particular see this discussion on the serialisation of #getattr and #readdir calls.

Under the hood

FFI::Libfuse tries to provide raw access to the underlying libfuse but there some constraints imposed by Ruby.

The functions fuse_main(), fuse_daemonize() and fuse_loop<_mt>() are re-implemented in Ruby so we can provide

  • dynamic compatibility between Fuse2 and Fuse3
  • integrated support for multi-threading under MRI (see {FFI::Libfuse::ThreadPool})
  • signal handling in ruby filesystem (eg HUP to reload)

Sending `-o native' will used the native C functions but this exists to assist with testing that FFI::Libfuse has similar behaviour to libfuse itself.

See {FFI::Libfuse::Main} and {FFI::Libfuse::FuseCommon}


Bug reports and pull requests are welcome on GitHub at https://github.com/lwoggardner/ffi-libfuse.


  • Include a MetaFS, PathMapperFS etc (possibly a separate library)
  • Build a filesystem that can make use of multi-threaded operations
  • Test with macFUSE


The gem is available under the terms of the MIT License.