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
@@ -1,43 +1,91 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../accessors'
|
4
|
+
require_relative '../boolean_int'
|
4
5
|
|
5
6
|
module FFI
|
6
7
|
module Libfuse
|
7
|
-
#
|
8
|
-
# int clone_fd;
|
9
|
-
# unsigned int max_idle_threads;
|
10
|
-
# };
|
8
|
+
# For native fuse_loop_mt only
|
11
9
|
class FuseLoopConfig < FFI::Struct
|
12
10
|
include(FFI::Accessors)
|
13
11
|
|
14
|
-
|
15
|
-
clone_fd: :int,
|
16
|
-
max_idle: :int
|
17
|
-
)
|
18
|
-
|
19
|
-
# @!attribute [rw] clone_fd
|
12
|
+
# @!attribute [w] clone_fd?
|
20
13
|
# whether to use separate device fds for each thread (may increase performance)
|
21
14
|
# Unused by ffi-libfuse as we do not call fuse_loop_mt
|
22
15
|
# @return [Boolean]
|
23
|
-
ffi_attr_reader(:clone_fd) do |v|
|
24
|
-
v != 0
|
25
|
-
end
|
26
|
-
|
27
|
-
ffi_attr_writer(:clone_fd) do |v|
|
28
|
-
v ? 1 : 0
|
29
|
-
end
|
30
16
|
|
31
|
-
# @!attribute [
|
17
|
+
# @!attribute [w] max_idle_threads
|
32
18
|
# The maximum number of available worker threads before they start to get deleted when they become idle. If not
|
33
19
|
# specified, the default is 10.
|
34
20
|
#
|
35
21
|
# Adjusting this has performance implications; a very small number of threads in the pool will cause a lot of
|
36
22
|
# thread creation and deletion overhead and performance may suffer. When set to 0, a new thread will be created
|
37
23
|
# to service every operation.
|
38
|
-
#
|
24
|
+
# @deprecated at Fuse 3.12. Use max_threads instead
|
39
25
|
# @return [Integer] the maximum number of threads to leave idle
|
40
|
-
|
26
|
+
|
27
|
+
# @!attribute [w] max_threads
|
28
|
+
# @return [Integer]
|
29
|
+
# @since Fuse 3.12
|
30
|
+
|
31
|
+
if FUSE_VERSION >= 312
|
32
|
+
layout(
|
33
|
+
version_id: :int,
|
34
|
+
clone_fd: :bool_int,
|
35
|
+
max_idle_threads: :uint,
|
36
|
+
max_threads: :uint
|
37
|
+
)
|
38
|
+
|
39
|
+
Libfuse.attach_function :fuse_loop_cfg_create, [], by_ref
|
40
|
+
Libfuse.attach_function :fuse_loop_cfg_destroy, [:pointer], :void
|
41
|
+
|
42
|
+
ffi_attr_reader(:clone_fd?)
|
43
|
+
Libfuse.attach_function :fuse_loop_cfg_set_clone_fd, %i[pointer uint], :void
|
44
|
+
def clone_fd=(bool_val)
|
45
|
+
Libfuse.fuse_loop_cfg_set_clone_fd(to_ptr, bool_val ? 1 : 0)
|
46
|
+
end
|
47
|
+
|
48
|
+
ffi_attr_reader(:max_idle_threads)
|
49
|
+
Libfuse.attach_function :fuse_loop_cfg_set_idle_threads, %i[pointer uint], :uint
|
50
|
+
def max_idle_threads=(val)
|
51
|
+
Libfuse.fuse_loop_cfg_set_idle_threads(to_ptr, val) if val
|
52
|
+
end
|
53
|
+
|
54
|
+
Libfuse.attach_function :fuse_loop_cfg_set_max_threads, %i[pointer uint], :uint
|
55
|
+
ffi_attr_reader(:max_threads)
|
56
|
+
def max_threads=(val)
|
57
|
+
Libfuse.fuse_loop_cfg_set_max_threads(to_ptr, val) if val
|
58
|
+
end
|
59
|
+
|
60
|
+
class << self
|
61
|
+
def create(max_idle_threads: nil, max_threads: 10, clone_fd: false, **_)
|
62
|
+
cfg = Libfuse.fuse_loop_cfg_create
|
63
|
+
ObjectSpace.define_finalizer(cfg, finalizer(cfg.to_ptr))
|
64
|
+
cfg.clone_fd = clone_fd
|
65
|
+
cfg.max_idle_threads = max_idle_threads if max_idle_threads
|
66
|
+
cfg.max_threads = max_threads if max_threads
|
67
|
+
cfg
|
68
|
+
end
|
69
|
+
|
70
|
+
def finalizer(ptr)
|
71
|
+
proc { |_| Libfuse.fuse_loop_cfg_destroy(ptr) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
layout(
|
76
|
+
clone_fd: :bool_int,
|
77
|
+
max_idle_threads: :uint
|
78
|
+
)
|
79
|
+
|
80
|
+
ffi_attr_accessor(:clone_fd?)
|
81
|
+
ffi_attr_accessor(:max_idle_threads)
|
82
|
+
|
83
|
+
class << self
|
84
|
+
def create(clone_fd: false, max_idle_threads: 10, **_)
|
85
|
+
new.fill(max_idle_threads: max_idle_threads, clone_fd: clone_fd)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
41
89
|
end
|
42
90
|
end
|
43
91
|
end
|
@@ -1,19 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'fuse_version'
|
4
|
-
require_relative '../ruby_object'
|
5
4
|
require_relative 'fuse_conn_info'
|
6
|
-
require_relative '
|
5
|
+
require_relative 'fuse_config'
|
6
|
+
require_relative 'fuse_buf_vec'
|
7
7
|
require_relative 'fuse_context'
|
8
8
|
require_relative 'fuse_file_info'
|
9
9
|
require_relative 'fuse_poll_handle'
|
10
|
+
require_relative 'fuse_callbacks'
|
11
|
+
require_relative '../ruby_object'
|
10
12
|
require_relative '../stat_vfs'
|
11
13
|
require_relative '../flock'
|
12
|
-
require_relative 'thread_pool'
|
13
14
|
require_relative '../stat'
|
14
|
-
require_relative '../struct_array'
|
15
15
|
require_relative '../encoding'
|
16
|
-
require_relative 'fuse_callbacks'
|
17
16
|
|
18
17
|
module FFI
|
19
18
|
# Ruby FFI Binding for [libfuse](https://github.com/libfuse/libfuse)
|
@@ -44,18 +43,80 @@ module FFI
|
|
44
43
|
# All Callback methods are optional, but some are essential for a useful filesystem
|
45
44
|
# e.g. {getattr},{readdir}
|
46
45
|
#
|
47
|
-
# Almost all callback operations take a path which can be of any length and will return 0 for success
|
48
|
-
#
|
46
|
+
# Almost all callback operations take a path which can be of any length and will return 0 for success or a negative
|
47
|
+
# `Errno` value on failure.
|
49
48
|
#
|
50
49
|
class FuseOperations < FFI::Struct
|
51
50
|
include FuseCallbacks
|
52
51
|
|
52
|
+
# Callbacks that have no return value
|
53
|
+
VOID_RETURN = %i[init destroy].freeze
|
54
|
+
|
53
55
|
# Callbacks that are expected to return meaningful positive integers
|
54
56
|
MEANINGFUL_RETURN = %i[read write write_buf lseek copy_file_range getxattr listxattr].freeze
|
55
57
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
58
|
+
# @!visibility private
|
59
|
+
# Methods to handle the path argument for most {path_callbacks}
|
60
|
+
NODE_PATH_METHODS = %i[first shift unshift].freeze
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
# Methods to handle the path argument for {link}, {symlink} and {rename}
|
64
|
+
LINK_PATH_METHODS = %i[last pop push].freeze
|
65
|
+
|
66
|
+
# @!visibility private
|
67
|
+
CALLBACK_PATH_ARG_METHODS = Hash.new(NODE_PATH_METHODS).merge(
|
68
|
+
{
|
69
|
+
link: LINK_PATH_METHODS,
|
70
|
+
symlink: LINK_PATH_METHODS,
|
71
|
+
rename: LINK_PATH_METHODS
|
72
|
+
}
|
73
|
+
).freeze
|
74
|
+
|
75
|
+
class << self
|
76
|
+
# @return [Boolean] true if fuse_callback expects a meaningful integer return
|
77
|
+
def meaningful_return?(fuse_callback)
|
78
|
+
MEANINGFUL_RETURN.include?(fuse_callback)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Boolean] true if fuse_callback expects a void return
|
82
|
+
def void_return?(fuse_callback)
|
83
|
+
VOID_RETURN.include?(fuse_callback)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Helper to determine how to handle the path argument for a path callback
|
87
|
+
# @param [Symbol] fuse_callback callback method name (must be one of #{path_callbacks})
|
88
|
+
# @return [Symbol, Symbol,Symbol] read, remove, add methods.
|
89
|
+
# [:last, :push, :pop] for :link, :symlink, :rename,
|
90
|
+
# [:first, :shift, :unshift] for everything else
|
91
|
+
# @example
|
92
|
+
# def wrap_callback(fuse_method, *args)
|
93
|
+
# read, remove, add = FFI::Libfuse::FuseOperations.path_arg_methods(fuse_method)
|
94
|
+
# path = args.send(read)
|
95
|
+
# # ... do something with path
|
96
|
+
#
|
97
|
+
# path = args.send(remove)
|
98
|
+
# # ... do something to make an alternate path
|
99
|
+
# args.send(add, adjusted_path)
|
100
|
+
# delegate.send(fuse_methoed, *args)
|
101
|
+
# end
|
102
|
+
def path_arg_methods(fuse_callback)
|
103
|
+
CALLBACK_PATH_ARG_METHODS[fuse_callback]
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Set<Symbol>] list of callback methods
|
107
|
+
def fuse_callbacks
|
108
|
+
@fuse_callbacks ||= Set.new(members - [:flags])
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Set<Symbol>] list of path callback methods
|
112
|
+
def path_callbacks
|
113
|
+
@path_callbacks ||= fuse_callbacks - VOID_RETURN
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# @!visibility private
|
118
|
+
def fuse_callbacks
|
119
|
+
self.class.fuse_callbacks
|
59
120
|
end
|
60
121
|
|
61
122
|
# Container to dynamically build up the operations layout which is dependent on the loaded libfuse version
|
@@ -151,12 +212,11 @@ module FFI
|
|
151
212
|
# int (*rmdir) (const char *);
|
152
213
|
op[:rmdir] = []
|
153
214
|
|
154
|
-
# @!method symlink(path
|
215
|
+
# @!method symlink(target, path)
|
155
216
|
# @abstract
|
156
217
|
# Create a symbolic link
|
218
|
+
# @param [String] target
|
157
219
|
# @param [String] path
|
158
|
-
# @param [String] target the link target
|
159
|
-
#
|
160
220
|
# @return [Integer] 0 for success or -ve errno
|
161
221
|
|
162
222
|
# int (*symlink) (const char *, const char *);
|
@@ -173,13 +233,13 @@ module FFI
|
|
173
233
|
# int (*rename) (const char *, const char *);
|
174
234
|
op[:rename] = [:fs_string]
|
175
235
|
|
176
|
-
# @!method link(path
|
236
|
+
# @!method link(target, path)
|
177
237
|
# @abstract
|
178
238
|
# Create a hard link to a file
|
179
|
-
# @param [String] path
|
180
239
|
# @param [String] target
|
181
|
-
#
|
240
|
+
# @param [String] path
|
182
241
|
# @return [Integer] 0 for success or -ve errno
|
242
|
+
# @see rename(2)
|
183
243
|
|
184
244
|
# int (*link) (const char *, const char *);
|
185
245
|
op[:link] = [:fs_string]
|
@@ -486,7 +546,6 @@ module FFI
|
|
486
546
|
# fuse3: void *(*init) (struct fuse_conn_info *conn, struct fuse_config *cfg);
|
487
547
|
op[:init] =
|
488
548
|
if FUSE_MAJOR_VERSION >= 3
|
489
|
-
require_relative 'fuse_config'
|
490
549
|
callback([FuseConnInfo.by_ref, FuseConfig.by_ref], RubyObject)
|
491
550
|
else
|
492
551
|
callback([FuseConnInfo.by_ref], RubyObject)
|
@@ -618,7 +677,7 @@ module FFI
|
|
618
677
|
#
|
619
678
|
|
620
679
|
# int (*utimens) (const char *, const struct timespec tv[2]);
|
621
|
-
op[:utimens] = [FFI::Stat::TimeSpec
|
680
|
+
op[:utimens] = [FFI::Stat::TimeSpec[2]]
|
622
681
|
op[:utimens] << FuseFileInfo.by_ref if FUSE_MAJOR_VERSION >= 3
|
623
682
|
|
624
683
|
# @!method bmap(path,blocksize,index)
|
@@ -655,17 +714,19 @@ module FFI
|
|
655
714
|
# release, fsync, readdir, releasedir, fsyncdir, ftruncate, fgetattr, lock, ioctl and poll
|
656
715
|
#
|
657
716
|
# Closely related to flag_nullpath_ok, but if this flag is set then the path will not be calculaged even if
|
658
|
-
# the file
|
659
|
-
# reason.
|
717
|
+
# the file wasn't unlinked. However the path can still be non-NULL if it needs to be calculated for some
|
718
|
+
# other reason.
|
660
719
|
#
|
661
720
|
# - :utime_omit_ok
|
662
721
|
#
|
663
722
|
# Flag indicating that the filesystem accepts special UTIME_NOW and UTIME_OMIT values in its utimens
|
664
723
|
# operation.
|
665
724
|
#
|
666
|
-
# @return [Array
|
725
|
+
# @return [Array<Symbol>] a list of flags to set capabilities
|
667
726
|
# @note Not available in Fuse3
|
668
727
|
# @deprecated in Fuse3 use fuse_config object in {init}
|
728
|
+
|
729
|
+
# flags
|
669
730
|
op[:flags] = :flags_mask if FUSE_MAJOR_VERSION < 3
|
670
731
|
|
671
732
|
if FUSE_VERSION >= 28
|
@@ -717,7 +778,7 @@ module FFI
|
|
717
778
|
# @abstract
|
718
779
|
# Write contents of buffer to an open file
|
719
780
|
#
|
720
|
-
# Similar to the write
|
781
|
+
# Similar to the {write} method, but data is supplied in a generic buffer.
|
721
782
|
# Use {FuseBufVec#copy_to_fd} to copy data to an open file descriptor, or {FuseBufVec#copy_to_str} to extract
|
722
783
|
# string data from the buffer
|
723
784
|
#
|
@@ -734,16 +795,15 @@ module FFI
|
|
734
795
|
# @!method read_buf(path,bufp,size,offset,fuse_file_info)
|
735
796
|
# @abstract
|
736
797
|
#
|
737
|
-
# Similar to the read
|
798
|
+
# Similar to the {read} method, but data is stored and returned in a generic buffer.
|
738
799
|
#
|
739
800
|
# No actual copying of data has to take place, the source file descriptor may simply be stored in the buffer
|
740
801
|
# for later data transfer.
|
741
802
|
#
|
742
803
|
# @param [String] path
|
743
804
|
# @param [FFI::Pointer<FuseBufVec>] bufp
|
744
|
-
# The buffer must be allocated dynamically
|
745
|
-
#
|
746
|
-
# the caller.
|
805
|
+
# The buffer must be allocated dynamically ({FuseBufVec.init})
|
806
|
+
# and stored at the location pointed to by bufp (see {FuseBufVec#store_to}(bufp)).
|
747
807
|
# @param [Integer] size
|
748
808
|
# @param [Integer] offset
|
749
809
|
# @param [FuseFileInfo] fuse_file_info
|
@@ -886,21 +946,6 @@ module FFI
|
|
886
946
|
fuse_flags.concat(delegate.fuse_flags) if delegate.respond_to?(:fuse_flags)
|
887
947
|
send(:[]=, :flags, fuse_flags.uniq)
|
888
948
|
end
|
889
|
-
|
890
|
-
# @!visibility private
|
891
|
-
def fuse_callbacks
|
892
|
-
self.class.fuse_callbacks
|
893
|
-
end
|
894
|
-
|
895
|
-
# @return [Set<Symbol>] list of callback methods
|
896
|
-
def self.fuse_callbacks
|
897
|
-
@fuse_callbacks ||= Set.new(members - [:flags])
|
898
|
-
end
|
899
|
-
|
900
|
-
# @return [Set<Symbol>] list of path callback methods
|
901
|
-
def self.path_callbacks
|
902
|
-
@path_callbacks ||= fuse_callbacks - %i[init destroy]
|
903
|
-
end
|
904
949
|
end
|
905
950
|
end
|
906
951
|
end
|
@@ -5,13 +5,6 @@ module FFI
|
|
5
5
|
module Libfuse
|
6
6
|
# @!visibility private
|
7
7
|
class GemHelper
|
8
|
-
SEMVER_TAG_REGEX = /^v\d+\.\d+\.\d+/.freeze
|
9
|
-
|
10
|
-
# branches the format is refs/heads/<branch_name>,
|
11
|
-
# tags it is refs/tags/<tag_name>.
|
12
|
-
# for pull requests it is refs/pull/<pr_number>/merge,
|
13
|
-
GIT_REF_TYPES = { 'heads' => :branch, 'tags' => :tag, 'pull' => :pull }.freeze
|
14
|
-
|
15
8
|
class << self
|
16
9
|
# set when install'd.
|
17
10
|
attr_accessor :instance
|
@@ -33,7 +26,7 @@ module FFI
|
|
33
26
|
return [ref, nil] unless ref&.start_with?('refs/')
|
34
27
|
|
35
28
|
_refs, ref_type, ref_name = ref.split('/', 3)
|
36
|
-
[ref_name,
|
29
|
+
[ref_name, { 'heads' => :branch, 'tags' => :tag, 'pull' => :pull }[ref_type]]
|
37
30
|
end
|
38
31
|
|
39
32
|
def gem_version(main_branch:, version:, env: ENV)
|
@@ -44,7 +37,7 @@ module FFI
|
|
44
37
|
when :branch
|
45
38
|
ref_name == main_branch ? [version] : [version, ref_name]
|
46
39
|
when :tag
|
47
|
-
|
40
|
+
/^v\d+\.\d+\.\d+/.match?(ref_name) ? [ref_name[1..]] : [version, ref_name]
|
48
41
|
when :pull
|
49
42
|
pr_number, merge, _rest = ref_name.split('/')
|
50
43
|
# GITHUB_BASE_REF The name of the base ref or target branch of the pull request in a workflow run
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module Libfuse
|
5
|
+
# Helpers for reading/writing to io like objects
|
6
|
+
module IO
|
7
|
+
class << self
|
8
|
+
# Helper to convert a ruby object to size bytes required by {FuseOperations#read}
|
9
|
+
# @param [#pread, #seek & #read, #to_s] io the source to read from, either...
|
10
|
+
#
|
11
|
+
# * an {::IO} like object via :pread(size, offset) or :seek(offset) then :read(size)
|
12
|
+
# * or the String from :to_s
|
13
|
+
#
|
14
|
+
# @param [Integer] size
|
15
|
+
# @param [Integer, nil] offset
|
16
|
+
# if nil the io is assumed to be already positioned
|
17
|
+
# @return [String] the extracted data
|
18
|
+
def read(io, size, offset = nil)
|
19
|
+
return io.pread(size, offset) if offset && io.respond_to?(:pread)
|
20
|
+
|
21
|
+
if (offset ? %i[seek read] : %i[read]).all? { |m| io.respond_to?(m) }
|
22
|
+
io.seek(offset) if offset
|
23
|
+
return io.read(size)
|
24
|
+
end
|
25
|
+
|
26
|
+
io.to_s[offset || 0, size] || ''
|
27
|
+
end
|
28
|
+
|
29
|
+
# Helper to write date to {::IO} or {::String} like objects for use with #{FuseOperations#write}
|
30
|
+
# @param [#pwrite, #seek & #write, #[]=] io an object that accepts String data via...
|
31
|
+
#
|
32
|
+
# * ```ruby io.pwrite(data, offset)```
|
33
|
+
# * ```ruby io.seek(offset) ; io.write(data)```
|
34
|
+
# * ```ruby io[offset, data.size] = data```
|
35
|
+
# @param [String] data
|
36
|
+
# @param [nil, Integer] offset
|
37
|
+
# if not nil start start writing at this position in io
|
38
|
+
# @return [Integer] number of bytes written
|
39
|
+
# @raise [Errno::EBADF] if io does not support the requisite methods
|
40
|
+
def write(io, data, offset = nil)
|
41
|
+
if offset && io.respond_to?(:pwrite)
|
42
|
+
io.pwrite(data, offset)
|
43
|
+
elsif (offset ? %i[seek write] : %i[write]).all? { |m| io.respond_to?(m) }
|
44
|
+
io.seek(offset) if offset
|
45
|
+
io.write(data)
|
46
|
+
elsif io.respond_to?(:[]=) # eg String
|
47
|
+
io[offset || 0, data.size] = data
|
48
|
+
data.size
|
49
|
+
else
|
50
|
+
raise "cannot :pwrite or :write to #{io}", Errno::EBADF
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/ffi/libfuse/main.rb
CHANGED
@@ -24,15 +24,13 @@ module FFI
|
|
24
24
|
|
25
25
|
# Main function of FUSE
|
26
26
|
#
|
27
|
-
# This function:
|
28
|
-
#
|
29
27
|
# - parses command line options - see {fuse_parse_cmdline}
|
30
|
-
#
|
31
|
-
# -
|
32
|
-
# -
|
33
|
-
# -
|
34
|
-
# -
|
35
|
-
# - calls
|
28
|
+
# - calls {#fuse_configure} if implemented by operations
|
29
|
+
# - creates a fuse handle see {fuse_create}
|
30
|
+
# - returns 0 if help or version options were processed (ie after all messages have been printed by libfuse)
|
31
|
+
# - returns 2 if fuse handle is not successfully mounted
|
32
|
+
# - calls {#fuse_traps} if implemented by operations
|
33
|
+
# - calls run on the fuse handle with options from previous steps- see {FuseCommon#run}
|
36
34
|
#
|
37
35
|
# @param [Array<String>] argv mount.fuse arguments
|
38
36
|
# expects progname, mountpoint, options....
|
@@ -46,23 +44,23 @@ module FFI
|
|
46
44
|
# @return [Integer] suitable for process exit code
|
47
45
|
def fuse_main(*argv, operations:, args: argv.any? ? argv : default_args, private_data: nil)
|
48
46
|
run_args = fuse_parse_cmdline(args: args, handler: operations)
|
49
|
-
return 2 unless run_args
|
50
47
|
|
51
48
|
fuse_args = run_args.delete(:args)
|
52
49
|
mountpoint = run_args.delete(:mountpoint)
|
53
50
|
|
54
|
-
|
51
|
+
show_only = run_args[:show_help] || run_args[:show_version]
|
52
|
+
|
53
|
+
return 3 if !show_only && !fuse_configure(operations)
|
55
54
|
|
56
55
|
warn "FuseCreate: mountpoint: #{mountpoint}, args: [#{fuse_args.argv.join(' ')}]" if run_args[:debug]
|
57
56
|
warn "FuseRun: #{run_args}" if run_args[:debug]
|
58
57
|
|
59
58
|
fuse = fuse_create(mountpoint, args: fuse_args, operations: operations, private_data: private_data)
|
60
59
|
|
61
|
-
return 0 if
|
60
|
+
return 0 if show_only
|
62
61
|
return 2 if !fuse || !mountpoint
|
63
62
|
|
64
|
-
|
65
|
-
|
63
|
+
run_args[:traps] = operations.fuse_traps if operations.respond_to?(:fuse_traps)
|
66
64
|
fuse.run(**run_args)
|
67
65
|
end
|
68
66
|
alias main fuse_main
|
@@ -72,7 +70,6 @@ module FFI
|
|
72
70
|
# - parses standard command line options (-d -s -h -V)
|
73
71
|
# will call {fuse_debug}, {fuse_version}, {fuse_help} if implemented by handler
|
74
72
|
# - calls {fuse_options} for custom option processing if implemented by handler
|
75
|
-
# - records signal handlers if operations implements {fuse_traps}
|
76
73
|
# - parses standard fuse mount options
|
77
74
|
#
|
78
75
|
# @param [Array<String>] argv mount.fuse arguments
|
@@ -88,24 +85,25 @@ module FFI
|
|
88
85
|
# * show_version [Boolean]: -v or --version
|
89
86
|
# * debug [Boolean]: -d
|
90
87
|
# * others are options to pass to {FuseCommon#run}
|
88
|
+
# @return [nil] if args are not parsed successfully
|
91
89
|
def fuse_parse_cmdline(*argv, args: argv.any? ? argv : default_args, handler: nil)
|
92
90
|
args = fuse_init_args(args)
|
93
91
|
|
94
92
|
# Parse args and print cmdline help
|
95
93
|
run_args = Fuse.parse_cmdline(args, handler: handler)
|
96
|
-
return nil unless run_args
|
97
94
|
|
98
|
-
|
95
|
+
handler.fuse_options(args) if handler.respond_to?(:fuse_options)
|
99
96
|
|
100
|
-
run_args
|
101
|
-
|
102
|
-
return nil unless parse_run_options(args, run_args)
|
97
|
+
parse_run_options(args, run_args)
|
103
98
|
|
104
99
|
run_args[:args] = args
|
105
100
|
run_args
|
101
|
+
rescue Error
|
102
|
+
nil
|
106
103
|
end
|
107
104
|
|
108
|
-
# @return [FuseCommon
|
105
|
+
# @return [FuseCommon] the mounted filesystem handle
|
106
|
+
# @return [nil] if not mounted (eg due to --help or --version, or an error)
|
109
107
|
def fuse_create(mountpoint, *argv, operations:, args: nil, private_data: nil)
|
110
108
|
args = fuse_init_args(args || argv)
|
111
109
|
|
@@ -116,8 +114,8 @@ module FFI
|
|
116
114
|
end
|
117
115
|
|
118
116
|
# @!visibility private
|
119
|
-
def fuse_configure(operations
|
120
|
-
return true unless operations.respond_to?(:fuse_configure)
|
117
|
+
def fuse_configure(operations)
|
118
|
+
return true unless operations.respond_to?(:fuse_configure)
|
121
119
|
|
122
120
|
# Provide sensible values for FuseContext in case this is referenced during configure
|
123
121
|
FFI::Libfuse::FuseContext.overrides do
|
@@ -166,7 +164,8 @@ module FFI
|
|
166
164
|
# @abstract
|
167
165
|
# Called to allow filesystem to handle custom options and observe standard mount options #
|
168
166
|
# @param [FuseArgs] args
|
169
|
-
# @
|
167
|
+
# @raise [Error] if there is an error parsing the options
|
168
|
+
# @return [void]
|
170
169
|
# @see FuseArgs#parse!
|
171
170
|
# @example
|
172
171
|
# OPTIONS = { 'config=' => :config, '-c ' => :config }
|
@@ -174,7 +173,7 @@ module FFI
|
|
174
173
|
# args.parse!(OPTIONS) do |key:, value:, out:, **opts|
|
175
174
|
#
|
176
175
|
# # raise errors for invalid config
|
177
|
-
# raise FFI::Libfuse::
|
176
|
+
# raise FFI::Libfuse::Error, "Invalid config" unless valid_config?(key,value)
|
178
177
|
#
|
179
178
|
# # Configure the file system
|
180
179
|
# @config = value if key == :config
|
@@ -189,15 +188,22 @@ module FFI
|
|
189
188
|
|
190
189
|
# @!method fuse_traps
|
191
190
|
# @abstract
|
192
|
-
#
|
191
|
+
# Passed to {FuseCommon#run} to allow filesystem to handle custom signal traps. These traps
|
192
|
+
# are merged over those from {FuseCommon#default_traps}. A nil value can be used to avoid a default trap
|
193
|
+
# being set.
|
194
|
+
# @return [Hash<String|Symbol|Integer,String|Proc|nil>]
|
193
195
|
# map of signal name or number to signal handler as per Signal.trap
|
194
196
|
# @example
|
195
197
|
# def fuse_traps
|
196
|
-
# {
|
198
|
+
# {
|
199
|
+
# HUP: ->() { reload() },
|
200
|
+
# INT: nil
|
201
|
+
# }
|
197
202
|
# end
|
198
203
|
|
199
204
|
# @!method fuse_version
|
200
205
|
# @abstract
|
206
|
+
# Called as part of generating output for the -V option
|
201
207
|
# @return [String] a custom version string to output with -V option
|
202
208
|
|
203
209
|
# @!method fuse_help
|
@@ -214,6 +220,7 @@ module FFI
|
|
214
220
|
# @!method fuse_configure
|
215
221
|
# @abstract
|
216
222
|
# Called immediately before the filesystem is mounted, after options have been parsed
|
223
|
+
# (eg to validate required options)
|
217
224
|
#
|
218
225
|
# @raise [Error] to prevent the mount from proceeding
|
219
226
|
# @return [void]
|