ffi-libfuse 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- 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 +2 -9
- 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 +6 -3
- data/lib/ffi/libfuse/fuse_buffer.rb +0 -257
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e105d84b1d0f73af20845ed1d39e51ae61f9ca4998fa9caf505b4e87ae08eaa9
|
4
|
+
data.tar.gz: 7f9013b530bc62e9fb4071899e13f191fdc720f662221da1cac0cd554a76bc5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72b0a464ab67be704cb14f3ce4b07f1f9a29d260ee50864dcf8c75cc24ba2eaf43aab6ae9f79fda9edb707cded39fde10e8504be7b8ca011b1a7d625969d62f6
|
7
|
+
data.tar.gz: b85626a26f149dc1852ae5928cef67eb5dd7fc4353acb6bafa4fb0061aec38dce6d6e6c8137b216bc540263ba28f5b5f627f3af8feecb9bab417bbfc64df45ab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.4.0](https://github.com/lwoggardner/ffi-libfuse/compare/v0.3.4...v0.4.0) (2024-01-21)
|
4
|
+
|
5
|
+
|
6
|
+
### ⚠ BREAKING CHANGES
|
7
|
+
|
8
|
+
* **filesystem:** Fuse callbacks :init and :destroy are no longer passed on to sub-filesystems.
|
9
|
+
* **adapters:** Adapter::Debug now includes Adapter::Safe.
|
10
|
+
* Option parsing errors via raise exception rather than return false/nil
|
11
|
+
|
12
|
+
### Features
|
13
|
+
|
14
|
+
* **adapters:** Adapter::Debug now includes Adapter::Safe. ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
15
|
+
* **filesystem:** Support :rename operation in virtual filesystems ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
16
|
+
* **filesystem:** Support symlinks and hardlinks in virtual filesystems (VirtualDir/MemoryFS) ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
17
|
+
* Option parsing errors via raise exception rather than return false/nil ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
18
|
+
|
19
|
+
|
20
|
+
### Bug Fixes
|
21
|
+
|
22
|
+
* **fuse2compat:** Enhanced Fuse2 compatibility in Fuse2Compat module ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
23
|
+
* symlinks and hard links ([a595304](https://github.com/lwoggardner/ffi-libfuse/commit/a59530427d7eb85961a724969eaa6ec099c5e4f6))
|
24
|
+
|
3
25
|
## [0.3.4](https://github.com/lwoggardner/ffi-libfuse/compare/v0.3.3...v0.3.4) (2023-01-08)
|
4
26
|
|
5
27
|
|
data/README.md
CHANGED
data/lib/ffi/accessors.rb
CHANGED
@@ -19,22 +19,29 @@ module FFI
|
|
19
19
|
|
20
20
|
#
|
21
21
|
# Define a struct attribute reader for members
|
22
|
-
# @param [Array<Symbol>]
|
22
|
+
# @param [Array<Symbol>]
|
23
|
+
# attrs the attribute names used as the reader method name
|
24
|
+
#
|
25
|
+
# a trailing '?' will be stripped from attribute names for primary reader method name, and cause an
|
26
|
+
# boolean alias method to be created.
|
23
27
|
# @param [Proc|String] format
|
24
|
-
# A Proc, or format string containing a single %s, to convert
|
28
|
+
# A Proc, or format string containing a single %s, to convert each attribute name to the corresponding
|
29
|
+
# struct member name
|
25
30
|
# @param [Boolean] simple
|
26
31
|
# Controls how writer methods are defined using block
|
27
32
|
# @param [Proc] block
|
28
|
-
# An optional block to the struct field
|
33
|
+
# An optional block to convert the struct field value into something more useful
|
29
34
|
#
|
30
35
|
# If simple is true then block takes the struct field value, otherwise method is defined directly from the block
|
31
|
-
# and should use __method__ to get the
|
32
|
-
# name
|
36
|
+
# and should use __method__ to get the attribute name. and self.class.ffi_attr_readers[__method__] to get the
|
37
|
+
# member name if these are not available from enclosed variables.
|
33
38
|
# @return [void]
|
34
39
|
def ffi_attr_reader(*attrs, format: '%s', simple: true, &block)
|
35
40
|
attrs.each do |attr|
|
41
|
+
bool, attr = attr[-1] == '?' ? [true, attr[..-2]] : [false, attr]
|
42
|
+
|
36
43
|
member = (format.respond_to?(:call) ? format.call(attr) : format % attr).to_sym
|
37
|
-
ffi_attr_readers[attr] = member
|
44
|
+
ffi_attr_readers[attr.to_sym] = member
|
38
45
|
if !block
|
39
46
|
define_method(attr) { self[member] }
|
40
47
|
elsif simple
|
@@ -42,11 +49,14 @@ module FFI
|
|
42
49
|
else
|
43
50
|
define_method(attr, &block)
|
44
51
|
end
|
52
|
+
|
53
|
+
alias_method "#{attr}?", attr if bool
|
45
54
|
end
|
46
55
|
end
|
47
56
|
|
48
57
|
# Define a struct attribute writer
|
49
58
|
# @param [Array<Symbol>] attrs the attribute names
|
59
|
+
# trailing '?' will be stripped from attribute names
|
50
60
|
# @param [String|Proc] format
|
51
61
|
# A format string containing a single %s to convert attr symbol to struct member
|
52
62
|
# @param [Boolean] simple
|
@@ -60,6 +70,8 @@ module FFI
|
|
60
70
|
# @return [void]
|
61
71
|
def ffi_attr_writer(*attrs, format: '%s', simple: true, &block)
|
62
72
|
attrs.each do |attr|
|
73
|
+
attr = attr[..-2] if attr[-1] == '?'
|
74
|
+
|
63
75
|
member = (format % attr).to_sym
|
64
76
|
ffi_attr_writers[attr.to_sym] = member
|
65
77
|
if !block
|
@@ -95,7 +107,9 @@ module FFI
|
|
95
107
|
# @param [Array<Symbol>] flags list of flags
|
96
108
|
# @return [void]
|
97
109
|
def ffi_bitflag_reader(attr, *flags)
|
98
|
-
flags.each
|
110
|
+
flags.each do |f|
|
111
|
+
ffi_attr_reader(:"#{f}?", simple: false) { self[attr].include?(f) }
|
112
|
+
end
|
99
113
|
end
|
100
114
|
|
101
115
|
# Define individual flag writers over a bitmask field
|
data/lib/ffi/boolean_int.rb
CHANGED
data/lib/ffi/devt.rb
CHANGED
@@ -15,17 +15,17 @@ module FFI
|
|
15
15
|
# @param [Integer] major
|
16
16
|
# @param [Integer] minor
|
17
17
|
# @return [Integer] combined major/minor to a single value to pass to mknod etc
|
18
|
-
attach_function :makedev, "#{prefix}makedev"
|
18
|
+
attach_function :makedev, :"#{prefix}makedev", %i[int int], :int
|
19
19
|
|
20
20
|
# @!method major(dev)
|
21
21
|
# @param [Integer] dev
|
22
22
|
# @return [Integer] the major component of dev
|
23
|
-
attach_function :major, "#{prefix}major"
|
23
|
+
attach_function :major, :"#{prefix}major", [:int], :int
|
24
24
|
|
25
25
|
# @!method minor(dev)
|
26
26
|
# @param [Integer] dev
|
27
27
|
# @return [Integer] the minor component of dev
|
28
|
-
attach_function :minor, "#{prefix}minor"
|
28
|
+
attach_function :minor, :"#{prefix}minor", [:int], :int
|
29
29
|
rescue FFI::NotFoundError
|
30
30
|
case Platform::NAME
|
31
31
|
when 'x86_64-darwin'
|
@@ -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,8 +37,8 @@ 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
44
|
super(*wrappers)
|
@@ -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
|
@@ -31,8 +31,8 @@ module FFI
|
|
31
31
|
super(path, mode, fuse_file_info)
|
32
32
|
end
|
33
33
|
|
34
|
-
def utimens(path,
|
35
|
-
super(path,
|
34
|
+
def utimens(path, times, fuse_file_info = nil)
|
35
|
+
super(path, times, fuse_file_info)
|
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(fuse_method)
|
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
|