Module: FFI::Libfuse::Filesystem::MappedFiles

Included in:
MappedDir, PassThroughDir, PassThroughFile
Defined in:
lib/ffi/libfuse/filesystem/mapped_files.rb

Overview

An abstract filesystem mapping paths to either real files or an alternate filesystem based on outcome of #map_path as implemented by including class

Real files permissions are made read-only by default. Including classes can override #stat_mask to change this behaviour

Implements callbacks satisfying Adapter::Ruby which is automatically included.

Constant Summary collapse

HAS_XATTR =

Do we have ffi-xattr to handle extended attributes in real files

begin
  require 'ffi-xattr'
  true
rescue LoadError
  false
end

Instance Attribute Summary collapse

FUSE Callbacks collapse

Instance Method Summary collapse

Instance Attribute Details

#accountingAccounting|nil

Note:

the real LIBC statvfs is always used for non-root paths

Returns if set the accounting object will be used to provide #statfs for the root path.

Returns:

  • (Accounting|nil)

    if set the accounting object will be used to provide #statfs for the root path



34
35
36
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 34

def accounting
  @accounting
end

Instance Method Details

#create(path, perms, ffi) ⇒ Object

Create real file - assuming the path can be mapped before it exists



75
76
77
78
79
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 75

def create(path, perms, ffi)
  path_method(__method__, path, perms, ffi, error: Errno::EROFS) do |rp|
    File.open(rp, ffi.flags, perms)
  end
end

#getattr(path, stat, ffi = nil) ⇒ Object

Pass to real stat and then #stat_mask



64
65
66
67
68
69
70
71
72
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 64

def getattr(path, stat, ffi = nil)
  if (fd = ffi&.fh&.fileno)
    stat.fstat(fd)
  else
    path_method(__method__, path, stat, ffi) { |rp| stat.stat(rp) }
  end

  stat_mask(path, stat)
end

#getxattr(path, name) ⇒ String

Returns the value of the extended attribute name from the real file.

Returns:

  • (String)

    the value of the extended attribute name from the real file



126
127
128
129
130
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 126

def getxattr(path, name)
  return nil unless HAS_XATTR

  path_method(__method__, path, name) { |rp| Xattr.new(rp)[name] }
end

#listxattr(path) ⇒ Array<String>

Returns the list of extended attributes from the real file.

Returns:

  • (Array<String>)

    the list of extended attributes from the real file



133
134
135
136
137
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 133

def listxattr(path)
  return [] unless HAS_XATTR

  path_method(__method__, path) { |rp| Xattr.new(rp).list }
end

#map_path(path) ⇒ String, ...

This method is abstract.

Parameters:

  • path (String)

    the path in the fuse filesystem

Returns:

  • (String)

    mapped_path in an underlying filesystem

    Fuse callbacks are fulfilled using Ruby's native File methods called on this path

  • (String, Adapter::Ruby)

    mapped_path, filesystem

    If an optional filesystem value is returned fuse callbacks will be passed on to this filesystem with the mapped_path and other callback args unchanged

  • (nil)

    eg on create to indicate the path does not exist



# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 36

#open(path, ffi) ⇒ File

Returns the newly opened file at #map_path(path).

Returns:

  • (File)

    the newly opened file at #map_path(path)



82
83
84
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 82

def open(path, ffi)
  path_method(__method__, path, ffi) { |rp| File.open(rp, ffi.flags) }
end

#read(path, size, offset, ffi) ⇒ Object

implemented to allow for virtual files within the mapped fs, but we just rely om the result of open



87
88
89
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 87

def read(path, size, offset, ffi)
  path_method(__method__, path, size, offset, ffi) { |_rp| nil }
end

#read_buf(path, size, offset, ffi) ⇒ Object

implemented to allow for virtual files within the mapped fs, but we just rely om the result of open



92
93
94
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 92

def read_buf(path, size, offset, ffi)
  path_method(__method__, path, size, offset, ffi, error: nil) { |_rp| nil }
end

#stat_mask(path, stat) ⇒ FFI::Stat

Manipulate file attributes

Default implementation forces read-only permissions

Returns stat.

Parameters:

  • path (String)

    the path received by #getattr

  • stat (FFI::Stat)

    loaded from the mapped file, can be filled, mapped as necessary

Returns:



57
58
59
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 57

def stat_mask(_path, stat)
  stat.mask(0o0222)
end

#statfs(path, statvfs) ⇒ Object

TODO: Set xattr TODO: chmod, change the stat[:mode] TODO: chown, change the stat[:uid,:gid]



143
144
145
146
147
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 143

def statfs(path, statvfs)
  return accounting&.to_statvfs(statvfs) if root?(path)

  path_method(__method__, path, statvfs) { |rp| statvfs.from(rp) }
end

#truncate(path, size, ffi = nil) ⇒ Object

Truncates the file handle (or the real file)



107
108
109
110
111
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 107

def truncate(path, size, ffi = nil)
  return ffi.fh.truncate(size) if ffi&.fh

  path_method(__method__, path, size, ffi) { |rp| File.truncate(rp, size) }
end

Delete the real file



114
115
116
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 114

def unlink(path)
  path_method(__method__, path) { |rp| File.unlink(rp) }
end

#utimens(_path, atime, mtime, ffi = nil) ⇒ Object

Calls File.utime on an Integer file handle or the real file



119
120
121
122
123
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 119

def utimens(_path, atime, mtime, ffi = nil)
  return File.utime(atime, mtime, ffi.fh) if ffi&.fh.is_a?(Integer)

  path_method(__method__, atime, mtime, ffi) { |rp| File.utime(atime, mtime, rp) }
end

#write(path, size, offset, ffi) ⇒ Object

implemented to allow for virtual files within the mapped fs, but we just rely om the result of open



97
98
99
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 97

def write(path, size, offset, ffi)
  path_method(__method__, path, size, offset, ffi) { |_rp| nil }
end

#write_buf(path, offset, ffi, &buffer) ⇒ Object

implemented to allow for virtual files within the mapped fs, but we just rely om the result of open



102
103
104
# File 'lib/ffi/libfuse/filesystem/mapped_files.rb', line 102

def write_buf(path, offset, ffi, &buffer)
  path_method(__method__, path, offset, ffi, block: buffer, error: nil) { |_rp| nil }
end