ffi-libfuse 0.0.1.rctest12 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CHANGELOG.md +60 -0
  4. data/LICENSE +21 -0
  5. data/README.md +127 -44
  6. data/lib/ffi/accessors.rb +6 -6
  7. data/lib/ffi/boolean_int.rb +27 -0
  8. data/lib/ffi/devt.rb +23 -0
  9. data/lib/ffi/encoding.rb +38 -0
  10. data/lib/ffi/flock.rb +7 -5
  11. data/lib/ffi/gnu_extensions.rb +1 -1
  12. data/lib/ffi/libfuse/ackbar.rb +3 -3
  13. data/lib/ffi/libfuse/adapter/context.rb +12 -10
  14. data/lib/ffi/libfuse/adapter/fuse2_compat.rb +52 -51
  15. data/lib/ffi/libfuse/adapter/fuse3_support.rb +7 -4
  16. data/lib/ffi/libfuse/adapter/interrupt.rb +1 -1
  17. data/lib/ffi/libfuse/adapter/ruby.rb +499 -148
  18. data/lib/ffi/libfuse/adapter/safe.rb +12 -11
  19. data/lib/ffi/libfuse/adapter.rb +1 -2
  20. data/lib/ffi/libfuse/callbacks.rb +1 -1
  21. data/lib/ffi/libfuse/filesystem/accounting.rb +116 -0
  22. data/lib/ffi/libfuse/filesystem/mapped_dir.rb +74 -0
  23. data/lib/ffi/libfuse/filesystem/mapped_files.rb +141 -0
  24. data/lib/ffi/libfuse/filesystem/pass_through_dir.rb +55 -0
  25. data/lib/ffi/libfuse/filesystem/pass_through_file.rb +45 -0
  26. data/lib/ffi/libfuse/filesystem/utils.rb +102 -0
  27. data/lib/ffi/libfuse/filesystem/virtual_dir.rb +306 -0
  28. data/lib/ffi/libfuse/filesystem/virtual_file.rb +94 -0
  29. data/lib/ffi/libfuse/filesystem/virtual_fs.rb +196 -0
  30. data/lib/ffi/libfuse/filesystem/virtual_node.rb +101 -0
  31. data/lib/ffi/libfuse/filesystem.rb +25 -0
  32. data/lib/ffi/libfuse/fuse2.rb +32 -24
  33. data/lib/ffi/libfuse/fuse3.rb +28 -18
  34. data/lib/ffi/libfuse/fuse_args.rb +71 -34
  35. data/lib/ffi/libfuse/fuse_buffer.rb +128 -26
  36. data/lib/ffi/libfuse/fuse_callbacks.rb +1 -5
  37. data/lib/ffi/libfuse/fuse_common.rb +60 -61
  38. data/lib/ffi/libfuse/fuse_config.rb +134 -143
  39. data/lib/ffi/libfuse/fuse_conn_info.rb +310 -134
  40. data/lib/ffi/libfuse/fuse_context.rb +45 -3
  41. data/lib/ffi/libfuse/fuse_operations.rb +57 -21
  42. data/lib/ffi/libfuse/fuse_opt.rb +1 -1
  43. data/lib/ffi/libfuse/fuse_version.rb +10 -6
  44. data/lib/ffi/libfuse/gem_version.rb +54 -0
  45. data/lib/ffi/libfuse/main.rb +96 -48
  46. data/lib/ffi/libfuse/test_helper.rb +145 -0
  47. data/lib/ffi/libfuse/version.rb +1 -1
  48. data/lib/ffi/libfuse.rb +13 -4
  49. data/lib/ffi/ruby_object.rb +4 -1
  50. data/lib/ffi/stat/constants.rb +9 -0
  51. data/lib/ffi/stat/native.rb +36 -6
  52. data/lib/ffi/stat/time_spec.rb +26 -10
  53. data/lib/ffi/stat.rb +111 -22
  54. data/lib/ffi/stat_vfs.rb +59 -1
  55. data/lib/ffi/struct_wrapper.rb +22 -1
  56. data/sample/hello_fs.rb +54 -0
  57. data/sample/memory_fs.rb +5 -181
  58. data/sample/no_fs.rb +20 -21
  59. data/sample/pass_through_fs.rb +30 -0
  60. metadata +83 -10
  61. data/lib/ffi/libfuse/adapter/thread_local_context.rb +0 -36
  62. data/lib/ffi/libfuse/test/operations.rb +0 -56
  63. data/lib/ffi/libfuse/test.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cc15469bfd68dbe59e7b5dfab82fc1b34fe51e7e3b61e44c686d8a8025ec5ff
4
- data.tar.gz: 691758dbb28272d60cfc1f5f2f37e8cef56de15412706b303f181c5b31cdf03f
3
+ metadata.gz: 688ea85b8e5ee83a4baae3055c14026e65e929c2e22a8d9a2d0e983584e8bd7b
4
+ data.tar.gz: 552a053bea357d44ccf6fa2fcc12d311116d66320e113d7de7acb929a8ac539e
5
5
  SHA512:
6
- metadata.gz: 6dfefe8f3a512dcaa6f2ca34c3f45cba0fb61e17af4dc0114b9fec6a1adc7a63b0f156415b69e256b9bae97d5a9574626001e285f85ddaae985df84d840b2ca3
7
- data.tar.gz: cb4d1f15b5220c9ec4c16a2c0874c082b17ca23a9f725d4bc8e62f5eb69f1e02abaa3960dfef6711dd059ef38e7d97abe2e4af69e68a630bf8728ab3afbfb0ad
6
+ metadata.gz: ca1a1f2b2b9573c523583f0ee9d8fa05fecbbaf4ba36fbe73b4db5090626b8fc984091880677b4654caacda25d6e073b0a679b57539f6faecfd4c62f5bc45257
7
+ data.tar.gz: f8cb9a7d82ac0be86249066b9b69d2cfe03be3e6eb028881b16e715766b2a0f9dbba46ba2478310be75677e2b8c188f0b26235bbfa491dc42d9dff0ca904840e
data/.yardopts CHANGED
@@ -1 +1,3 @@
1
- --markup=markdown
1
+ --markup=markdown
2
+ -
3
+ CHANGELOG.md
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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Grant Gardner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -2,61 +2,160 @@
2
2
 
3
3
  Ruby FFI Binding for [libfuse](https://github.com/libfuse/libfuse)
4
4
 
5
- ## Writing a FUSE Filesystem
5
+ ## Requirements
6
6
 
7
- Create a class that implements the abstract methods of {FFI::Libfuse::Main} and {FFI::Libfuse::FuseOperations}
7
+ * Ruby 2.7
8
+ * Linux: libfuse (Fuse2) or libfuse3 (Fuse3)
9
+ * MacOS: macFuse (https://osxfuse.github.io/)
8
10
 
9
- Call {FFI::Libfuse.fuse_main} to start the filesystem
11
+ ## Building a FUSE Filesystem
12
+
13
+ Install the gem
14
+
15
+ ```bash
16
+ gem install ffi-libfuse
17
+ ```
18
+
19
+ Create a filesystem class
20
+
21
+ * implement FUSE callbacks for filesystem operations satisfying {FFI::Libfuse::FuseOperations}
22
+ * recommend including {FFI::Libfuse::Adapter::Ruby} to add some ruby sugar and safety to the native FUSE Callbacks
23
+ * recommend including {FFI::Libfuse::Adapter::Fuse2Compat} for compatibility with Fuse2/macFuse
24
+ * implement {FFI::Libfuse::Main} configuration methods, eg to parse custom options with {FFI::Libfuse::FuseArgs#parse!}
25
+ (as altered by any included adapters from {FFI::Libfuse::Adapter})
26
+ * Provide an entrypoint to start the filesystem using {FFI::Libfuse::Main.fuse_main}
27
+
28
+ {FFI::Libfuse::Filesystem} contains additional classes and modules to help build and compose filesystems
29
+
30
+ <!-- SAMPLE BEGIN: sample/hello_fs.rb -->
31
+ *sample/hello_fs.rb*
10
32
 
11
33
  ```ruby
34
+ #!/usr/bin/env ruby
35
+ # frozen_string_literal: true
36
+
12
37
  require 'ffi/libfuse'
13
38
 
14
- class MyFS
15
- # include helpers to abstract away from the native C callbacks to more idiomatic Ruby
39
+ # Hello World!
40
+ class HelloFS
16
41
  include FFI::Libfuse::Adapter::Ruby
17
-
18
- # ... FUSE callbacks .... quacks like a FFI:Libfuse::FuseOperations
19
- def getattr(*args)
20
- #...
42
+ include FFI::Libfuse::Adapter::Fuse2Compat
43
+
44
+ # FUSE Configuration methods
45
+
46
+ def fuse_options(args)
47
+ args.parse!({ 'subject=' => :subject }) do |key:, value:, **|
48
+ raise FFI::Libfuse::Error, 'subject option must be at least 2 characters' unless value.size >= 2
49
+
50
+ @subject = value if key == :subject
51
+ :handled
52
+ end
21
53
  end
22
-
23
- def readdir(*args)
24
- #...
54
+
55
+ def fuse_help
56
+ '-o subject=<subject> a target to say hello to'
57
+ end
58
+
59
+ def fuse_configure
60
+ @subject ||= 'World!'
61
+ @content = "Hello #{@subject}\n"
62
+ end
63
+
64
+ # FUSE callbacks
65
+
66
+ def getattr(path, stat, *_args)
67
+ case path
68
+ when '/'
69
+ stat.directory(mode: 0o550)
70
+ when '/hello.txt'
71
+ stat.file(mode: 0o440, size: @content.size)
72
+ else
73
+ raise Errno::ENOENT
74
+ end
75
+ end
76
+
77
+ def readdir(_path, *_args)
78
+ yield 'hello.txt'
79
+ end
80
+
81
+ def read(_path, *_args)
82
+ @content
25
83
  end
26
-
27
84
  end
28
85
 
29
- FFI::Libfuse::fuse_main(operations: MyFS.new) if __FILE__ == $0
86
+ # Start the file system
87
+ FFI::Libfuse.fuse_main(operations: HelloFS.new) if __FILE__ == $0
88
+
30
89
  ```
90
+ <!-- SAMPLE END: sample/hello_fs.rb -->
31
91
 
32
- # Fuse2/Fuse3 compatibility
92
+ Mount the filesystem
93
+
94
+ ```bash
95
+ hello_fs.rb -h # show help
96
+ hello_fs.rb /mnt/hello # run deamonized, mounted at /mnt/hello
97
+ ```
98
+
99
+ Do file things
100
+
101
+ ```bash
102
+ ls /mnt/hello
103
+ cat /mnt/hello/hello.txt
104
+ ```
105
+
106
+ ## Fuse2/Fuse3 compatibility
33
107
 
34
108
  FFI::Libfuse will prefer Fuse3 over Fuse2 by default. See {FFI::Libfuse::LIBFUSE}
35
109
 
36
- For writing filesystems with backwards/forwards compatibility between fuse version see
37
- {FFI::Libfuse::Adapter::Fuse2Compat} and {FFI::Libfuse::Adapter::Fuse3Support}
110
+ New filesystems should write for Fuse3 API and include {FFI::Libfuse::Adapter::Fuse2Compat} for backwards compatibility
111
+
112
+ Alternatively filesystems written against Fuse2 API can include {FFI::Libfuse::Adapter::Fuse3Support}
38
113
 
39
114
  ## MACFuse
40
115
 
41
- [macFUSE](https://osxfuse.github.io/) (previously OSXFuse) supports a superset of the Fuse2 api so FFI::Libfuse is
42
- intended to work in that environment.
116
+ [macFUSE](https://osxfuse.github.io/) (previously OSXFuse) supports a superset of the Fuse2 api
117
+
118
+ **TODO** Implement macFuse extensions
119
+
120
+
121
+ # Under the hood
122
+
123
+ {FFI::Libfuse} provides raw access to the underlying libfuse but there some constraints imposed by Ruby.
124
+
125
+ ## Low-level functions re-implemented in Ruby
43
126
 
44
- # Multi-threading
127
+ The C functions fuse_main(), fuse_daemonize() and fuse_loop<_mt>() are re-implemented to provide
45
128
 
46
- Most Ruby filesystems are unlikely to benefit from multi-threaded operation so
47
- {FFI::Libfuse.fuse_main} as shown above injects the '-s' (single-thread) option by default.
129
+ * dynamic compatibility between Fuse2 and Fuse3
130
+ * support for multi-threading under MRI
131
+ * signal handling in ruby filesystem (eg HUP to reload)
48
132
 
49
- Pass the original options in directly if multi-threaded operation is desired for your filesystem
133
+ The `-o native' option will use the native C functions but only exists to assist with testing that FFI::Libfuse has
134
+ similar behaviour to C libfuse.
135
+
136
+ See {FFI::Libfuse::Main} and {FFI::Libfuse::FuseCommon}
137
+
138
+ ## Multi-threading
139
+
140
+ {FFI::Libfuse.fuse_main} forces the `-s` (single-thread) option to be set since most Ruby filesystems are
141
+ unlikely to benefit from the overhead caused by multi-threaded operation obtaining/releasing the GVL around each
142
+ callback.
143
+
144
+ {FFI::Libfuse::Main.fuse_main} does not pass any options by default and should be used in situations where
145
+ multi-threaded operations may be desirable.
50
146
 
51
147
  ```ruby
52
- FFI::Libfuse::fuse_main($0,*ARGV, operations: MyFS.new) if __FILE__ == $0
148
+ FFI::Libfuse::Main.fuse_main(operations: MyFS.new) if __FILE__ == $0
53
149
  ```
54
150
 
55
- The {FFI::Libfuse::ThreadPool} can be configured with `-o max_threads=<n>,max_idle_threads=<n>` options
151
+ The multi-thread loop uses {FFI::Libfuse::ThreadPool} to control thread usage and can be configured with options
152
+ `-o max_threads=<n>,max_idle_threads=<n>`
56
153
 
57
- Callbacks that are about to block (and release the GVL for MRI) should call {FFI::Libfuse::ThreadPool.busy}.
154
+ Callbacks that are about to block (and release the GVL for MRI) should call {FFI::Libfuse::ThreadPool.busy} which will
155
+ spawn additional worker threads as required.
58
156
 
59
- A typical scenario would be a filesystem where some callbacks are blocking on network IO.
157
+ Note that uncaught exceptions in callbacks will kill the worker thread and if all worker threads are dead the
158
+ file system will stop and unmount. In particular if the first callback raises an exception
60
159
 
61
160
  ```ruby
62
161
  def read(*args)
@@ -70,29 +169,13 @@ end
70
169
  [this discussion](http://fuse.996288.n3.nabble.com/GetAttr-calls-being-serialised-td11741.html)
71
170
  on the serialisation of `#getattr` and `#readdir` calls.
72
171
 
73
- ## Under the hood
172
+ **TODO** Build an example filesystem that makes use of multi-threading
74
173
 
75
- FFI::Libfuse tries to provide raw access to the underlying libfuse but there some constraints imposed by Ruby.
76
-
77
- The functions fuse_main(), fuse_daemonize() and fuse_loop<_mt>() are re-implemented in Ruby so we can provide
78
-
79
- * dynamic compatibility between Fuse2 and Fuse3
80
- * integrated support for multi-threading under MRI (see {FFI::Libfuse::ThreadPool})
81
- * signal handling in ruby filesystem (eg HUP to reload)
82
-
83
- Sending `-o native' will used the native C functions but this exists to assist with testing that FFI::Libfuse has
84
- similar behaviour to libfuse itself.
85
-
86
- See {FFI::Libfuse::Main} and {FFI::Libfuse::FuseCommon}
87
174
 
88
175
  ## Contributing
89
176
 
90
177
  Bug reports and pull requests are welcome on GitHub at https://github.com/lwoggardner/ffi-libfuse.
91
178
 
92
- ### TODO
93
- * Include a MetaFS, PathMapperFS etc (possibly a separate library)
94
- * Build a filesystem that can make use of multi-threaded operations
95
- * Test with macFUSE
96
179
 
97
180
  ## License
98
181
 
data/lib/ffi/accessors.rb CHANGED
@@ -20,8 +20,8 @@ module FFI
20
20
  #
21
21
  # Define a struct attribute reader for members
22
22
  # @param [Array<Symbol>] attrs the attribute names
23
- # @param [String] format
24
- # A format string containing a single %s to convert attr symbol to struct member
23
+ # @param [Proc|String] format
24
+ # A Proc, or format string containing a single %s, to convert attr to struct member name
25
25
  # @param [Boolean] simple
26
26
  # Controls how writer methods are defined using block
27
27
  # @param [Proc] block
@@ -33,7 +33,7 @@ module FFI
33
33
  # @return [void]
34
34
  def ffi_attr_reader(*attrs, format: '%s', simple: true, &block)
35
35
  attrs.each do |attr|
36
- member = (format % attr).to_sym
36
+ member = (format.respond_to?(:call) ? format.call(attr) : format % attr).to_sym
37
37
  ffi_attr_readers[attr] = member
38
38
  if !block
39
39
  define_method(attr) { self[member] }
@@ -47,7 +47,7 @@ module FFI
47
47
 
48
48
  # Define a struct attribute writer
49
49
  # @param [Array<Symbol>] attrs the attribute names
50
- # @param [String] format
50
+ # @param [String|Proc] format
51
51
  # A format string containing a single %s to convert attr symbol to struct member
52
52
  # @param [Boolean] simple
53
53
  # Controls how writer methods are defined using block
@@ -55,8 +55,8 @@ module FFI
55
55
  # An optional block to set the input value into the struct field.
56
56
  #
57
57
  # If simple is true then the struct field is set to the result of calling block with the input value,
58
- # otherwise the method is defined directly from the block. Use __method__[0..-2] to get the attribute name
59
- # and self.class.ffi_attr_writers[__method__[0..-2]] to get the struct field name
58
+ # otherwise the method is defined directly from the block. Use __method__[0..-1] to get the attribute name
59
+ # and self.class.ffi_attr_writers[__method__[0..-1]] to get the struct member name
60
60
  # @return [void]
61
61
  def ffi_attr_writer(*attrs, format: '%s', simple: true, &block)
62
62
  attrs.each do |attr|
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FFI
4
+ # Converter generator for different sizes ints as boolean
5
+ class BooleanInt
6
+ include DataConverter
7
+ attr_reader :native_type
8
+
9
+ def initialize(int_type)
10
+ @native_type = FFI.find_type(int_type)
11
+ end
12
+
13
+ # Falsey = 0, Truthy = 1
14
+ def to_native(obj, _context)
15
+ obj ? 1 : 0
16
+ end
17
+
18
+ # Not Zero
19
+ def from_native(object_id, _context)
20
+ !object_id.zero?
21
+ end
22
+
23
+ %i[char short int long int8 int16 int32 int64].each do |t|
24
+ FFI.typedef(BooleanInt.new(t), "bool_#{t}".to_sym)
25
+ end
26
+ end
27
+ end
data/lib/ffi/devt.rb CHANGED
@@ -26,5 +26,28 @@ module FFI
26
26
  # @param [Integer] dev
27
27
  # @return [Integer] the minor component of dev
28
28
  attach_function :minor, "#{prefix}minor".to_sym, [:int], :int
29
+ rescue FFI::NotFoundError
30
+ case Platform::NAME
31
+ when 'x86_64-darwin'
32
+ # From https://github.com/golang/go/issues/8106 these functions are not defined on Darwin.
33
+ class << self
34
+ # define major(x) ((int32_t)(((u_int32_t)(x) >> 24) & 0xff))
35
+ def major(dev)
36
+ (dev >> 24) & 0xff
37
+ end
38
+
39
+ # define minor(x) ((int32_t)((x) & 0xffffff))
40
+ def minor(dev)
41
+ (dev & 0xffffff)
42
+ end
43
+
44
+ # define makedev(x,y) ((dev_t)(((x) << 24) | (y)))
45
+ def makedev(major, minor)
46
+ (major << 24) | minor
47
+ end
48
+ end
49
+ else
50
+ raise
51
+ end
29
52
  end
30
53
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module FFI
6
+ # DataConverter for reading/writing encoded strings
7
+ class Encoding
8
+ include DataConverter
9
+
10
+ attr_reader :encoding
11
+
12
+ # Create a dataconverter for the specified encoding
13
+ # @example
14
+ # module MyFFIModule
15
+ # extend FFI::Library
16
+ # typedef FFI::Encoding.for('utf8'), :utf8_string
17
+ # end
18
+ def self.for(encoding)
19
+ new(encoding)
20
+ end
21
+
22
+ def from_native(value, _ctx)
23
+ value.force_encoding(encoding)
24
+ end
25
+
26
+ def to_native(value, _ctx)
27
+ value.encode(encoding)
28
+ end
29
+
30
+ def native_type(_type = nil)
31
+ FFI::Type::STRING
32
+ end
33
+
34
+ def initialize(encoding)
35
+ @encoding = encoding
36
+ end
37
+ end
38
+ end
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[f_rdlck f_wrlck f_unlck]
16
- LockCmd = enum :int, [:f_getlk, 5, :f_setlk, 6, :f_setlkw, 7]
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(type: Enums::LockType, whence: Enums::SeekWhenceShort, start: :off_t, len: :off_t, pid: :pid_t)
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
- ffi_attr_reader :type, :whence, :start, :len, :pid
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, :f_rdlck, :f_wrlck, :f_unlck
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
@@ -27,7 +27,7 @@ module FFI
27
27
  module GNUExtensions
28
28
  if FFI::Platform::IS_GNU
29
29
  extend FFI::Library
30
- ffi_lib 'libdl'
30
+ ffi_lib(%w[libdl.so libdl.so.2].flat_map { |l| [l, "#{FFI::Platform::NAME}-gnu/#{l}"] })
31
31
 
32
32
  # @!method dlopen(library,type)
33
33
  # @return [FFI::Pointer] library address, possibly NULL
@@ -29,15 +29,15 @@ module FFI
29
29
  end
30
30
 
31
31
  # @param [Hash<Symbol|String|Integer,String|Proc>] traps
32
- # Map of signal or signo to signal handler as per Signal.trap
32
+ # Map of signal or signo to signal handler as per {::Signal.trap}
33
33
  # @param [Boolean] force
34
- # If not set traps that are not currently set to 'DEFAULT' will be ignored
34
+ # Unless set, only installs traps currently set to 'DEFAULT'.
35
35
  def initialize(traps, force: false, signal: Signal)
36
36
  @signal = signal
37
37
  @traps = traps.transform_keys { |k| signame(k) }
38
38
  @pr, @pw = ::IO.pipe
39
39
  @monitor = nil
40
- @restore = @traps.map { |(sig, handler)| [sig, trap(sig, handler, force: force)] }.to_h
40
+ @restore = @traps.to_h { |sig, handler| [sig, trap(sig, handler, force: force)] }
41
41
  end
42
42
 
43
43
  # Handle the next available signal on the pipe (without blocking)
@@ -5,15 +5,14 @@ require_relative '../fuse_context'
5
5
  module FFI
6
6
  module Libfuse
7
7
  module Adapter
8
- # Wrapper module to inject {FuseContext} as first arg to each callback method (except :destroy)
9
- #
10
- # {ThreadLocalContext} may be a less intrusive means to make the context available to callbacks
8
+ # Injects a wrapper via #{FuseCallbacks#fuse_wrappers} make the current {FuseContext} object available to
9
+ # callbacks (except :destroy) via thread local variable :fuse_context
11
10
  module Context
12
11
  # @!visibility private
13
12
  def fuse_wrappers(*wrappers)
14
13
  wrappers.unshift(
15
14
  {
16
- wrapper: proc { |_fm, *args, **_, &b| self.class.context_callback(*args, &b) },
15
+ wrapper: proc { |_fm, *args, **_, &b| Context.thread_local_context(*args, &b) },
17
16
  excludes: %i[destroy]
18
17
  }
19
18
  )
@@ -24,12 +23,15 @@ module FFI
24
23
 
25
24
  module_function
26
25
 
27
- # @yieldparam [FuseContext] ctx
28
- # @yieldparam [Array] *args
29
- def context_callback(*args)
30
- ctx = FuseContext.get
31
- ctx = nil if ctx.null?
32
- yield ctx, *args
26
+ # Capture {FuseContext} in thread local variable
27
+ def fuse_context
28
+ Thread.current[:fuse_context] ||= FuseContext.get
29
+ end
30
+
31
+ def thread_local_context(*args)
32
+ yield(*args)
33
+ ensure
34
+ Thread.current[:fuse_context] = nil
33
35
  end
34
36
  end
35
37
  end