Class: FFI::Libfuse::Filesystem::VirtualFS
- Inherits:
-
Object
- Object
- FFI::Libfuse::Filesystem::VirtualFS
- Includes:
- Adapter::Context, Adapter::Debug, Adapter::Fuse2Compat, Utils
- Defined in:
- lib/ffi/libfuse/filesystem/virtual_fs.rb
Overview
A configurable main Filesystem that delegates FUSE Callbacks to another filesystem
This class registers support for all available fuse callbacks, subject to the options below.
Delegate filesystems like VirtualDir may raise ENOTSUP to indicate a callback is not handled at runtime although the behaviour of C libfuse varies in this regard.
It is writable to the user that mounted it may create and edit files within it
Filesystem options
Passed by -o options to FFI::Libfuse.main
- :max_space used for #FFI::Libfuse::FuseOperations#statfs. See #accounting
- :max_nodes used for #FFI::Libfuse::FuseOperations#statfs. See #accounting
:no_buf do not register :read_buf, :write_buf
when set all filesystems must implement :read/:write
when not set all filesystems must implement :read_buf, :write_buf which enables C libfuse to handle file descriptor based io, eg. MappedFiles, but means Ruby FFI is doing memory allocations for string based io, eg. VirtualFile.
Note that VirtualFile and MappedFiles both prepend Adapter::Ruby::Prepend which implements the logic to fallback from :read/:write_buf to plain :read/:write as necessary to support this option.
Constant Summary
Constants included from Adapter::Fuse2Compat
Adapter::Fuse2Compat::FUSE_CONFIG_FLAGS, Adapter::Fuse2Compat::FUSE_CONFIG_ONLY_ATTRIBUTES
Constants included from Adapter::Debug
Adapter::Debug::DEFAULT_FORMAT
Instance Attribute Summary collapse
-
#options ⇒ Hash{Symbol => String,Boolean}
readonly
Custom options captured as defined by #fuse_options.
-
#root ⇒ Object
readonly
The root filesystem that quacks like a FFI::Libfuse::FuseOperations.
Fuse Configuration collapse
-
#fuse_help ⇒ Object
Subclasses can override this method to add descriptions for additional options.
-
#fuse_options(args, opts = {}, &block) ⇒ Object
Default fuse options Subclasses can override this method and call super with the additional options: @yield(key, value, **args) Called for each matching key in opts.
-
#fuse_respond_to?(method) ⇒ Boolean
Respond to all FUSE Callbacks except deprecated, noting that ..
-
#fuse_version ⇒ Object
Subclasses can override to produce a nice version string for -V.
-
#use_ino ⇒ Boolean
Configure whether entries in this filesystem provide useful inode values in #gettattr and #readdir.
Instance Method Summary collapse
-
#accounting ⇒ Accounting|:max_space=, :max_nodes=
An accumulator of filesystem statistics used to consume the max_space and max_nodes options.
-
#build(files) ⇒ Object
Adds files directly to the filesystem according to the content implementing one of the methods below.
-
#fuse_configure(root = VirtualDir.new(accounting: accounting).mkdir('/')) ⇒ Object
Subclasses can override the no-arg method and call super to pass in a different root.
Methods included from Adapter::Debug
debug, #debug?, debug_callback, #debug_config, debug_error, debug_format, error_message
Methods included from Adapter::Safe
Methods included from Adapter::Context
fuse_context, thread_local_context
Methods included from Utils
#directory?, #empty_dir?, #empty_file?, #exists?, #file?, #mkdir_p, #stat
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object (private)
Passes FUSE Callbacks on to the #root filesystem
190 191 192 193 194 195 196 197 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 190 def method_missing(method, *args, &block) return @root.public_send(method, *args, &block) if @root.respond_to?(method) # This is not always reliable but better than raising NoMethodError return -Errno::ENOTSUP::Errno if FuseOperations.fuse_callbacks.include?(method) super end |
Instance Attribute Details
#options ⇒ Hash{Symbol => String,Boolean} (readonly)
Returns custom options captured as defined by #fuse_options.
61 62 63 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 61 def @options end |
#root ⇒ Object (readonly)
Returns the root filesystem that quacks like a FFI::Libfuse::FuseOperations.
58 59 60 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 58 def root @root end |
Instance Method Details
#accounting ⇒ Accounting|:max_space=, :max_nodes=
Returns an accumulator of filesystem statistics used to consume the max_space and max_nodes options.
65 66 67 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 65 def accounting @accounting ||= Accounting.new end |
#build(files) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 84 def build(files, base_path = Pathname.new('/')) files.each_pair do |path, content| path = (base_path + path).cleanpath @root.mkdir_p(path.dirname) unless path.dirname == base_path rt = %i[each_pair readdir getattr to_str].detect { |m| content.respond_to?(m) } raise "Unsupported initial content for #{self.class.name}: #{content.class.name}- #{content}" unless rt send("build_#{rt}", content, path) end end |
#fuse_configure(root = VirtualDir.new(accounting: accounting).mkdir('/')) ⇒ Object
Subclasses can override the no-arg method and call super to pass in a different root.
71 72 73 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 71 def fuse_configure(root = VirtualDir.new(accounting: accounting).mkdir('/')) @root = root end |
#fuse_help ⇒ Object
Subclasses can override this method to add descriptions for additional options
140 141 142 143 144 145 146 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 140 def fuse_help <<~END_HELP #{Accounting::HELP} #{self.class.name} options: -o no_buf always use read, write instead of read_buf, write_buf END_HELP end |
#fuse_options(args, opts = {}, &block) ⇒ Object
Default fuse options Subclasses can override this method and call super with the additional options: @yield(key, value, **args) Called for each matching key in opts
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 121 def (args, opts = {}, &block) @options = {} opts = opts.merge({ 'no_buf' => :no_buf }).merge(Accounting::OPTIONS) args.parse!(opts) do |key:, value:, **kwargs| case key when *Accounting::OPTIONS.values.uniq next accounting.fuse_opt_proc(key: key, value: value) when :no_buf @no_buf = true else next block.call(key, value, **kwargs) if block [key] = value end :handled end end |
#fuse_respond_to?(method) ⇒ Boolean
Respond to all FUSE Callbacks except deprecated, noting that ..
- :read_buf, :write_buf can be excluded by the 'no_buf' mount option
- :access already has a libfuse mount option (default_permissions)
- :create falls back to :mknod on ENOSYS (as raised by FFI::Libfuse::Filesystem::VirtualDir)
- :copy_file_range can raise ENOTSUP to trigger glibc to fallback to inefficient copy
106 107 108 109 110 111 112 113 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 106 def fuse_respond_to?(method) case method when :read_buf, :write_buf !no_buf else true end end |
#fuse_version ⇒ Object
Subclasses can override to produce a nice version string for -V
149 150 151 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 149 def fuse_version self.class.name end |
#use_ino ⇒ Boolean
Configure whether entries in this filesystem provide useful inode values in #gettattr and #readdir
Defaults to true since default Dir, File, Link all use FFI::Libfuse::Filesystem::VirtualNode which uses Ruby object id as the inode value.
Subclasses should override to false if some sub-filesystems will not provide inode values.
165 166 167 |
# File 'lib/ffi/libfuse/filesystem/virtual_fs.rb', line 165 def use_ino true end |