ffi-libfuse 0.1.0.rc20220550 → 0.3.3
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/.yardopts +1 -1
- data/CHANGELOG.md +60 -0
- data/lib/ffi/flock.rb +7 -5
- data/lib/ffi/libfuse/adapter/fuse3_support.rb +7 -3
- data/lib/ffi/libfuse/adapter/interrupt.rb +1 -1
- data/lib/ffi/libfuse/adapter/safe.rb +11 -10
- data/lib/ffi/libfuse/filesystem/utils.rb +2 -2
- data/lib/ffi/libfuse/filesystem/virtual_fs.rb +8 -0
- data/lib/ffi/libfuse/fuse2.rb +11 -3
- data/lib/ffi/libfuse/fuse3.rb +17 -7
- data/lib/ffi/libfuse/fuse_args.rb +4 -2
- data/lib/ffi/libfuse/fuse_common.rb +9 -4
- data/lib/ffi/libfuse/fuse_operations.rb +14 -2
- data/lib/ffi/libfuse/fuse_opt.rb +1 -1
- data/lib/ffi/libfuse/gem_version.rb +54 -0
- data/lib/ffi/libfuse/main.rb +21 -16
- data/lib/ffi/libfuse/test_helper.rb +145 -0
- data/lib/ffi/libfuse/version.rb +1 -1
- data/lib/ffi/libfuse.rb +2 -2
- data/lib/ffi/ruby_object.rb +3 -0
- metadata +9 -9
- data/CHANGES.md +0 -14
- data/lib/ffi/libfuse/test/operations.rb +0 -56
- data/lib/ffi/libfuse/test.rb +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 688ea85b8e5ee83a4baae3055c14026e65e929c2e22a8d9a2d0e983584e8bd7b
|
|
4
|
+
data.tar.gz: 552a053bea357d44ccf6fa2fcc12d311116d66320e113d7de7acb929a8ac539e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca1a1f2b2b9573c523583f0ee9d8fa05fecbbaf4ba36fbe73b4db5090626b8fc984091880677b4654caacda25d6e073b0a679b57539f6faecfd4c62f5bc45257
|
|
7
|
+
data.tar.gz: f8cb9a7d82ac0be86249066b9b69d2cfe03be3e6eb028881b16e715766b2a0f9dbba46ba2478310be75677e2b8c188f0b26235bbfa491dc42d9dff0ca904840e
|
data/.yardopts
CHANGED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.3](https://github.com/lwoggardner/ffi-libfuse/compare/v0.0.1...v0.3.3) (2023-01-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* Support downstream RFuse/RFuseFS
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* FFI::Libfuse::Filesystem - base filesystems ([5b19005](https://github.com/lwoggardner/ffi-libfuse/commit/5b19005c4b1ff2237b85c4854f481ea6e3625c62))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Code Refactoring
|
|
16
|
+
|
|
17
|
+
* Support downstream RFuse/RFuseFS ([e6b3fb5](https://github.com/lwoggardner/ffi-libfuse/commit/e6b3fb552b8881dbf28f014617b7412f2542aaa3))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Miscellaneous Chores
|
|
21
|
+
|
|
22
|
+
* **github:** release 0.3.3 ([b54a56f](https://github.com/lwoggardner/ffi-libfuse/commit/b54a56f3f93f15c7684aa2cb2c2dd38c9d033e7f))
|
|
23
|
+
|
|
24
|
+
## [0.3.2](https://github.com/lwoggardner/ffi-libfuse/compare/v0.3.0...v0.3.2) (2023-01-07)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Miscellaneous Chores
|
|
28
|
+
|
|
29
|
+
* fix release-please action ([fd55030](https://github.com/lwoggardner/ffi-libfuse/commit/fd550301248ebd9616da457ef8c2d88a7e55f819))
|
|
30
|
+
|
|
31
|
+
## [0.3.0](https://github.com/lwoggardner/ffi-libfuse/compare/v0.2.1...v0.3.0) (2023-01-07)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Miscellaneous Chores
|
|
35
|
+
|
|
36
|
+
* fix release-please action ([57d43e9](https://github.com/lwoggardner/ffi-libfuse/commit/57d43e9cac552b1b36469092a6278058893cadc4))
|
|
37
|
+
|
|
38
|
+
## [0.2.1](https://github.com/lwoggardner/ffi-libfuse/compare/v0.1.0...v0.2.1) (2023-01-07)
|
|
39
|
+
|
|
40
|
+
### Miscellaneous Chores
|
|
41
|
+
|
|
42
|
+
* release 0.2.1 ([bb0ef37](https://github.com/lwoggardner/ffi-libfuse/commit/bb0ef37c05a41c6b51a14e5cae292b2d7b75ef1c))
|
|
43
|
+
|
|
44
|
+
## [0.1.0](https://github.com/lwoggardner/ffi-libfuse/compare/v0.0.1...v0.1.0) (2023-01-07)
|
|
45
|
+
|
|
46
|
+
### ⚠ BREAKING CHANGES
|
|
47
|
+
|
|
48
|
+
* Support downstream RFuse/RFuseFS
|
|
49
|
+
* Changed option parsing.
|
|
50
|
+
|
|
51
|
+
{FFI::Libfuse::Main#fuse_options} takes a FuseArgs parameter and fuse_opt_proc is not used
|
|
52
|
+
|
|
53
|
+
### Features
|
|
54
|
+
|
|
55
|
+
* FFI::Libfuse::Filesystem - base filesystems ([5b19005](https://github.com/lwoggardner/ffi-libfuse/commit/5b19005c4b1ff2237b85c4854f481ea6e3625c62))
|
|
56
|
+
|
|
57
|
+
### Code Refactoring
|
|
58
|
+
|
|
59
|
+
* Support downstream RFuse/RFuseFS ([e6b3fb5](https://github.com/lwoggardner/ffi-libfuse/commit/e6b3fb552b8881dbf28f014617b7412f2542aaa3))
|
|
60
|
+
* Test on OSX with macFuse
|
data/lib/ffi/flock.rb
CHANGED
|
@@ -12,18 +12,20 @@ module FFI
|
|
|
12
12
|
SeekWhenceShort = enum :short, seek_whence
|
|
13
13
|
SeekWhence = enum :int, seek_whence
|
|
14
14
|
|
|
15
|
-
LockType = enum :short, %i[
|
|
16
|
-
LockCmd = enum :int, [:
|
|
15
|
+
LockType = enum :short, %i[rdlck wrlck unlck]
|
|
16
|
+
LockCmd = enum :int, [:getlk, 5, :setlk, 6, :setlkw, 7]
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
include(Accessors)
|
|
20
20
|
|
|
21
|
-
layout(
|
|
21
|
+
layout(l_type: Enums::LockType, l_whence: Enums::SeekWhenceShort, l_start: :off_t, l_len: :off_t, l_pid: :pid_t)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
l_members = members.grep(/^l_/).map { |m| m[2..].to_sym }
|
|
24
|
+
|
|
25
|
+
ffi_attr_reader(*l_members, format: 'l_%s')
|
|
24
26
|
|
|
25
27
|
# @!attribute [r] type
|
|
26
|
-
# @return [Symbol] lock type, :
|
|
28
|
+
# @return [Symbol] lock type, :rdlck, :wrlck, :unlck
|
|
27
29
|
|
|
28
30
|
# @!attribute [r] whence
|
|
29
31
|
# @return [Symbol] specifies what the offset is relative to, one of :seek_set, :seek_cur or :seek_end
|
|
@@ -22,14 +22,14 @@ module FFI
|
|
|
22
22
|
|
|
23
23
|
def getattr(*args)
|
|
24
24
|
fi = args.pop
|
|
25
|
-
return fgetattr(*args, fi) if fi &&
|
|
25
|
+
return fgetattr(*args, fi) if fi && fuse_super_respond_to?(:fgetattr)
|
|
26
26
|
|
|
27
27
|
super(*args)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def truncate(*args)
|
|
31
31
|
fi = args.pop
|
|
32
|
-
return ftruncate(*args, fi) if fi &&
|
|
32
|
+
return ftruncate(*args, fi) if fi && fuse_super_respond_to?(:ftruncate)
|
|
33
33
|
|
|
34
34
|
super(*args)
|
|
35
35
|
end
|
|
@@ -50,7 +50,7 @@ module FFI
|
|
|
50
50
|
# but there is no way to handle OMIT
|
|
51
51
|
def utimens(*args)
|
|
52
52
|
args.pop
|
|
53
|
-
super(*args)
|
|
53
|
+
super(*args) if defined?(super)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def init(*args)
|
|
@@ -73,6 +73,10 @@ module FFI
|
|
|
73
73
|
|
|
74
74
|
super(*args, &block)
|
|
75
75
|
end
|
|
76
|
+
|
|
77
|
+
def fuse_respond_to(fuse_callback)
|
|
78
|
+
super || (%i[truncate getattr].include?(fuse_callback) && fuse_super_respond_to?("f#{fuse_callback}"))
|
|
79
|
+
end
|
|
76
80
|
end
|
|
77
81
|
|
|
78
82
|
# @!visibility private
|
|
@@ -10,7 +10,7 @@ module FFI
|
|
|
10
10
|
# @!visibility private
|
|
11
11
|
def fuse_wrappers(*wrappers)
|
|
12
12
|
wrappers << {
|
|
13
|
-
wrapper: proc { |fm, *args, **_, &b| Safe.safe_callback(fm, *args, &b) },
|
|
13
|
+
wrapper: proc { |fm, *args, **_, &b| Safe.safe_callback(fm, *args, default_errno: default_errno, &b) },
|
|
14
14
|
excludes: %i[init destroy]
|
|
15
15
|
}
|
|
16
16
|
return wrappers unless defined?(super)
|
|
@@ -18,8 +18,10 @@ module FFI
|
|
|
18
18
|
super(*wrappers)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
|
|
21
|
+
# @return [Integer] the default errno. ENOTRECOVERABLE unless overridden
|
|
22
|
+
def default_errno
|
|
23
|
+
defined?(super) ? super : Errno::ENOTRECOVERABLE::Errno
|
|
24
|
+
end
|
|
23
25
|
|
|
24
26
|
module_function
|
|
25
27
|
|
|
@@ -27,30 +29,29 @@ module FFI
|
|
|
27
29
|
#
|
|
28
30
|
# @yieldreturn [SystemCallError] expected callback errors rescued to return equivalent -ve errno value
|
|
29
31
|
# @yieldreturn [StandardError,ScriptError] unexpected callback errors are rescued
|
|
30
|
-
# to return -
|
|
32
|
+
# to return -ve {default_errno} after emitting backtrace to #warn
|
|
31
33
|
#
|
|
32
34
|
# @yieldreturn [Integer]
|
|
33
35
|
#
|
|
34
36
|
# * -ve values returned directly
|
|
35
|
-
# * +ve values returned directly for fuse_methods in {MEANINGFUL_RETURN} list
|
|
37
|
+
# * +ve values returned directly for fuse_methods in {FuseOperations.MEANINGFUL_RETURN} list
|
|
36
38
|
# * otherwise returns 0
|
|
37
39
|
#
|
|
38
40
|
# @yieldreturn [Object] always returns 0 if no exception is raised
|
|
39
41
|
#
|
|
40
|
-
def safe_callback(fuse_method, *args)
|
|
42
|
+
def safe_callback(fuse_method, *args, default_errno: Errno::ENOTRECOVERABLE::Errno)
|
|
41
43
|
result = yield(*args)
|
|
42
44
|
|
|
43
|
-
return
|
|
44
|
-
return 0 unless result.negative? || MEANINGFUL_RETURN.include?(fuse_method)
|
|
45
|
+
return result.to_i if FuseOperations.meaningful_return?(fuse_method)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
0
|
|
47
48
|
rescue SystemCallError => e
|
|
48
49
|
-e.errno
|
|
49
50
|
rescue StandardError, ScriptError => e
|
|
50
51
|
# rubocop:disable Layout/LineLength
|
|
51
52
|
warn ["FFI::Libfuse error in #{fuse_method}", *e.backtrace.reverse, "#{e.class.name}:#{e.message}"].join("\n\t")
|
|
52
53
|
# rubocop:enable Layout/LineLength
|
|
53
|
-
-
|
|
54
|
+
-default_errno.abs
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
end
|
|
@@ -19,7 +19,7 @@ module FFI
|
|
|
19
19
|
# @param [Integer] mode permissions for any dirs that need to be created
|
|
20
20
|
# @yieldparam [String] the path component being created
|
|
21
21
|
# @yieldreturn [FuseOperations] optionally a filesystem to mount at path, if the path did not previously exist
|
|
22
|
-
def mkdir_p(path, mode = (
|
|
22
|
+
def mkdir_p(path, mode = (~FuseContext.get.umask & 0o0777), &mount_fs)
|
|
23
23
|
return if root?(path) # nothing to make
|
|
24
24
|
|
|
25
25
|
path.to_s.split('/')[1..].inject('') do |base_path, sub_dir|
|
|
@@ -71,7 +71,7 @@ module FFI
|
|
|
71
71
|
# @return [Boolean] File exists at path and has zero size
|
|
72
72
|
def empty_file?(path)
|
|
73
73
|
s = stat(path)
|
|
74
|
-
(s&.file? && s.size.zero?) || false
|
|
74
|
+
(s&.file? && s.size.zero?) || false # rubocop:disable Style/ZeroLengthPredicate
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# Check if a directory is empty
|
|
@@ -182,6 +182,14 @@ module FFI
|
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
attr_reader :no_buf
|
|
185
|
+
|
|
186
|
+
# This class does not implement any fuse methods, ensure they are passed to method missing.
|
|
187
|
+
# eg Kernel.open
|
|
188
|
+
FFI::Libfuse::FuseOperations.fuse_callbacks.each do |c|
|
|
189
|
+
undef_method(c)
|
|
190
|
+
rescue StandardError
|
|
191
|
+
nil
|
|
192
|
+
end
|
|
185
193
|
end
|
|
186
194
|
end
|
|
187
195
|
end
|
data/lib/ffi/libfuse/fuse2.rb
CHANGED
|
@@ -115,9 +115,7 @@ module FFI
|
|
|
115
115
|
@fuse = nil if @fuse&.null?
|
|
116
116
|
end
|
|
117
117
|
ensure
|
|
118
|
-
|
|
119
|
-
# as it's weakref will have been GC'd
|
|
120
|
-
ObjectSpace.define_finalizer(self, self.class.finalize_fuse(@fuse, @mountpoint, @ch))
|
|
118
|
+
define_finalizer
|
|
121
119
|
end
|
|
122
120
|
|
|
123
121
|
# [IO] /dev/fuse file descriptor for use with IO.select
|
|
@@ -150,6 +148,16 @@ module FFI
|
|
|
150
148
|
c = @ch
|
|
151
149
|
@ch = nil
|
|
152
150
|
Libfuse.fuse_unmount2(mountpoint, c)
|
|
151
|
+
ensure
|
|
152
|
+
# Can't unmount twice
|
|
153
|
+
define_finalizer
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def define_finalizer
|
|
157
|
+
# if we unmount/destroy in the finalizer then the private_data object cannot be used in destory
|
|
158
|
+
# as it's weakref will have been GC'd
|
|
159
|
+
ObjectSpace.undefine_finalizer(self)
|
|
160
|
+
ObjectSpace.define_finalizer(self, self.class.finalize_fuse(@fuse, @mountpoint, @ch))
|
|
153
161
|
end
|
|
154
162
|
end
|
|
155
163
|
|
data/lib/ffi/libfuse/fuse3.rb
CHANGED
|
@@ -87,10 +87,10 @@ module FFI
|
|
|
87
87
|
$stdout.puts "\n#{handler.fuse_help}" if handler.respond_to?(:fuse_help)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def finalize_fuse(fuse)
|
|
90
|
+
def finalize_fuse(fuse, mounted)
|
|
91
91
|
proc do
|
|
92
92
|
if fuse
|
|
93
|
-
Libfuse.fuse_unmount3(fuse)
|
|
93
|
+
Libfuse.fuse_unmount3(fuse) if mounted
|
|
94
94
|
Libfuse.fuse_destroy(fuse)
|
|
95
95
|
end
|
|
96
96
|
end
|
|
@@ -101,7 +101,7 @@ module FFI
|
|
|
101
101
|
|
|
102
102
|
# Have we requested an unmount (note not actually checking if OS sees the fs as mounted)
|
|
103
103
|
def mounted?
|
|
104
|
-
session && !fuse_exited?
|
|
104
|
+
session && !fuse_exited? && @mounted
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def initialize(mountpoint, args, operations, private_data)
|
|
@@ -119,9 +119,7 @@ module FFI
|
|
|
119
119
|
|
|
120
120
|
@mounted = @fuse && Libfuse.fuse_mount3(@fuse, @mountpoint).zero?
|
|
121
121
|
ensure
|
|
122
|
-
|
|
123
|
-
# as it's weakref will have been GC'd
|
|
124
|
-
ObjectSpace.define_finalizer(self, self.class.finalize_fuse(@fuse))
|
|
122
|
+
define_finalizer
|
|
125
123
|
end
|
|
126
124
|
|
|
127
125
|
def fuse_exited?
|
|
@@ -152,7 +150,19 @@ module FFI
|
|
|
152
150
|
end
|
|
153
151
|
|
|
154
152
|
def unmount
|
|
155
|
-
|
|
153
|
+
return unless @mounted && @fuse && !@fuse.null?
|
|
154
|
+
|
|
155
|
+
Libfuse.fuse_unmount3(@fuse)
|
|
156
|
+
@mounted = false
|
|
157
|
+
ensure
|
|
158
|
+
define_finalizer
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def define_finalizer
|
|
162
|
+
# if we unmount/destroy in the finalizer then the private_data object cannot be used in destroy
|
|
163
|
+
# as it's weakref will have been GC'd
|
|
164
|
+
ObjectSpace.undefine_finalizer(self)
|
|
165
|
+
ObjectSpace.define_finalizer(self, self.class.finalize_fuse(@fuse, @mounted))
|
|
156
166
|
end
|
|
157
167
|
end
|
|
158
168
|
|
|
@@ -14,11 +14,13 @@ module FFI
|
|
|
14
14
|
# Create a fuse_args struct from command line options
|
|
15
15
|
# @param [Array<String>] argv command line args
|
|
16
16
|
#
|
|
17
|
-
# first arg is expected to be program name
|
|
17
|
+
# first arg is expected to be program name and is ignored by fuse_opt_parse
|
|
18
|
+
# it is handled specially only in fuse_parse_cmdline (ie no subtype is given)
|
|
18
19
|
# @return [FuseArgs]
|
|
19
20
|
# @example
|
|
20
21
|
# FFI::Libfuse::FuseArgs.create($0,*ARGV)
|
|
21
22
|
def self.create(*argv)
|
|
23
|
+
argv.unshift('ffi-libfuse') if argv.empty? || argv[0].start_with?('-')
|
|
22
24
|
new.fill(*argv)
|
|
23
25
|
end
|
|
24
26
|
|
|
@@ -162,7 +164,7 @@ module FFI
|
|
|
162
164
|
[opt, arg[opt.rstrip.length..].lstrip]
|
|
163
165
|
else
|
|
164
166
|
warn "FuseOptProc error - Cannot match option for #{arg}"
|
|
165
|
-
next
|
|
167
|
+
next FUSE_OPT_PROC_RETURN.fetch(:error)
|
|
166
168
|
end
|
|
167
169
|
|
|
168
170
|
safe_opt_proc(key: key, value: value, match: match, data: data, out: out, &block)
|
|
@@ -100,7 +100,7 @@ module FFI
|
|
|
100
100
|
# @param [Boolean] foreground
|
|
101
101
|
# @param [Boolean] single_thread
|
|
102
102
|
def run_native(foreground: true, single_thread: true, **options)
|
|
103
|
-
raise 'Cannot run
|
|
103
|
+
raise 'Cannot run daemonized native multi-thread fuse_loop' if !single_thread && !foreground
|
|
104
104
|
|
|
105
105
|
clear_default_traps
|
|
106
106
|
(se = session) && Libfuse.fuse_set_signal_handlers(se)
|
|
@@ -165,7 +165,7 @@ module FFI
|
|
|
165
165
|
# @api private
|
|
166
166
|
# Ruby implementation of single threaded fuse loop
|
|
167
167
|
def fuse_loop(**_options)
|
|
168
|
-
|
|
168
|
+
safe_fuse_process until fuse_exited?
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
# @api private
|
|
@@ -179,11 +179,17 @@ module FFI
|
|
|
179
179
|
ThreadPool.new(name: 'FuseThread', max_idle: max_idle_threads.to_i, max_active: max_threads&.to_i) do
|
|
180
180
|
raise StopIteration if fuse_exited?
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
safe_fuse_process
|
|
183
183
|
end.join
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
# @!visibility private
|
|
187
|
+
|
|
188
|
+
def safe_fuse_process
|
|
189
|
+
# sometimes we get null on unmount, and exit needs a chance to finish to avoid hangs
|
|
190
|
+
fuse_process || (sleep(0.1) && false)
|
|
191
|
+
end
|
|
192
|
+
|
|
187
193
|
def teardown
|
|
188
194
|
return unless @fuse
|
|
189
195
|
|
|
@@ -209,7 +215,6 @@ module FFI
|
|
|
209
215
|
sleep 0.2 if mac_fuse?
|
|
210
216
|
|
|
211
217
|
Libfuse.fuse_exit(@fuse)
|
|
212
|
-
|
|
213
218
|
true
|
|
214
219
|
end
|
|
215
220
|
end
|
|
@@ -33,7 +33,10 @@ module FFI
|
|
|
33
33
|
bitmask :lock_op, [:lock_sh, 0, :lock_ex, 2, :lock_nb, 4, :lock_un, 8]
|
|
34
34
|
bitmask :falloc_mode, %i[keep_size punch_hole no_hide_stale collapse_range zero_range insert_range unshare_range]
|
|
35
35
|
bitmask :flags_mask, %i[nullpath_ok nopath utime_omit_ok] if FUSE_MAJOR_VERSION < 3
|
|
36
|
-
|
|
36
|
+
|
|
37
|
+
# @!visibility private
|
|
38
|
+
XAttr = enum :xattr, [:xattr_create, 1, :xattr_replace]
|
|
39
|
+
|
|
37
40
|
callback :fill_dir_t, fill_dir_t_args, :int
|
|
38
41
|
|
|
39
42
|
# The file system operations as specified in libfuse.
|
|
@@ -47,6 +50,14 @@ module FFI
|
|
|
47
50
|
class FuseOperations < FFI::Struct
|
|
48
51
|
include FuseCallbacks
|
|
49
52
|
|
|
53
|
+
# Callbacks that are expected to return meaningful positive integers
|
|
54
|
+
MEANINGFUL_RETURN = %i[read write write_buf lseek copy_file_range getxattr listxattr].freeze
|
|
55
|
+
|
|
56
|
+
# @return [Boolean] true if fuse_callback expects a meaningful integer return
|
|
57
|
+
def self.meaningful_return?(fuse_callback)
|
|
58
|
+
MEANINGFUL_RETURN.include?(fuse_callback)
|
|
59
|
+
end
|
|
60
|
+
|
|
50
61
|
# Container to dynamically build up the operations layout which is dependent on the loaded libfuse version
|
|
51
62
|
op = {}
|
|
52
63
|
|
|
@@ -213,6 +224,7 @@ module FFI
|
|
|
213
224
|
op[:truncate] = [:off_t]
|
|
214
225
|
op[:truncate] << FuseFileInfo.by_ref if FUSE_MAJOR_VERSION >= 3
|
|
215
226
|
|
|
227
|
+
# Not directly implemented see utimens
|
|
216
228
|
# int (*utime) (const char *, struct utimbuf *);
|
|
217
229
|
op[:utime] = [:pointer] if FUSE_MAJOR_VERSION < 3
|
|
218
230
|
|
|
@@ -568,7 +580,7 @@ module FFI
|
|
|
568
580
|
# @param [String] path
|
|
569
581
|
# @param [FuseFileInfo] fuse_file_info
|
|
570
582
|
# For checking lock ownership, the 'fuse_file_info->owner' argument must be used.
|
|
571
|
-
# @param [Symbol] cmd either :
|
|
583
|
+
# @param [Symbol] cmd either :getlck, :setlck or :setlkw.
|
|
572
584
|
# @param [Flock] flock
|
|
573
585
|
# For the meaning of fields in 'struct flock' see the man page for fcntl(2). The whence field will always
|
|
574
586
|
# be set to :seek_set.
|
data/lib/ffi/libfuse/fuse_opt.rb
CHANGED
|
@@ -19,7 +19,7 @@ module FFI
|
|
|
19
19
|
def fill(template, value)
|
|
20
20
|
str_ptr = FFI::MemoryPointer.from_string(template)
|
|
21
21
|
self[:template] = str_ptr
|
|
22
|
-
self[:offset] = (2**(
|
|
22
|
+
self[:offset] = (2**(FFI::Type::INT.size * 8)) - 1 # -(1U) in a LONG!!
|
|
23
23
|
self[:value] = value.to_i
|
|
24
24
|
self
|
|
25
25
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'version'
|
|
4
|
+
|
|
5
|
+
module FFI
|
|
6
|
+
# Ruby FFI Binding for [libfuse](https://github.com/libfuse/libfuse)
|
|
7
|
+
module Libfuse
|
|
8
|
+
# @!visibility private
|
|
9
|
+
|
|
10
|
+
SEMVER_TAG_REGEX = /^v\d+\.\d+\.\d+/.freeze
|
|
11
|
+
|
|
12
|
+
# branches the format is refs/heads/<branch_name>,
|
|
13
|
+
# tags it is refs/tags/<tag_name>.
|
|
14
|
+
# for pull requests it is refs/pull/<pr_number>/merge,
|
|
15
|
+
GIT_REF_TYPES = { 'heads' => :branch, 'tags' => :tag, 'pull' => :pull }.freeze
|
|
16
|
+
|
|
17
|
+
def self.git_ref(env: ENV)
|
|
18
|
+
ref = env.fetch('GIT_REF') do
|
|
19
|
+
# get branch ref, or detached head ref to tag
|
|
20
|
+
`git symbolic-ref HEAD 2>/dev/null || git name-rev HEAD | awk '{ gsub(/[\\^~@].*$/,"",$2); printf("refs/%s\\n",$2)}'`.strip # rubocop:disable Layout/LineLength
|
|
21
|
+
rescue StandardError
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return [ref, nil] unless ref&.start_with?('refs/')
|
|
26
|
+
|
|
27
|
+
_refs, ref_type, ref_name = ref.split('/', 3)
|
|
28
|
+
[ref_name, GIT_REF_TYPES[ref_type]]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.gem_version(main_branch: 'main', version: VERSION, env: ENV)
|
|
32
|
+
ref_name, ref_type = git_ref(env: env)
|
|
33
|
+
|
|
34
|
+
version =
|
|
35
|
+
case ref_type
|
|
36
|
+
when :branch
|
|
37
|
+
ref_name == main_branch ? [version] : [version, ref_name]
|
|
38
|
+
when :tag
|
|
39
|
+
SEMVER_TAG_REGEX.match?(ref_name) ? [ref_name[1..]] : [version, ref_name]
|
|
40
|
+
when :pull
|
|
41
|
+
pr_number, merge, _rest = ref_name.split('/')
|
|
42
|
+
# GITHUB_BASE_REF The name of the base ref or target branch of the pull request in a workflow run
|
|
43
|
+
base_ref = env.fetch('GIT_BASE_REF', 'undefined')
|
|
44
|
+
[version, base_ref, "#{merge}#{pr_number}"]
|
|
45
|
+
else
|
|
46
|
+
[version, 'pre', ref_name]
|
|
47
|
+
end.select { |p| p && !p.empty? }.join('.').tr('//_-', '')
|
|
48
|
+
|
|
49
|
+
[version, ref_name, ref_type]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
GEM_VERSION, GIT_REF_NAME, GIT_REF_TYPE = gem_version
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/ffi/libfuse/main.rb
CHANGED
|
@@ -9,6 +9,19 @@ module FFI
|
|
|
9
9
|
# Controls the main run loop for a FUSE filesystem
|
|
10
10
|
module Main
|
|
11
11
|
class << self
|
|
12
|
+
# Builds default argument list for #{fuse_main} regardless of being called directly or from mount.fuse3
|
|
13
|
+
#
|
|
14
|
+
# @param [Array<String>] extra_args additional arguments to add to $0 and *ARGV
|
|
15
|
+
# @return [Array<String>]
|
|
16
|
+
# @see https://github.com/libfuse/libfuse/issues/621
|
|
17
|
+
def default_args(*extra_args)
|
|
18
|
+
args = ARGV.dup
|
|
19
|
+
|
|
20
|
+
# If called from mount.fuse3 we already have a 'source' argument which should go at args[0]
|
|
21
|
+
args.unshift($0) unless args.size >= 2 && args[0..1].all? { |a| !a.start_with?('-') }
|
|
22
|
+
args.concat(extra_args)
|
|
23
|
+
end
|
|
24
|
+
|
|
12
25
|
# Main function of FUSE
|
|
13
26
|
#
|
|
14
27
|
# This function:
|
|
@@ -31,7 +44,7 @@ module FFI
|
|
|
31
44
|
# any data to be made available to the {FuseOperations#init} callback
|
|
32
45
|
#
|
|
33
46
|
# @return [Integer] suitable for process exit code
|
|
34
|
-
def fuse_main(*argv, operations:, args: argv.any? ? argv :
|
|
47
|
+
def fuse_main(*argv, operations:, args: argv.any? ? argv : default_args, private_data: nil)
|
|
35
48
|
run_args = fuse_parse_cmdline(args: args, handler: operations)
|
|
36
49
|
return 2 unless run_args
|
|
37
50
|
|
|
@@ -63,7 +76,7 @@ module FFI
|
|
|
63
76
|
# - parses standard fuse mount options
|
|
64
77
|
#
|
|
65
78
|
# @param [Array<String>] argv mount.fuse arguments
|
|
66
|
-
# expects progname,
|
|
79
|
+
# expects progname, mountpoint, options....
|
|
67
80
|
# @param [FuseArgs] args
|
|
68
81
|
# alternatively constructed args
|
|
69
82
|
# @param [Object] handler
|
|
@@ -75,7 +88,7 @@ module FFI
|
|
|
75
88
|
# * show_version [Boolean]: -v or --version
|
|
76
89
|
# * debug [Boolean]: -d
|
|
77
90
|
# * others are options to pass to {FuseCommon#run}
|
|
78
|
-
def fuse_parse_cmdline(*argv, args: argv, handler: nil)
|
|
91
|
+
def fuse_parse_cmdline(*argv, args: argv.any? ? argv : default_args, handler: nil)
|
|
79
92
|
args = fuse_init_args(args)
|
|
80
93
|
|
|
81
94
|
# Parse args and print cmdline help
|
|
@@ -94,16 +107,15 @@ module FFI
|
|
|
94
107
|
|
|
95
108
|
# @return [FuseCommon|nil] the mounted filesystem or nil if not mounted
|
|
96
109
|
def fuse_create(mountpoint, *argv, operations:, args: nil, private_data: nil)
|
|
97
|
-
args = fuse_init_args(args || argv
|
|
110
|
+
args = fuse_init_args(args || argv)
|
|
98
111
|
|
|
99
112
|
operations = FuseOperations.new(delegate: operations) unless operations.is_a?(FuseOperations)
|
|
100
113
|
|
|
101
|
-
fuse = Fuse.new(mountpoint, args, operations, private_data)
|
|
114
|
+
fuse = Fuse.new(mountpoint.to_s, args, operations, private_data)
|
|
102
115
|
fuse if fuse.mounted?
|
|
103
116
|
end
|
|
104
117
|
|
|
105
118
|
# @!visibility private
|
|
106
|
-
|
|
107
119
|
def fuse_configure(operations:, show_help: false, show_version: false, **_)
|
|
108
120
|
return true unless operations.respond_to?(:fuse_configure) && !show_help && !show_version
|
|
109
121
|
|
|
@@ -120,20 +132,15 @@ module FFI
|
|
|
120
132
|
end
|
|
121
133
|
end
|
|
122
134
|
|
|
123
|
-
#
|
|
135
|
+
# @!visibility private
|
|
124
136
|
def version
|
|
125
137
|
"#{name}: #{VERSION}"
|
|
126
138
|
end
|
|
127
139
|
|
|
140
|
+
private
|
|
141
|
+
|
|
128
142
|
def fuse_init_args(args)
|
|
129
143
|
if args.is_a?(Array)
|
|
130
|
-
args = args.map(&:to_s) # handle mountpoint as Pathname etc..
|
|
131
|
-
|
|
132
|
-
# https://github.com/libfuse/libfuse/issues/621 handle "source" field sent from /etc/fstab via mount.fuse3
|
|
133
|
-
# if arg[1] and arg[2] are both non option fields then replace arg1 with -ofsname=<arg1>
|
|
134
|
-
unless args.size <= 2 || args[1]&.start_with?('-') || args[2]&.start_with?('-')
|
|
135
|
-
args[1] = "-ofsname=#{args[1]}"
|
|
136
|
-
end
|
|
137
144
|
warn "FuseArgs: #{args.join(' ')}" if args.include?('-d')
|
|
138
145
|
args = FuseArgs.create(*args)
|
|
139
146
|
end
|
|
@@ -143,8 +150,6 @@ module FFI
|
|
|
143
150
|
raise ArgumentError "fuse main args: must be Array<String> or #{FuseArgs.class.name}"
|
|
144
151
|
end
|
|
145
152
|
|
|
146
|
-
private
|
|
147
|
-
|
|
148
153
|
def parse_run_options(args, run_args)
|
|
149
154
|
args.parse!(RUN_OPTIONS) do |key:, value:, **|
|
|
150
155
|
run_args[key] = value
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../libfuse'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'sys-filesystem'
|
|
6
|
+
|
|
7
|
+
# utilities for running tests with fuse filesystems
|
|
8
|
+
module FFI
|
|
9
|
+
module Libfuse
|
|
10
|
+
# Can be included test classes to assist with running/debugging filesystems
|
|
11
|
+
module TestHelper
|
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
|
13
|
+
# rubocop:disable Metrics/MethodLength
|
|
14
|
+
|
|
15
|
+
# Runs the fuse loop on a pre configured fuse filesystem
|
|
16
|
+
# @param [FuseOperations] operations
|
|
17
|
+
# @param [Array<String>] args to pass to {FFI::Libfuse::Main.fuse_create}
|
|
18
|
+
# @param [Hash] options to pass to {FFI::Libfuse::FuseCommon.run}
|
|
19
|
+
# @yield [mnt]
|
|
20
|
+
# caller can execute and test file operations using mnt and ruby File/Dir etc
|
|
21
|
+
# the block is run in a forked process and is successful unless an exception is raised
|
|
22
|
+
# @yieldparam [String] mnt the temporary direct used as the mount point
|
|
23
|
+
# @raise [Error] if unexpected state is found during operations
|
|
24
|
+
# @return [void]
|
|
25
|
+
def with_fuse(operations, *args, **options)
|
|
26
|
+
raise ArgumentError, 'Needs block' unless block_given?
|
|
27
|
+
|
|
28
|
+
# ignore MacOS special files
|
|
29
|
+
args << '-onoappledouble,noapplexattr' if mac_fuse?
|
|
30
|
+
safe_fuse do |mnt|
|
|
31
|
+
# Start the fork before loading fuse (for MacOS)
|
|
32
|
+
fpid = Process.fork do
|
|
33
|
+
sleep 2.5 # Give fuse a chance to start
|
|
34
|
+
yield mnt
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
fuse = FFI::Libfuse::Main.fuse_create(mnt, *args, operations: operations)
|
|
38
|
+
raise FFI::Libfuse::Error, 'No fuse object returned from fuse_create' unless fuse
|
|
39
|
+
|
|
40
|
+
# Rake owns INT
|
|
41
|
+
fuse.default_traps.delete(:TERM)
|
|
42
|
+
fuse.default_traps.delete(:INT)
|
|
43
|
+
|
|
44
|
+
raise FFI::Libfuse::Error, 'fuse object is not mounted?' unless fuse.mounted?
|
|
45
|
+
|
|
46
|
+
t = Thread.new { fuse.run(foreground: true, **options) }
|
|
47
|
+
|
|
48
|
+
# TODO: Work out why waitpid2 hangs on mac unless the process has already finished
|
|
49
|
+
sleep 10 if mac_fuse?
|
|
50
|
+
|
|
51
|
+
_pid, block_status = Process.waitpid2(fpid)
|
|
52
|
+
block_exit = block_status.exitstatus
|
|
53
|
+
fuse.exit('fuse_helper')&.join
|
|
54
|
+
run_result = t.value
|
|
55
|
+
|
|
56
|
+
raise FFI::Libfuse::Error, 'fuse is still mounted after fuse.exit' if fuse.mounted?
|
|
57
|
+
raise FFI::Libfuse::Error, "forked file operations failed with #{block_exit}" unless block_exit.zero?
|
|
58
|
+
raise FFI::Libfuse::Error, "fuse run failed #{run_result}" unless run_result.zero?
|
|
59
|
+
|
|
60
|
+
if !mac_fuse? && mounted?(mnt)
|
|
61
|
+
raise FFI::Libfuse::Error, "OS reports fuse is still mounted at #{mnt} after fuse.exit"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Runs a filesystem in a separate process
|
|
69
|
+
# @param [String] filesystem path to filesystem executable
|
|
70
|
+
# @param [Array<String>] args to pass the filesystem
|
|
71
|
+
# @param [Hash<String,String>] env environment to run the filesystem under
|
|
72
|
+
# @yield [mnt]
|
|
73
|
+
# caller can execute and test file operations using mnt and ruby File/Dir etc
|
|
74
|
+
# @yieldparam [String] mnt the temporary direct used as the mount point
|
|
75
|
+
# @raise [Error] if unexpected state is found during operations
|
|
76
|
+
# @return [Array] stdout, stderr, exit code as captured by Open3.capture3
|
|
77
|
+
# @note if the filesystem is configured to daemonize then no output will be captured
|
|
78
|
+
def run_filesystem(filesystem, *args, env: {})
|
|
79
|
+
fsname = File.basename(filesystem)
|
|
80
|
+
safe_fuse do |mnt|
|
|
81
|
+
t = Thread.new do
|
|
82
|
+
if defined?(Bundler)
|
|
83
|
+
Bundler.with_unbundled_env do
|
|
84
|
+
Open3.capture3(env, 'bundle', 'exec', filesystem.to_s, mnt, "-ofsname=#{fsname}", *args, binmode: true)
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
Open3.capture3(env, filesystem.to_s, mnt, "-ofsname=#{fsname}", *args, binmode: true)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
sleep 1
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
if block_given?
|
|
94
|
+
raise Error, "#{fsname} not mounted at #{mnt}" unless mounted?(mnt, fsname)
|
|
95
|
+
|
|
96
|
+
yield mnt
|
|
97
|
+
end
|
|
98
|
+
# rubocop:disable Lint/RescueException
|
|
99
|
+
# Minitest::Assertion and other test assertion classes are not derived from StandardError
|
|
100
|
+
rescue Exception => _err
|
|
101
|
+
# rubocop:enable Lint/RescueException
|
|
102
|
+
unmount(mnt) if mounted?(mnt)
|
|
103
|
+
o, e, _s = t.value
|
|
104
|
+
warn "Errors\n#{e}" unless e.empty?
|
|
105
|
+
warn "Output\n#{o}" unless o.empty?
|
|
106
|
+
raise
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
unmount(mnt) if mounted?(mnt)
|
|
110
|
+
o, e, s = t.value
|
|
111
|
+
[o, e, s.exitstatus]
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
# rubocop:enable Metrics/AbcSize
|
|
115
|
+
# rubocop:enable Metrics/MethodLength
|
|
116
|
+
|
|
117
|
+
def mounted?(mnt, _filesystem = '.*')
|
|
118
|
+
type, prefix = mac_fuse? ? %w[macfuse /private] : %w[fuse]
|
|
119
|
+
mounts = Sys::Filesystem.mounts.select { |m| m.mount_type == type }
|
|
120
|
+
mounts.detect { |m| m.mount_point == "#{prefix}#{mnt}" }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def unmount(mnt)
|
|
124
|
+
if mac_fuse?
|
|
125
|
+
system("diskutil unmount force #{mnt} >/dev/null 2>&1")
|
|
126
|
+
else
|
|
127
|
+
system("fusermount -zu #{mnt} >/dev/null 2>&1")
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def safe_fuse
|
|
132
|
+
Dir.mktmpdir('ffi-libfuse-spec') do |mountpoint|
|
|
133
|
+
yield mountpoint
|
|
134
|
+
ensure
|
|
135
|
+
# Attempt to force unmount.
|
|
136
|
+
unmount(mountpoint) if mounted?(mountpoint)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def mac_fuse?
|
|
141
|
+
FFI::Platform::IS_MAC
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
data/lib/ffi/libfuse/version.rb
CHANGED
data/lib/ffi/libfuse.rb
CHANGED
|
@@ -19,12 +19,12 @@ module FFI
|
|
|
19
19
|
# Filesystems that want full control (eg to take advantage of multi-threaded operations) should call
|
|
20
20
|
# {Main.fuse_main} instead
|
|
21
21
|
# @note These may change between major versions
|
|
22
|
-
DEFAULT_ARGS = [
|
|
22
|
+
DEFAULT_ARGS = %w[-s -odefault_permissions].freeze
|
|
23
23
|
|
|
24
24
|
class << self
|
|
25
25
|
# Filesystem entry point
|
|
26
26
|
# @see Main.fuse_main
|
|
27
|
-
def fuse_main(*argv, operations:, args: argv.any? ? argv : DEFAULT_ARGS, private_data: nil)
|
|
27
|
+
def fuse_main(*argv, operations:, args: argv.any? ? argv : Main.default_args(*DEFAULT_ARGS), private_data: nil)
|
|
28
28
|
Main.fuse_main(args: args, operations: operations, private_data: private_data) || -1
|
|
29
29
|
end
|
|
30
30
|
alias main fuse_main
|
data/lib/ffi/ruby_object.rb
CHANGED
|
@@ -32,6 +32,7 @@ module FFI
|
|
|
32
32
|
return nil if object_id.zero?
|
|
33
33
|
|
|
34
34
|
_ptr, obj = RubyObject.cache[object_id]
|
|
35
|
+
obj = obj.__getobj__ if obj.is_a?(WeakRef)
|
|
35
36
|
obj
|
|
36
37
|
end
|
|
37
38
|
end
|
|
@@ -66,6 +67,8 @@ module FFI
|
|
|
66
67
|
raise TypeError, "No RubyObject stored at #{ptr.address}" unless cache.key?(ptr.address.object_id)
|
|
67
68
|
|
|
68
69
|
_ptr, obj = cache[ptr.get(:long, 0)]
|
|
70
|
+
# unwrap as the object gets used
|
|
71
|
+
obj = obj.__getobj__ if obj.is_a?(WeakRef)
|
|
69
72
|
obj
|
|
70
73
|
end
|
|
71
74
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ffi-libfuse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Grant Gardner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-01-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|
|
@@ -130,7 +130,7 @@ extensions: []
|
|
|
130
130
|
extra_rdoc_files: []
|
|
131
131
|
files:
|
|
132
132
|
- ".yardopts"
|
|
133
|
-
-
|
|
133
|
+
- CHANGELOG.md
|
|
134
134
|
- LICENSE
|
|
135
135
|
- README.md
|
|
136
136
|
- lib/ffi/accessors.rb
|
|
@@ -178,10 +178,10 @@ files:
|
|
|
178
178
|
- lib/ffi/libfuse/fuse_opt.rb
|
|
179
179
|
- lib/ffi/libfuse/fuse_poll_handle.rb
|
|
180
180
|
- lib/ffi/libfuse/fuse_version.rb
|
|
181
|
+
- lib/ffi/libfuse/gem_version.rb
|
|
181
182
|
- lib/ffi/libfuse/job_pool.rb
|
|
182
183
|
- lib/ffi/libfuse/main.rb
|
|
183
|
-
- lib/ffi/libfuse/
|
|
184
|
-
- lib/ffi/libfuse/test/operations.rb
|
|
184
|
+
- lib/ffi/libfuse/test_helper.rb
|
|
185
185
|
- lib/ffi/libfuse/thread_pool.rb
|
|
186
186
|
- lib/ffi/libfuse/version.rb
|
|
187
187
|
- lib/ffi/ruby_object.rb
|
|
@@ -200,7 +200,7 @@ homepage:
|
|
|
200
200
|
licenses:
|
|
201
201
|
- MIT
|
|
202
202
|
metadata:
|
|
203
|
-
source_code_uri:
|
|
203
|
+
source_code_uri: https://github.com/lwoggardner/ffi-libfuse
|
|
204
204
|
rubygems_mfa_required: 'true'
|
|
205
205
|
post_install_message:
|
|
206
206
|
rdoc_options: []
|
|
@@ -213,11 +213,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
213
213
|
version: 2.7.0
|
|
214
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
215
|
requirements:
|
|
216
|
-
- - "
|
|
216
|
+
- - ">="
|
|
217
217
|
- !ruby/object:Gem::Version
|
|
218
|
-
version:
|
|
218
|
+
version: '0'
|
|
219
219
|
requirements: []
|
|
220
|
-
rubygems_version: 3.1.
|
|
220
|
+
rubygems_version: 3.1.6
|
|
221
221
|
signing_key:
|
|
222
222
|
specification_version: 4
|
|
223
223
|
summary: FFI Bindings for Libfuse
|
data/CHANGES.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
0.1.0 / 2022-04
|
|
2
|
-
------------------
|
|
3
|
-
|
|
4
|
-
#### BREAKING changes
|
|
5
|
-
* Changed option parsing.
|
|
6
|
-
|
|
7
|
-
{FFI::Libfuse::Main#fuse_options} now takes a FuseArgs parameter and fuse_opt_proc is not used
|
|
8
|
-
|
|
9
|
-
#### New Features
|
|
10
|
-
* Implemented helper filesystems in {FFI::Libfuse::Filesystem}
|
|
11
|
-
|
|
12
|
-
#### Fixes
|
|
13
|
-
* Test on OSX with macFuse
|
|
14
|
-
* Lots
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../fuse_operations'
|
|
4
|
-
|
|
5
|
-
module FFI
|
|
6
|
-
module Libfuse
|
|
7
|
-
module Test
|
|
8
|
-
# A FuseOperations that holds callback procs in a Hash rather than FFI objects and allows for direct invocation of
|
|
9
|
-
# callback methods
|
|
10
|
-
# @!parse FuseOperations
|
|
11
|
-
class Operations
|
|
12
|
-
include FuseCallbacks
|
|
13
|
-
|
|
14
|
-
def initialize(delegate:, fuse_wrappers: [])
|
|
15
|
-
@callbacks = {}
|
|
16
|
-
initialize_callbacks(delegate: delegate, wrappers: fuse_wrappers)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# @!visibility private
|
|
20
|
-
def [](member)
|
|
21
|
-
@callbacks[member]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# @!visibility private
|
|
25
|
-
def []=(member, value)
|
|
26
|
-
@callbacks[member] = value
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# @!visibility private
|
|
30
|
-
def members
|
|
31
|
-
FuseOperations.members
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
# Allow the fuse operations to be called directly - useful for testing
|
|
37
|
-
# @todo some fancy wrapper to convert tests using Fuse2 signatures when Fuse3 is the loaded library
|
|
38
|
-
# and vice-versa
|
|
39
|
-
def method_missing(method, *args)
|
|
40
|
-
callback = callback?(method) && self[method]
|
|
41
|
-
return super unless callback
|
|
42
|
-
|
|
43
|
-
callback.call(*args)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def respond_to_missing?(method, _private = false)
|
|
47
|
-
self[method] && callback?(method)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def callback?(method)
|
|
51
|
-
callback_members.include?(method)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
data/lib/ffi/libfuse/test.rb
DELETED