ffi-libfuse 0.3.4 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|