ffi-libfuse 0.3.4 → 0.4.1
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 +29 -0
- data/README.md +1 -1
- data/lib/ffi/accessors.rb +419 -93
- data/lib/ffi/boolean_int.rb +1 -1
- data/lib/ffi/devt.rb +36 -10
- data/lib/ffi/flock.rb +31 -27
- data/lib/ffi/libfuse/adapter/context.rb +1 -1
- data/lib/ffi/libfuse/adapter/debug.rb +54 -16
- data/lib/ffi/libfuse/adapter/fuse2_compat.rb +43 -26
- data/lib/ffi/libfuse/adapter/fuse3_support.rb +7 -8
- data/lib/ffi/libfuse/adapter/interrupt.rb +1 -1
- data/lib/ffi/libfuse/adapter/pathname.rb +1 -1
- data/lib/ffi/libfuse/adapter/ruby.rb +211 -160
- data/lib/ffi/libfuse/adapter/safe.rb +70 -22
- 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 +294 -127
- 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 +6 -6
- data/lib/ffi/libfuse/fuse_args.rb +14 -21
- data/lib/ffi/libfuse/fuse_buf.rb +112 -0
- data/lib/ffi/libfuse/fuse_buf_vec.rb +228 -0
- data/lib/ffi/libfuse/fuse_cmdline_opts.rb +19 -16
- data/lib/ffi/libfuse/fuse_common.rb +10 -4
- data/lib/ffi/libfuse/fuse_config.rb +35 -23
- data/lib/ffi/libfuse/fuse_conn_info.rb +1 -1
- data/lib/ffi/libfuse/fuse_context.rb +2 -1
- data/lib/ffi/libfuse/fuse_loop_config.rb +68 -20
- data/lib/ffi/libfuse/fuse_operations.rb +86 -41
- data/lib/ffi/libfuse/gem_helper.rb +2 -9
- data/lib/ffi/libfuse/io.rb +56 -0
- data/lib/ffi/libfuse/main.rb +33 -26
- data/lib/ffi/libfuse/test_helper.rb +67 -61
- 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 +35 -12
- data/lib/ffi/stat_vfs.rb +1 -2
- data/lib/ffi/struct_array.rb +2 -1
- data/lib/ffi/struct_wrapper.rb +6 -4
- data/sample/hello_fs.rb +1 -1
- metadata +6 -3
- data/lib/ffi/libfuse/fuse_buffer.rb +0 -257
data/lib/ffi/devt.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'ffi'
|
4
|
-
|
5
4
|
module FFI
|
6
5
|
# Calculate major/minor device numbers for use with mknod etc..
|
7
6
|
# @see makedev(3)
|
@@ -15,22 +14,25 @@ module FFI
|
|
15
14
|
# @param [Integer] major
|
16
15
|
# @param [Integer] minor
|
17
16
|
# @return [Integer] combined major/minor to a single value to pass to mknod etc
|
18
|
-
attach_function :makedev, "#{prefix}makedev"
|
17
|
+
attach_function :makedev, :"#{prefix}makedev", %i[int int], :int
|
19
18
|
|
20
19
|
# @!method major(dev)
|
21
20
|
# @param [Integer] dev
|
22
21
|
# @return [Integer] the major component of dev
|
23
|
-
attach_function :major, "#{prefix}major"
|
22
|
+
attach_function :major, :"#{prefix}major", [:int], :int
|
24
23
|
|
25
24
|
# @!method minor(dev)
|
26
25
|
# @param [Integer] dev
|
27
26
|
# @return [Integer] the minor component of dev
|
28
|
-
attach_function :minor, "#{prefix}minor"
|
27
|
+
attach_function :minor, :"#{prefix}minor", [:int], :int
|
29
28
|
rescue FFI::NotFoundError
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
|
29
|
+
|
30
|
+
class << self
|
31
|
+
# rubocop:disable Naming/MethodParameterName
|
32
|
+
case RUBY_PLATFORM
|
33
|
+
when 'x86_64-darwin'
|
34
|
+
# From https://github.com/golang/go/issues/8106 these functions are not defined on Darwin.
|
35
|
+
|
34
36
|
# define major(x) ((int32_t)(((u_int32_t)(x) >> 24) & 0xff))
|
35
37
|
def major(dev)
|
36
38
|
(dev >> 24) & 0xff
|
@@ -45,9 +47,33 @@ module FFI
|
|
45
47
|
def makedev(major, minor)
|
46
48
|
(major << 24) | minor
|
47
49
|
end
|
50
|
+
|
51
|
+
when 'x86_64-linux-musl' # eg alpine linux
|
52
|
+
# #define major(x) \
|
53
|
+
# ((unsigned)( (((x)>>31>>1) & 0xfffff000) | (((x)>>8) & 0x00000fff) ))
|
54
|
+
def major(x)
|
55
|
+
((x >> 31 >> 1) & 0xfffff000) | ((x >> 8) & 0x00000fff)
|
56
|
+
end
|
57
|
+
|
58
|
+
# #define minor(x) \
|
59
|
+
# ((unsigned)( (((x)>>12) & 0xffffff00) | ((x) & 0x000000ff) ))
|
60
|
+
#
|
61
|
+
def minor(x)
|
62
|
+
((x >> 12) & 0xffffff00) | (x & 0x000000ff)
|
63
|
+
end
|
64
|
+
|
65
|
+
# #define makedev(x,y) ( \
|
66
|
+
# (((x)&0xfffff000ULL) << 32) | \
|
67
|
+
# (((x)&0x00000fffULL) << 8) | \
|
68
|
+
# (((y)&0xffffff00ULL) << 12) | \
|
69
|
+
# (((y)&0x000000ffULL)) )
|
70
|
+
def makedev(x, y)
|
71
|
+
((x & 0xfffff000) << 32) | ((x & 0x00000fff) << 8) | ((y & 0xffffff00) << 12) | (y & 0x000000ff)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise
|
48
75
|
end
|
49
|
-
|
50
|
-
raise
|
76
|
+
# rubocop:enable Naming/MethodParameterName
|
51
77
|
end
|
52
78
|
end
|
53
79
|
end
|
data/lib/ffi/flock.rb
CHANGED
@@ -18,32 +18,36 @@ module FFI
|
|
18
18
|
|
19
19
|
include(Accessors)
|
20
20
|
|
21
|
-
layout(
|
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
|
-
|
21
|
+
layout(
|
22
|
+
# @!attribute [r] type
|
23
|
+
# @return [Symbol] lock type, :rdlck, :wrlck, :unlck
|
24
|
+
l_type: Enums::LockType,
|
25
|
+
|
26
|
+
# @!attribute [r] whence
|
27
|
+
# @return [Symbol] specifies what the offset is relative to, one of :seek_set, :seek_cur or :seek_end
|
28
|
+
# corresponding to the whence argument to fseek(2) or lseek(2),
|
29
|
+
l_whence: Enums::SeekWhenceShort,
|
30
|
+
|
31
|
+
# @!attribute [r] start
|
32
|
+
# @return [Integer] the offset of the start of the region to which the lock applies, and is given in bytes
|
33
|
+
# relative to the point specified by #{whence} member.
|
34
|
+
l_start: :off_t,
|
35
|
+
|
36
|
+
# @!attribute [r] len
|
37
|
+
# @return [Integer] the length of the region to be locked.
|
38
|
+
#
|
39
|
+
# A value of 0 means the region extends to the end of the file.
|
40
|
+
l_len: :off_t,
|
41
|
+
|
42
|
+
# @!attribute [r] pid
|
43
|
+
# @return [Integer] the process ID (see Process Creation Concepts) of the process holding the lock.
|
44
|
+
# It is filled in by calling fcntl with the F_GETLK command, but is ignored when making a lock. If the
|
45
|
+
# conflicting lock is an open file description lock (see Open File Description Locks), then this field will be
|
46
|
+
# set to -1.
|
47
|
+
l_pid: :pid_t
|
48
|
+
)
|
49
|
+
|
50
|
+
# Strip leading 'l_' to make attribute names
|
51
|
+
ffi_attr_reader(**members.to_h { |m| [m[2..].to_sym, m] })
|
48
52
|
end
|
49
53
|
end
|
@@ -1,13 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'safe'
|
4
|
+
|
3
5
|
module FFI
|
4
6
|
module Libfuse
|
5
7
|
module Adapter
|
6
8
|
# Debug callbacks
|
7
9
|
#
|
8
10
|
# When included in a filesystem class, and if debugging is enabled via {Main#fuse_debug}, then installs a wrapper
|
9
|
-
# via #{FuseCallbacks#fuse_wrappers} to log callbacks
|
11
|
+
# via #{FuseCallbacks#fuse_wrappers} to log callbacks.
|
12
|
+
#
|
13
|
+
# Simple format options can be handled by #{debug_config}, or override the **Module Functions** on an including
|
14
|
+
# class for more programmatic control of output.
|
15
|
+
#
|
16
|
+
# @note {Debug} includes {Safe} as it expects to handle (and re-raise) exceptions.
|
10
17
|
module Debug
|
18
|
+
include Safe
|
19
|
+
|
20
|
+
# Default format
|
21
|
+
# @see debug_callback
|
11
22
|
DEFAULT_FORMAT = "%<p>s %<n>s %<t>s %<m>s(%<a>s)\n\t=> %<r>s"
|
12
23
|
|
13
24
|
# @return [Boolean] true if debug is enabled
|
@@ -26,11 +37,11 @@ module FFI
|
|
26
37
|
def fuse_wrappers(*wrappers)
|
27
38
|
conf = { prefix: self.class.name }.merge!(debug_config)
|
28
39
|
# validate config for bad formats, strftime etc
|
29
|
-
|
30
|
-
wrappers << proc { |fm, *args, &b|
|
40
|
+
debug_format(:test_debug, [], :result, **conf)
|
41
|
+
wrappers << proc { |fm, *args, &b| debug_callback(fm, *args, **conf, &b) } if debug?
|
31
42
|
return wrappers unless defined?(super)
|
32
43
|
|
33
|
-
super
|
44
|
+
super
|
34
45
|
end
|
35
46
|
|
36
47
|
# @!visibility private
|
@@ -41,10 +52,11 @@ module FFI
|
|
41
52
|
|
42
53
|
module_function
|
43
54
|
|
44
|
-
# Debug fuse method, args and result
|
55
|
+
# Debug fuse method, args and result of yielding args to the block
|
56
|
+
#
|
45
57
|
# @param [Symbol] fuse_method the callback name
|
46
58
|
# @param [Array] args callback arguments
|
47
|
-
# @param [Hash<Symbol,String>] options see {
|
59
|
+
# @param [Hash<Symbol,String>] options see {debug_format} for defaults
|
48
60
|
# @option options [String] prefix
|
49
61
|
# @option options [String] strftime a date time format
|
50
62
|
# @option options [String] format format string with fields
|
@@ -55,25 +67,49 @@ module FFI
|
|
55
67
|
# * %<a>: Comma separate list of arguments
|
56
68
|
# * %<r>: Result of the method call (or any error raised)
|
57
69
|
# * %<p>: The value of prefix option
|
70
|
+
# @raise [SystemCallError]
|
71
|
+
# expected Errors raised from callbacks are logged with their cause (if any)
|
72
|
+
# @raise [StandardError,ScriptError]
|
73
|
+
# unexpected Errors raised from callbacks are logged with their backtrace
|
58
74
|
def debug_callback(fuse_method, *args, **options)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
debug(fuse_method, args, "#{e.class.name}(errno=#{e.errno}): #{e.message}", **options)
|
63
|
-
raise
|
75
|
+
result = yield(*args)
|
76
|
+
debug(fuse_method, args, result, **options)
|
77
|
+
result
|
64
78
|
rescue StandardError, ScriptError => e
|
65
|
-
|
66
|
-
|
79
|
+
debug(fuse_method, args, error_message(e), **options)
|
80
|
+
debug_error(e)
|
67
81
|
raise
|
68
82
|
end
|
69
83
|
|
70
|
-
# @!
|
84
|
+
# @!group Module Functions
|
85
|
+
|
86
|
+
# Logs the callback
|
71
87
|
def debug(fuse_method, args, result, **options)
|
72
88
|
warn debug_format(fuse_method, args, result, **options)
|
73
|
-
result
|
74
89
|
end
|
75
90
|
|
76
|
-
#
|
91
|
+
# @param [Exception] err
|
92
|
+
# @return [String] the detailed error message for err
|
93
|
+
def error_message(err)
|
94
|
+
if err.is_a?(SystemCallError)
|
95
|
+
"#{err.class.name}(errno=#{err.errno}): #{err.message}"
|
96
|
+
else
|
97
|
+
"#{err.class.name}: #{err.message}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Log additional information for errors (cause/backtrace etc)
|
102
|
+
# @see debug_callback
|
103
|
+
def debug_error(err)
|
104
|
+
if err.is_a?(SystemCallError)
|
105
|
+
warn "Caused by #{error_message(err.cause)}" if err.cause
|
106
|
+
else
|
107
|
+
warn err.backtrace.join("\n\t")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [String] the formatted debug message
|
112
|
+
# @see debug_callback
|
77
113
|
def debug_format(fuse_method, args, result, prefix: 'DEBUG', strftime: '%FT%T%:z', format: DEFAULT_FORMAT)
|
78
114
|
format(format,
|
79
115
|
p: prefix,
|
@@ -83,6 +119,8 @@ module FFI
|
|
83
119
|
a: args.map(&:to_s).join(','),
|
84
120
|
r: result)
|
85
121
|
end
|
122
|
+
|
123
|
+
# @!endgroup
|
86
124
|
end
|
87
125
|
end
|
88
126
|
end
|
@@ -12,27 +12,27 @@ module FFI
|
|
12
12
|
if FUSE_MAJOR_VERSION == 2
|
13
13
|
# @!visibility private
|
14
14
|
def getattr(path, stat, fuse_file_info = nil)
|
15
|
-
super
|
15
|
+
super
|
16
16
|
end
|
17
17
|
|
18
18
|
def truncate(path, size, fuse_file_info = nil)
|
19
|
-
super
|
19
|
+
super
|
20
20
|
end
|
21
21
|
|
22
22
|
def init(fuse_conn_info, fuse_config = nil)
|
23
|
-
super
|
23
|
+
super
|
24
24
|
end
|
25
25
|
|
26
26
|
def chown(path, uid, gid, fuse_file_info = nil)
|
27
|
-
super
|
27
|
+
super
|
28
28
|
end
|
29
29
|
|
30
30
|
def chmod(path, mode, fuse_file_info = nil)
|
31
|
-
super
|
31
|
+
super
|
32
32
|
end
|
33
33
|
|
34
|
-
def utimens(path,
|
35
|
-
super
|
34
|
+
def utimens(path, times, fuse_file_info = nil)
|
35
|
+
super
|
36
36
|
end
|
37
37
|
|
38
38
|
def readdir(path, buffer, filler, offset, fuse_file_info, fuse_readdir_flag = 0)
|
@@ -40,49 +40,66 @@ module FFI
|
|
40
40
|
super(path, buffer, f3_fill, offset, fuse_file_info, fuse_readdir_flag)
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
43
|
+
def fuse_respond_to?(fuse_method)
|
44
|
+
# getdir is never supported here anyway
|
45
|
+
# fgetattr and ftruncate already fallback to the respective basic method
|
46
|
+
return false if %i[getdir fgetattr ftruncate].include?(fuse_method)
|
48
47
|
|
49
|
-
|
50
|
-
truncate(*args)
|
48
|
+
super
|
51
49
|
end
|
52
50
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
51
|
+
def fuse_options(args)
|
52
|
+
super if defined?(super)
|
53
|
+
return unless respond_to?(:init_fuse_config)
|
54
|
+
|
55
|
+
FUSE_CONFIG_ONLY_ATTRIBUTES.each do |opt|
|
56
|
+
args.add("-o#{opt}") if fuse_config.send(opt)
|
57
|
+
end
|
56
58
|
end
|
57
59
|
|
58
60
|
def fuse_flags
|
59
61
|
res = defined?(super) ? super : []
|
60
|
-
|
61
|
-
fuse_config = FuseConfig.new
|
62
|
-
init_fuse_config(fuse_config, :fuse2)
|
63
|
-
res << :nullpath_ok if fuse_config.nullpath_ok?
|
64
|
-
end
|
62
|
+
return res unless respond_to?(:init_fuse_config)
|
65
63
|
|
64
|
+
FUSE_CONFIG_FLAGS.each { |opt| res << opt if fuse_config.send(opt) }
|
66
65
|
res
|
67
66
|
end
|
68
67
|
|
68
|
+
private
|
69
|
+
|
70
|
+
def fuse_config
|
71
|
+
@fuse_config ||= begin
|
72
|
+
fuse_config = FuseConfig.new
|
73
|
+
init_fuse_config(fuse_config, :fuse2) if respond_to?(:init_fuse_config)
|
74
|
+
fuse_config
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
69
78
|
else
|
70
79
|
def init(*args)
|
71
|
-
init_fuse_config(args.detect { |a| a.is_a?(FuseConfig) }) if respond_to?(:init_fuse_config)
|
80
|
+
init_fuse_config(args.detect { |a| a.is_a?(FuseConfig) }, :fuse3) if respond_to?(:init_fuse_config)
|
72
81
|
super if defined?(super)
|
73
82
|
end
|
74
83
|
end
|
75
84
|
end
|
76
85
|
|
86
|
+
# Attributes in Fuse3 config that cannot be set by Fuse3 options. If set via {init_fuse_config} the
|
87
|
+
# equivalent options will be force set under Fuse 2
|
88
|
+
FUSE_CONFIG_ONLY_ATTRIBUTES = %i[hard_remove use_ino readdir_ino direct_io].freeze
|
89
|
+
|
90
|
+
# Attributes in Fuse3 config that were {FuseOperations#fuse_flags} in Fuse2. If set via {init_fuse_config} the
|
91
|
+
# equivalent flags will be added
|
92
|
+
FUSE_CONFIG_FLAGS = %i[nullpath_ok].freeze
|
93
|
+
|
77
94
|
# @!visibility private
|
78
95
|
def self.included(mod)
|
79
|
-
mod.prepend(Prepend)
|
96
|
+
mod.prepend(Prepend) if FUSE_MAJOR_VERSION < 3
|
80
97
|
end
|
81
98
|
|
82
99
|
# @!method init_fuse_config(fuse_config,compat)
|
83
100
|
# @abstract
|
84
|
-
# Define this method to configure the
|
85
|
-
# can be converted to appropriate flags
|
101
|
+
# Define this method to configure the {FuseConfig} object so that under Fuse2 the config options
|
102
|
+
# can be converted to appropriate flags or options
|
86
103
|
#
|
87
104
|
# @param [FuseConfig] fuse_config the fuse config object
|
88
105
|
# @param [Symbol] compat either :fuse2 or :fuse3
|
@@ -24,24 +24,24 @@ module FFI
|
|
24
24
|
fi = args.pop
|
25
25
|
return fgetattr(*args, fi) if fi && fuse_super_respond_to?(:fgetattr)
|
26
26
|
|
27
|
-
super
|
27
|
+
super
|
28
28
|
end
|
29
29
|
|
30
30
|
def truncate(*args)
|
31
31
|
fi = args.pop
|
32
32
|
return ftruncate(*args, fi) if fi && fuse_super_respond_to?(:ftruncate)
|
33
33
|
|
34
|
-
super
|
34
|
+
super
|
35
35
|
end
|
36
36
|
|
37
37
|
def chown(*args)
|
38
38
|
args.pop
|
39
|
-
super
|
39
|
+
super
|
40
40
|
end
|
41
41
|
|
42
42
|
def chmod(*args)
|
43
43
|
args.pop
|
44
|
-
super
|
44
|
+
super
|
45
45
|
end
|
46
46
|
|
47
47
|
# TODO: Fuse3 deprecated flag utime_omit_ok - which meant that UTIME_OMIT and UTIME_NOW are passed through
|
@@ -50,14 +50,14 @@ module FFI
|
|
50
50
|
# but there is no way to handle OMIT
|
51
51
|
def utimens(*args)
|
52
52
|
args.pop
|
53
|
-
super
|
53
|
+
super if defined?(super)
|
54
54
|
end
|
55
55
|
|
56
56
|
def init(*args)
|
57
57
|
args.pop
|
58
58
|
|
59
59
|
# TODO: populate FuseConfig with output from fuse_flags/FuseConnInfo where appropriate
|
60
|
-
super
|
60
|
+
super
|
61
61
|
end
|
62
62
|
|
63
63
|
def readdir(*args, &block)
|
@@ -71,7 +71,7 @@ module FFI
|
|
71
71
|
proc { |buf, name, stat, off| a.call(buf, name, stat, off, 0) }
|
72
72
|
end
|
73
73
|
|
74
|
-
super
|
74
|
+
super
|
75
75
|
end
|
76
76
|
|
77
77
|
def fuse_respond_to(fuse_callback)
|
@@ -81,7 +81,6 @@ module FFI
|
|
81
81
|
|
82
82
|
# @!visibility private
|
83
83
|
def self.included(mod)
|
84
|
-
# We prepend our shim module so caller doesn't have to call super
|
85
84
|
mod.prepend(Prepend) if FUSE_MAJOR_VERSION > 2
|
86
85
|
end
|
87
86
|
end
|