ffi-libfuse 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -22
- data/README.md +1 -1
- data/lib/ffi/accessors.rb +21 -7
- data/lib/ffi/boolean_int.rb +1 -1
- data/lib/ffi/devt.rb +3 -3
- data/lib/ffi/libfuse/adapter/debug.rb +53 -15
- data/lib/ffi/libfuse/adapter/fuse2_compat.rb +38 -21
- data/lib/ffi/libfuse/adapter/fuse3_support.rb +0 -1
- data/lib/ffi/libfuse/adapter/ruby.rb +210 -159
- data/lib/ffi/libfuse/adapter/safe.rb +69 -21
- data/lib/ffi/libfuse/callbacks.rb +2 -1
- data/lib/ffi/libfuse/filesystem/accounting.rb +1 -1
- data/lib/ffi/libfuse/filesystem/mapped_files.rb +33 -7
- data/lib/ffi/libfuse/filesystem/pass_through_dir.rb +0 -1
- data/lib/ffi/libfuse/filesystem/virtual_dir.rb +293 -126
- data/lib/ffi/libfuse/filesystem/virtual_file.rb +85 -79
- data/lib/ffi/libfuse/filesystem/virtual_fs.rb +34 -15
- data/lib/ffi/libfuse/filesystem/virtual_link.rb +60 -0
- data/lib/ffi/libfuse/filesystem/virtual_node.rb +104 -87
- data/lib/ffi/libfuse/filesystem.rb +1 -1
- data/lib/ffi/libfuse/fuse2.rb +3 -2
- data/lib/ffi/libfuse/fuse3.rb +1 -1
- data/lib/ffi/libfuse/fuse_args.rb +5 -2
- data/lib/ffi/libfuse/fuse_buf.rb +112 -0
- data/lib/ffi/libfuse/fuse_buf_vec.rb +228 -0
- data/lib/ffi/libfuse/fuse_common.rb +10 -4
- data/lib/ffi/libfuse/fuse_config.rb +16 -7
- data/lib/ffi/libfuse/fuse_operations.rb +86 -41
- data/lib/ffi/libfuse/gem_helper.rb +91 -0
- data/lib/ffi/libfuse/gem_version.rb +4 -44
- data/lib/ffi/libfuse/io.rb +56 -0
- data/lib/ffi/libfuse/main.rb +27 -24
- data/lib/ffi/libfuse/test_helper.rb +68 -60
- data/lib/ffi/libfuse/version.rb +1 -1
- data/lib/ffi/libfuse.rb +1 -1
- data/lib/ffi/stat/native.rb +4 -4
- data/lib/ffi/stat.rb +19 -3
- data/lib/ffi/struct_array.rb +2 -1
- data/sample/hello_fs.rb +1 -1
- metadata +7 -3
- data/lib/ffi/libfuse/fuse_buffer.rb +0 -257
@@ -6,88 +6,94 @@ require 'stringio'
|
|
6
6
|
module FFI
|
7
7
|
module Libfuse
|
8
8
|
module Filesystem
|
9
|
+
module Ruby
|
10
|
+
# Filesystem methods representing a single synthetic file at the root and satisfying
|
11
|
+
# Satisfies the contract of {Adapter::Ruby}
|
12
|
+
module VirtualFile
|
13
|
+
include VirtualNode
|
14
|
+
|
15
|
+
# @return [String] the (binary) content of the synthetic file
|
16
|
+
attr_reader :content
|
17
|
+
|
18
|
+
# @return [Integer] the number of links to this file
|
19
|
+
attr_reader :nlink
|
20
|
+
|
21
|
+
# Create an empty synthetic file
|
22
|
+
def initialize(accounting: nil)
|
23
|
+
super(accounting: accounting)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!group FUSE Callbacks
|
27
|
+
|
28
|
+
def getattr(path, stat = nil, ffi = nil)
|
29
|
+
# We don't exist until create or otherwise or virtual stat exists
|
30
|
+
raise Errno::ENOENT unless root?(path) && virtual_stat
|
31
|
+
|
32
|
+
stat&.file(size: (ffi&.fh || content).size, nlink: nlink, **virtual_stat)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param [String] _path ignored, expected to be '/'
|
37
|
+
# @param [Integer] mode
|
38
|
+
# @param [FuseFileInfo] ffi
|
39
|
+
# @return [Object] a file handled (captured by {Adapter::Ruby::Prepend})
|
40
|
+
def create(_path, mode, ffi = nil)
|
41
|
+
init_node(mode)
|
42
|
+
@content = String.new(encoding: 'binary')
|
43
|
+
@nlink = 1
|
44
|
+
sio(ffi) if ffi
|
45
|
+
end
|
46
|
+
|
47
|
+
def open(_path, ffi)
|
48
|
+
virtual_stat[:atime] = Time.now.utc
|
49
|
+
sio(ffi)
|
50
|
+
end
|
51
|
+
|
52
|
+
# write(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi)
|
53
|
+
def write(path, data, offset = 0, _ffi = nil)
|
54
|
+
raise Errno::ENOENT unless root?(path)
|
55
|
+
|
56
|
+
accounting&.write(content.size, data.size, offset)
|
57
|
+
virtual_stat[:mtime] = Time.now.utc
|
58
|
+
nil # just let the sio in ffi handle it
|
59
|
+
end
|
60
|
+
|
61
|
+
def truncate(path, size, ffi = nil)
|
62
|
+
raise Errno::ENOENT unless root?(path)
|
63
|
+
|
64
|
+
accounting&.truncate(content.size, size)
|
65
|
+
sio(ffi).truncate(size)
|
66
|
+
virtual_stat[:mtime] = Time.now.utc
|
67
|
+
end
|
68
|
+
|
69
|
+
def link(_target, path)
|
70
|
+
raise Errno::ENOENT unless root?(path)
|
71
|
+
|
72
|
+
accounting&.adjust(content.size, 1) if @nlink.zero?
|
73
|
+
@nlink += 1
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def unlink(path)
|
78
|
+
raise Errno::ENOENT unless root?(path)
|
79
|
+
|
80
|
+
@nlink -= 1
|
81
|
+
accounting&.adjust(-content.size, -1) if @nlink.zero?
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def sio(ffi)
|
87
|
+
ffi&.fh || StringIO.new(content, ffi&.flags)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
9
92
|
# A Filesystem representing a single synthetic file at the root
|
10
|
-
class VirtualFile
|
93
|
+
class VirtualFile
|
11
94
|
prepend Adapter::Ruby::Prepend
|
12
95
|
include Fuse2Compat
|
13
|
-
|
14
|
-
# @return [String] the (binary) content of the synthetic file
|
15
|
-
attr_reader :content
|
16
|
-
|
17
|
-
# Create an empty synthetic file
|
18
|
-
def initialize(accounting: nil)
|
19
|
-
super(accounting: accounting)
|
20
|
-
end
|
21
|
-
|
22
|
-
# @!visibility private
|
23
|
-
def path_method(_method, *_args)
|
24
|
-
raise Errno::ENOENT
|
25
|
-
end
|
26
|
-
|
27
|
-
# @!group FUSE Callbacks
|
28
|
-
|
29
|
-
def getattr(path, stat, ffi = nil)
|
30
|
-
# We don't exist until create or otherwise or virtual stat exists
|
31
|
-
raise Errno::ENOENT unless root?(path) && virtual_stat
|
32
|
-
|
33
|
-
stat.file(size: (ffi&.fh || content).size, **virtual_stat)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
# @param [String] _path ignored, expected to be '/'
|
38
|
-
# @param [Integer] mode
|
39
|
-
# @param [FuseFileInfo] ffi
|
40
|
-
# @return [Object] a file handled (captured by {Adapter::Ruby::Prepend})
|
41
|
-
def create(_path, mode, ffi = nil)
|
42
|
-
init_node(mode)
|
43
|
-
@content = String.new(encoding: 'binary')
|
44
|
-
sio(ffi) if ffi
|
45
|
-
end
|
46
|
-
|
47
|
-
def open(_path, ffi)
|
48
|
-
virtual_stat[:atime] = Time.now.utc
|
49
|
-
sio(ffi)
|
50
|
-
end
|
51
|
-
|
52
|
-
# op[:read] = [:pointer, :size_t, :off_t, FuseFileInfo.by_ref]
|
53
|
-
def read(path, size, off, ffi)
|
54
|
-
raise Errno::ENOENT unless root?(path)
|
55
|
-
|
56
|
-
io = sio(ffi)
|
57
|
-
io.seek(off)
|
58
|
-
io.read(size)
|
59
|
-
end
|
60
|
-
|
61
|
-
# write(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi)
|
62
|
-
def write(path, data, offset = 0, ffi = nil)
|
63
|
-
raise Errno::ENOENT unless root?(path)
|
64
|
-
|
65
|
-
accounting&.write(content.size, data.size, offset)
|
66
|
-
io = sio(ffi)
|
67
|
-
io.seek(offset)
|
68
|
-
io.write(data)
|
69
|
-
virtual_stat[:mtime] = Time.now.utc
|
70
|
-
end
|
71
|
-
|
72
|
-
def truncate(path, size, ffi = nil)
|
73
|
-
raise Errno::ENOENT unless root?(path)
|
74
|
-
|
75
|
-
accounting&.truncate(content.size, size)
|
76
|
-
sio(ffi).truncate(size)
|
77
|
-
virtual_stat[:mtime] = Time.now.utc
|
78
|
-
end
|
79
|
-
|
80
|
-
def unlink(path)
|
81
|
-
raise Errno::ENOENT unless root?(path)
|
82
|
-
|
83
|
-
accounting&.adjust(-content.size, -1)
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def sio(ffi)
|
89
|
-
ffi&.fh || StringIO.new(content, ffi&.flags)
|
90
|
-
end
|
96
|
+
include Ruby::VirtualFile
|
91
97
|
end
|
92
98
|
end
|
93
99
|
end
|
@@ -15,6 +15,8 @@ module FFI
|
|
15
15
|
# Delegate filesystems like {VirtualDir} may raise ENOTSUP to indicate a callback is not handled at runtime
|
16
16
|
# although the behaviour of C libfuse varies in this regard.
|
17
17
|
#
|
18
|
+
# It is writable to the user that mounted it may create and edit files within it
|
19
|
+
#
|
18
20
|
# Filesystem options
|
19
21
|
# ===
|
20
22
|
#
|
@@ -33,15 +35,14 @@ module FFI
|
|
33
35
|
# Note that {VirtualFile} and {MappedFiles} both prepend {Adapter::Ruby::Prepend} which implements
|
34
36
|
# the logic to fallback from :read/:write_buf to plain :read/:write as necessary to support this option.
|
35
37
|
#
|
36
|
-
# It is writable to the user that mounted it may create and edit files within it
|
37
|
-
#
|
38
38
|
# @example
|
39
39
|
# class MyFS < FFI::Libfuse::Filesystem::VirtualFS
|
40
40
|
# def fuse_configure
|
41
41
|
# build({ 'hello' => { 'world.txt' => 'Hello World'}})
|
42
42
|
# mkdir("/hello")
|
43
|
-
# create("/hello/world").write("Hello World!\n")
|
43
|
+
# create("/hello/world.txt").write("Hello World!\n")
|
44
44
|
# create("/hello/everybody").write("Hello Everyone!\n")
|
45
|
+
# symlink("/hello/link","everybody")`
|
45
46
|
# end
|
46
47
|
# end
|
47
48
|
#
|
@@ -51,7 +52,7 @@ module FFI
|
|
51
52
|
include Utils
|
52
53
|
include Adapter::Context
|
53
54
|
include Adapter::Debug
|
54
|
-
include Adapter::
|
55
|
+
include Adapter::Fuse2Compat
|
55
56
|
|
56
57
|
# @return [Object] the root filesystem that quacks like a {FuseOperations}
|
57
58
|
attr_reader :root
|
@@ -73,12 +74,13 @@ module FFI
|
|
73
74
|
|
74
75
|
# @overload build(files)
|
75
76
|
# Adds files directly to the filesystem
|
76
|
-
# @param [Hash] files map of paths to content
|
77
|
+
# @param [Hash<String,:each_pair, :readdir,:getattr .:to_str] files map of paths to content generated
|
78
|
+
# according to the content implementing one of the methods below
|
77
79
|
#
|
78
80
|
# * :each_pair is treated as a subdir of files
|
79
81
|
# * :readdir (eg {PassThroughDir}) is treated as a directory- sent via mkdir
|
80
82
|
# * :getattr (eg {PassThroughFile}) is treated as a file - sent via create
|
81
|
-
# * :to_str (eg {::String} ) is created
|
83
|
+
# * :to_str (eg {::String} ) is created a default file, with the string sent via write
|
82
84
|
def build(files, base_path = Pathname.new('/'))
|
83
85
|
files.each_pair do |path, content|
|
84
86
|
path = (base_path + path).cleanpath
|
@@ -103,10 +105,6 @@ module FFI
|
|
103
105
|
# * :copy_file_range can raise ENOTSUP to trigger glibc to fallback to inefficient copy
|
104
106
|
def fuse_respond_to?(method)
|
105
107
|
case method
|
106
|
-
when :getdir, :fgetattr
|
107
|
-
# TODO: Find out if fgetattr works on linux, something wrong with stat values on OSX.
|
108
|
-
# https://github.com/osxfuse/osxfuse/issues/887
|
109
|
-
false
|
110
108
|
when :read_buf, :write_buf
|
111
109
|
!no_buf
|
112
110
|
else
|
@@ -117,16 +115,21 @@ module FFI
|
|
117
115
|
# Default fuse options
|
118
116
|
# Subclasses can override this method and call super with the additional options:
|
119
117
|
# @param [Hash] opts additional options to parse into the {#options} attribute
|
120
|
-
|
118
|
+
# @yield(key, value, **args)
|
119
|
+
# Called for each matching key in opts
|
120
|
+
# @see FuseArgs#parse!
|
121
|
+
def fuse_options(args, opts = {}, &block)
|
121
122
|
@options = {}
|
122
123
|
opts = opts.merge({ 'no_buf' => :no_buf }).merge(Accounting::OPTIONS)
|
123
|
-
args.parse!(opts) do |key:, value:,
|
124
|
+
args.parse!(opts) do |key:, value:, **kwargs|
|
124
125
|
case key
|
125
126
|
when *Accounting::OPTIONS.values.uniq
|
126
127
|
next accounting.fuse_opt_proc(key: key, value: value)
|
127
128
|
when :no_buf
|
128
129
|
@no_buf = true
|
129
130
|
else
|
131
|
+
next block.call(key, value, **kwargs) if block
|
132
|
+
|
130
133
|
options[key] = value
|
131
134
|
end
|
132
135
|
:handled
|
@@ -147,6 +150,21 @@ module FFI
|
|
147
150
|
self.class.name
|
148
151
|
end
|
149
152
|
|
153
|
+
# @!visibility private
|
154
|
+
def init_fuse_config(fuse_config, _fuse_version)
|
155
|
+
fuse_config.use_ino = use_ino
|
156
|
+
end
|
157
|
+
|
158
|
+
# Configure whether entries in this filesystem provide useful inode values in #gettattr and #readdir
|
159
|
+
#
|
160
|
+
# Defaults to true since default Dir, File, Link all use {VirtualNode} which uses
|
161
|
+
# Ruby object id as the inode value.
|
162
|
+
#
|
163
|
+
# Subclasses should override to false if some sub-filesystems will not provide inode values.
|
164
|
+
# @return [Boolean]
|
165
|
+
def use_ino
|
166
|
+
true
|
167
|
+
end
|
150
168
|
# @!endgroup
|
151
169
|
|
152
170
|
private
|
@@ -156,15 +174,16 @@ module FFI
|
|
156
174
|
end
|
157
175
|
|
158
176
|
def build_readdir(content, path)
|
159
|
-
@root.mkdir(path.to_s) { content }
|
177
|
+
@root.mkdir(path.to_s) { |_| content }
|
160
178
|
end
|
161
179
|
|
162
180
|
def build_getattr(content, path)
|
163
|
-
@root.create(path.to_s) { content }
|
181
|
+
@root.create(path.to_s) { |_| content }
|
164
182
|
end
|
165
183
|
|
166
184
|
def build_to_str(content, path)
|
167
|
-
@root.create(path.to_s)
|
185
|
+
vf = @root.create(path.to_s)
|
186
|
+
vf.write(content.to_str)
|
168
187
|
end
|
169
188
|
|
170
189
|
# Passes FUSE Callbacks on to the {#root} filesystem
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module Libfuse
|
5
|
+
module Filesystem
|
6
|
+
module Ruby
|
7
|
+
# Filesystem methods representing a symbolic link
|
8
|
+
# Satisfies the contract of {Adapter::Ruby}
|
9
|
+
module VirtualLink
|
10
|
+
attr_accessor :target
|
11
|
+
|
12
|
+
include VirtualNode
|
13
|
+
def initialize(accounting: nil)
|
14
|
+
@target = target
|
15
|
+
super(accounting: accounting)
|
16
|
+
end
|
17
|
+
|
18
|
+
def readlink(_path, size)
|
19
|
+
@target[0, size - 1] # buffer size needs null terminator
|
20
|
+
end
|
21
|
+
|
22
|
+
def symlink(from_path, path)
|
23
|
+
raise Errno::ENOENT unless root?(path)
|
24
|
+
|
25
|
+
@target = from_path
|
26
|
+
init_node(0o777)
|
27
|
+
end
|
28
|
+
|
29
|
+
def link(_from_path, path)
|
30
|
+
raise Errno::ENOENT unless root?(path)
|
31
|
+
|
32
|
+
# Cannot hard link a symbolic link
|
33
|
+
raise Errno::EPERM
|
34
|
+
end
|
35
|
+
|
36
|
+
def unlink(path)
|
37
|
+
raise Errno::ENOENT unless root?(path)
|
38
|
+
|
39
|
+
accounting&.adjust(0, -1)
|
40
|
+
end
|
41
|
+
|
42
|
+
def getattr(path, stat = nil, _ffi = nil)
|
43
|
+
# We don't exist until create or otherwise or virtual stat exists
|
44
|
+
raise Errno::ENOENT unless root?(path) && virtual_stat
|
45
|
+
|
46
|
+
stat&.symlink(size: @target.length + 1, **virtual_stat)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# A Filesystem that represents a single symbolic link at the root
|
53
|
+
class VirtualLink
|
54
|
+
prepend Adapter::Ruby::Prepend
|
55
|
+
include Fuse2Compat
|
56
|
+
include Ruby::VirtualLink
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -6,95 +6,112 @@ require_relative '../adapter/ruby'
|
|
6
6
|
module FFI
|
7
7
|
module Libfuse
|
8
8
|
module Filesystem
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
9
|
+
module Ruby
|
10
|
+
# Common FUSE Callbacks for a virtual inode representing a single filesystem object at '/'
|
11
|
+
#
|
12
|
+
# **Note** this module is used by both {VirtualFile} which is under {Adapter::Ruby::Prepend}
|
13
|
+
# and {VirtualDir} which passes on native {FuseOperations} calls
|
14
|
+
module VirtualNode
|
15
|
+
# @return [Hash<Symbol,Integer>] base file or directory stat information used for :getattr of this node
|
16
|
+
attr_reader :virtual_stat
|
17
|
+
|
18
|
+
# @return [Hash<String,String>] virtual extended attributes
|
19
|
+
attr_reader :virtual_xattr
|
20
|
+
|
21
|
+
# @return [Accounting|nil] file system statistcs accumulator
|
22
|
+
attr_reader :accounting
|
23
|
+
|
24
|
+
# @param [Accounting] accounting accumulator of filesystem statistics
|
25
|
+
def initialize(accounting: Accounting.new)
|
26
|
+
@accounting = accounting
|
27
|
+
|
28
|
+
@virtual_xattr = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!method path_method(callback, *args)
|
32
|
+
# @abstract
|
33
|
+
# called if this node cannot handle the callback (ie path is not root or an entry in this directory)
|
34
|
+
|
35
|
+
# @!group FUSE Callbacks
|
36
|
+
|
37
|
+
def utimens(path, *args)
|
38
|
+
return path_method(__method__, path, *args) unless root?(path)
|
39
|
+
|
40
|
+
atime, mtime, *_fuse3 = args
|
41
|
+
# if native fuse call atime will be Array<Stat::TimeSpec>
|
42
|
+
atime, mtime = Stat::TimeSpec.fill_times(atime[0, 2], 2).map(&:time) if atime.is_a?(Array)
|
43
|
+
virtual_stat[:atime] = atime if atime
|
44
|
+
virtual_stat[:mtime] = mtime if mtime
|
45
|
+
virtual_stat[:ctime] = mtime if mtime
|
46
|
+
end
|
47
|
+
|
48
|
+
def chmod(path, mode, *args)
|
49
|
+
return path_method(__method__, path, mode, *args) unless root?(path)
|
50
|
+
|
51
|
+
virtual_stat[:mode] = mode
|
52
|
+
virtual_stat[:ctime] = Time.now
|
53
|
+
end
|
54
|
+
|
55
|
+
def chown(path, uid, gid, *args)
|
56
|
+
return path_method(__method__, path, uid, gid, *args) unless root?(path)
|
57
|
+
|
58
|
+
virtual_stat[:uid] = uid
|
59
|
+
virtual_stat[:gid] = gid
|
60
|
+
virtual_stat[:ctime] = Time.now
|
61
|
+
end
|
62
|
+
|
63
|
+
def statfs(path, statfs_buf)
|
64
|
+
return path_method(__method__, path, statfs_buf) unless root?(path)
|
65
|
+
raise Errno::ENOTSUP unless accounting
|
66
|
+
|
67
|
+
accounting.to_statvfs(statfs_buf)
|
68
|
+
end
|
69
|
+
|
70
|
+
def getxattr(path, name, buf = nil, size = nil)
|
71
|
+
return path_method(__method__, path, name, buf, size) unless root?(path)
|
72
|
+
return virtual_xattr[name] unless buf
|
73
|
+
|
74
|
+
Adapter::Ruby.getxattr(buf, size) { virtual_xattr[name] }
|
75
|
+
end
|
76
|
+
|
77
|
+
def listxattr(path, buf = nil, size = nil)
|
78
|
+
return path_method(__method__, path) unless root?(path)
|
79
|
+
return virtual_xattr.keys unless buf
|
80
|
+
|
81
|
+
Adapter::Ruby.listxattr(buf, size) { virtual_xattr.keys }
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!endgroup
|
85
|
+
|
86
|
+
# Initialise the stat information for the node - should only be called once (eg from create or mkdir)
|
87
|
+
def init_node(mode, ctx: FuseContext.get, now: Time.now)
|
88
|
+
@virtual_stat =
|
89
|
+
{
|
90
|
+
mode: mode & ~ctx.umask, uid: ctx.uid, gid: ctx.gid,
|
91
|
+
ctime: now, mtime: now, atime: now,
|
92
|
+
ino: object_id
|
93
|
+
}
|
94
|
+
accounting&.adjust(0, +1)
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# @!visibility private
|
101
|
+
def path_method(_method, *_args)
|
102
|
+
raise Errno::ENOENT
|
103
|
+
end
|
104
|
+
|
105
|
+
def root?(path)
|
106
|
+
path.to_s == '/'
|
107
|
+
end
|
61
108
|
end
|
109
|
+
end
|
62
110
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
accounting.to_statvfs(statfs_buf)
|
68
|
-
end
|
69
|
-
|
70
|
-
def getxattr(path, name, buf = nil, size = nil)
|
71
|
-
return path_method(__method__, path, name, buf, size) unless root?(path)
|
72
|
-
return virtual_xattr[name] unless buf
|
73
|
-
|
74
|
-
Adapter::Ruby.getxattr(buf, size) { virtual_xattr[name] }
|
75
|
-
end
|
76
|
-
|
77
|
-
def listxattr(path, buf = nil, size = nil)
|
78
|
-
return path_method(__method__, path) unless root?(path)
|
79
|
-
return virtual_xattr.keys unless buf
|
80
|
-
|
81
|
-
Adapter::Ruby.listxattr(buf, size) { virtual_xattr.keys }
|
82
|
-
end
|
83
|
-
|
84
|
-
# @!endgroup
|
85
|
-
|
86
|
-
# Initialise the stat information for the node - should only be called once (eg from create or mkdir)
|
87
|
-
def init_node(mode, ctx: FuseContext.get, now: Time.now)
|
88
|
-
@virtual_stat = { mode: mode & ~ctx.umask, uid: ctx.uid, gid: ctx.gid, ctime: now, mtime: now, atime: now }
|
89
|
-
accounting&.adjust(0, +1)
|
90
|
-
self
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def root?(path)
|
96
|
-
path.to_s == '/'
|
97
|
-
end
|
111
|
+
# @abstract
|
112
|
+
# Base class Represents a virtual inode
|
113
|
+
class VirtualNode
|
114
|
+
include Ruby::VirtualNode
|
98
115
|
end
|
99
116
|
end
|
100
117
|
end
|
@@ -7,7 +7,7 @@ module FFI
|
|
7
7
|
# This module namespace contains classes and modules to assist with building and composing filesystems
|
8
8
|
#
|
9
9
|
# ### Virtual Filesystems
|
10
|
-
# Classes to help compose in-memory filesystems {VirtualFS}, {VirtualDir}, {VirtualFile}
|
10
|
+
# Classes to help compose in-memory filesystems {VirtualFS}, {VirtualDir}, {VirtualFile}, {VirtualLink}
|
11
11
|
#
|
12
12
|
# ### Mapped Filesystem
|
13
13
|
# Modules to map paths in the fuse filesystem to either real files or other filesystem objects
|
data/lib/ffi/libfuse/fuse2.rb
CHANGED
@@ -44,14 +44,15 @@ module FFI
|
|
44
44
|
def parse_cmdline(args, handler: nil)
|
45
45
|
# This also handles -h to print help information on stderr
|
46
46
|
# Parse mountpoint, -f , -s from args
|
47
|
-
# @return [Array<(String,Boolean,Boolean)
|
47
|
+
# @return [Array<(String,Boolean,Boolean)>]
|
48
48
|
# mountpoint, multi_thread, foreground options from args if available
|
49
49
|
# nil if no mountpoint, or options is requesting help or version information
|
50
50
|
mountpoint_ptr = FFI::MemoryPointer.new(:pointer, 1)
|
51
51
|
multi_thread_ptr = FFI::MemoryPointer.new(:int, 1)
|
52
52
|
foreground_ptr = FFI::MemoryPointer.new(:int, 1)
|
53
53
|
|
54
|
-
|
54
|
+
res = Libfuse.fuse_parse_cmdline2(args, mountpoint_ptr, multi_thread_ptr, foreground_ptr)
|
55
|
+
raise Error unless res.zero?
|
55
56
|
|
56
57
|
# noinspection RubyResolve
|
57
58
|
mp_data_ptr = mountpoint_ptr.get_pointer(0)
|
data/lib/ffi/libfuse/fuse3.rb
CHANGED
@@ -56,7 +56,7 @@ module FFI
|
|
56
56
|
class << self
|
57
57
|
def parse_cmdline(args, handler: nil)
|
58
58
|
cmdline_opts = FuseCmdlineOpts.new
|
59
|
-
|
59
|
+
raise Error unless Libfuse.fuse_parse_cmdline3(args, cmdline_opts).zero?
|
60
60
|
|
61
61
|
handler&.fuse_debug(cmdline_opts.debug) if handler.respond_to?(:fuse_debug)
|
62
62
|
|
@@ -121,7 +121,8 @@ module FFI
|
|
121
121
|
# - :error an error, alternatively raise {Error}
|
122
122
|
# - :keep retain the current argument for further processing
|
123
123
|
# - :handled,:discard remove the current argument from further processing
|
124
|
-
# @
|
124
|
+
# @raise Error if an error is raised during parsing
|
125
|
+
# @return [self]
|
125
126
|
def parse!(opts, data = nil, ignore: %i[non_option unmatched], &block)
|
126
127
|
ignore ||= []
|
127
128
|
|
@@ -140,7 +141,9 @@ module FFI
|
|
140
141
|
end
|
141
142
|
|
142
143
|
fop = fuse_opt_proc(symbols, bool_opts, param_opts, ignore, &block)
|
143
|
-
Libfuse.fuse_opt_parse(self, data, int_opts, fop).zero?
|
144
|
+
raise Error unless Libfuse.fuse_opt_parse(self, data, int_opts, fop).zero?
|
145
|
+
|
146
|
+
self
|
144
147
|
end
|
145
148
|
|
146
149
|
private
|