rfuse 1.2.3 → 2.0.0.ffilibfuse

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9bbd56ab8bb580e8c2a40b19b15a75bf7afad004296c72d3e8157e0a6fbb223
4
- data.tar.gz: 1eeef7cb6a0f6a874da3b87d99452af3737cfa7d973650ccb5eaed992174a48f
3
+ metadata.gz: 21bf2d68b3864f3d86fcb6aee697228b006a6195d3b50e75db16f4f57153d7e9
4
+ data.tar.gz: e277766b10e550cc2e249fd9e71a42de6def695fdc5d8c5ad1a8140389851948
5
5
  SHA512:
6
- metadata.gz: 124adc8292a4f1a017e3034d51d645486629992f97ff8b106366929a752b36bf3f25e228001cb8af21a5f7a98147c430bbf2de226d31f7e4392c4bba83151b86
7
- data.tar.gz: 11b76dd86a7b1687ef877c6d660a71c041d728341bb5e3200da5a97f6ba80a64102fd2134338f9c7edca67106688ba0a9109fc76024c2fb800254b33f7994d3d
6
+ metadata.gz: ef0321ae2ae040627784f18726ce368a30225b7ab081c3c67ea10293152387b3e54ec29c4ddd04654f3df2b7acc84dd81864be9b844f402aaec564e3d1b63f50
7
+ data.tar.gz: 4040eeb235b97fc83942dc5757ce3021c30732547f8368c1f1cfc8c90a1f2be9c90f529ae03e7c29cb6f77947439892178a7dd02906709da07830c2969e1d420
data/.yardopts CHANGED
@@ -1,4 +1,5 @@
1
1
  --no-private
2
2
  --markup=markdown
3
3
  -
4
- CHANGES.md
4
+ CHANGELOG.md
5
+
@@ -1,3 +1,9 @@
1
+ 2.0.0 - 2023/01 UNMAINTAINED
2
+ -------------------
3
+ * Uses ffi-libfuse instead of local C extension
4
+ * Starting filesystems through RFuse.main
5
+ * Require Ruby 2.7+
6
+
1
7
  1.2.0 - 2020/09
2
8
  -------------------
3
9
  * Fix builds on recent linux
data/README.md CHANGED
@@ -1,60 +1,32 @@
1
- RFuse
1
+ RFuse - DEPRECATED
2
2
  ===============
3
3
 
4
- http://rubygems.org/gems/rfuse
5
- ![Gem Version](https://badge.fury.io/rb/rfuse.png)
4
+ ### DEPRECATED
6
5
 
7
- Ruby FUSE binding
6
+ This gem exists and is maintained for backwards compatibility only.
8
7
 
9
- FUSE (Filesystem in USErspace) is a simple interface for userspace programs to export a virtual filesystem to the linux kernel. FUSE aims to provide a secure method for non privileged users to create and mount their own filesystem implementations.
8
+ Existing RFuse filesystems are recommended to refactor to depend directly on
9
+ [ffi_libfuse](http://rubygems.org/gems/ffi-libfuse) which supports Fuse 3 and Macfuse
10
10
 
11
- This library provides the low-level fuse operations as callbacks into a ruby object.
11
+ {RFuse::Adapter} documents the fuse method signatures that are different to ffi-libfuse
12
12
 
13
- For a more ruby-ish API for creating filesystems see {http://rubygems.org/gems/rfusefs RFuseFS} which is built on RFuse and takes care of some of the heavy lifting.
14
-
15
- Dependencies
16
- --------------
17
-
18
- * Ruby 2.5+
19
- * Fuse 2.8+
20
-
21
- Installation
22
13
  ---------------
23
14
 
24
- gem install rfuse
25
-
26
- Creating a filesystem
27
- ---------------------------
28
-
29
- Create your filesystem as a class implementing the abstract FUSE methods from {RFuse::Fuse} as necessary.
30
-
31
- Run it with {RFuse.main}
15
+ ### Dependencies
32
16
 
33
- For a sample filesystem see sample/test-ruby.rb
34
-
35
- To run the example:
36
-
37
- mkdir /tmp/fuse
38
- ruby sample/test-ruby.rb /tmp/fuse
39
-
40
- there should be an empty in-memory filesystem mounted at `/tmp/fuse`
17
+ * Ruby 2.7+
18
+ * Fuse 2.8+ / Fuse 3 / MACFuse
41
19
 
42
20
  HISTORY
43
- ======
44
- This project is forked from rfuse-ng which was forked from the original rfuse.
21
+ ============
22
+
23
+ This project was forked from rfuse-ng which was forked from the original rfuse.
45
24
 
46
25
  RFuse-NG: Tamás László Fábián <giganetom@gmail.com> et al on Github
47
26
 
48
27
  Original Rfuse (@rubyforge): Peter Schrammel AT gmx.de
49
28
 
50
- See also {file:CHANGES.md}
29
+ See also {file:CHANGELOG.md}
51
30
 
52
- CONTRIBUTING
31
+ ~~CONTRIBUTING~~
53
32
  ============
54
-
55
- 1. Fork it on {http://github.com/lwoggardner/rfuse on GitHub}
56
- 2. Create your feature branch (`git checkout -b my-new-feature`)
57
- 3. Write some specs and make them pass
58
- 4. Commit your changes (`git commit -am 'Added some feature'`)
59
- 5. Push to the branch (`git push origin my-new-feature`)
60
- 6. Create new Pull Request
@@ -0,0 +1,31 @@
1
+ module RFuse
2
+ # Wrapper for FFI:Flock back to RFuse
3
+ class Flock
4
+
5
+ attr_reader :delegate
6
+
7
+ def initialize(ffi_flock)
8
+ @delegate = ffi_flock
9
+ end
10
+
11
+ def l_type
12
+ FFI::Flock::Enums::LockType.to_h[delegate.type] || 0
13
+ end
14
+
15
+ def l_whence
16
+ FFI::Flock::Enums::SeekWhenceShort.to_h[delegate.whence] || 0
17
+ end
18
+
19
+ def l_start
20
+ delegate.start
21
+ end
22
+
23
+ def l_len
24
+ delegate.len
25
+ end
26
+
27
+ def l_pid
28
+ delegate.pid
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version'
4
+ begin
5
+ require 'ffi/libfuse/gem_helper'
6
+ rescue LoadError
7
+ # allow bundle install to run
8
+ end
9
+
10
+ module RFuse
11
+ # @!visibility private
12
+ MAIN_BRANCH = 'master'
13
+ GEM_VERSION, =
14
+ if defined? FFI::Libfuse
15
+ FFI::Libfuse::GemHelper.gem_version(version: VERSION, main_branch: MAIN_BRANCH)
16
+ else
17
+ "#{VERSION}.pre"
18
+ end
19
+ end
20
+
@@ -0,0 +1,318 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi/libfuse'
4
+
5
+ module RFuse
6
+ # Filler object
7
+ # @see readdir
8
+ class Filler < FFI::Libfuse::Adapter::Ruby::ReaddirFiller
9
+
10
+ def push(name, stat, offset = 0)
11
+ fill(name, stat: stat, offset: offset)
12
+ end
13
+ end
14
+
15
+ # Map callback methods to be compatible for legacy RFuse
16
+ #
17
+ # All native {FuseOperations} callback signatures are amended to take {FuseContext} as the first argument.
18
+ #
19
+ # A subset of callbacks are documented here where their signatures are further altered to match RFuse
20
+ #
21
+ # RFuse did not support Fuse3
22
+ # adapter module
23
+ module Adapter
24
+
25
+ # Converts Fuse2 calls into RFuse calls
26
+ # @!visibility private
27
+ module Prepend
28
+
29
+ include FFI::Libfuse::Adapter
30
+
31
+ def readdir(ctx, path, buf, filler, offset, ffi)
32
+
33
+ rd_filler = Filler.new(buf, filler, fuse3: false)
34
+ super(ctx, path, rd_filler, offset, ffi)
35
+ 0
36
+ end
37
+
38
+ def readlink(ctx, path, buf, size)
39
+ link = super(ctx, path)
40
+
41
+ return -Errno::ERANGE::Errno unless link.size <= size
42
+
43
+ buf.write_bytes(link)
44
+ 0
45
+ end
46
+
47
+ def mknod(ctx, path, mode, dev)
48
+ super(ctx, path, mode, FFI::Device.major(dev), FFI::Device.minor(dev))
49
+ 0
50
+ end
51
+
52
+ def getattr(ctx, path, stat_buf)
53
+ result = super(ctx, path)
54
+ raise Errno::ENOENT unless result
55
+
56
+ stat_buf.fill(result)
57
+ 0
58
+ end
59
+
60
+ def fgetattr(ctx, path, stat_buf, ffi)
61
+ stat_buf.fill(super(ctx, path, ffi))
62
+ 0
63
+ end
64
+
65
+ # Set file atime, mtime via super as per {Ruby#utimens}
66
+ def utimens(ctx, path, times)
67
+ atime, mtime = Stat::TimeSpec.fill_times(times[0, 2], 2)
68
+
69
+ begin
70
+ super(ctx, path, atime.nanos, mtime.nanos)
71
+ rescue NoMethodError
72
+ utime(ctx, path, atime.sec, mtime.sec)
73
+ end
74
+ 0
75
+ end
76
+
77
+ def read(ctx, path, buf, size, offset, info)
78
+ res = super(ctx, path, size, offset, info)
79
+
80
+ return -Errno::ERANGE::Errno unless res.size <= size
81
+
82
+ buf.write_bytes(res)
83
+ res.size
84
+ end
85
+
86
+ def write(ctx, path, buf, size, offset, info)
87
+ super(ctx, path, buf.read_bytes(size), offset, info)
88
+ end
89
+
90
+ def statfs(ctx, path, statfs_buf)
91
+ statfs_buf.fill(super(ctx, path))
92
+ 0
93
+ end
94
+
95
+ def setxattr(ctx, path, name, value, _size, flags)
96
+ super(ctx, path, name, value, FFI::Libfuse::XAttr.to_h[flags] || 0)
97
+ 0
98
+ end
99
+
100
+ def getxattr(ctx, path, name, buf, size)
101
+ FFI::Libfuse::Adapter::Ruby.getxattr(buf, size) do
102
+ super(ctx, path, name)
103
+ end
104
+ end
105
+
106
+ def listxattr(ctx, path, buf, size)
107
+ FFI::Libfuse::Adapter::Ruby.listxattr(buf, size) do
108
+ super(ctx, path)
109
+ end
110
+ end
111
+
112
+ %i[create open opendir].each do |fuse_method|
113
+ define_method(fuse_method) do |*args|
114
+ super(*args)
115
+ store_handle(args.last&.fh)
116
+ 0
117
+ end
118
+ end
119
+
120
+ %i[release releasedir].each do |fuse_method|
121
+ define_method(fuse_method) do |*args|
122
+ super(*args)
123
+ 0
124
+ rescue NoMethodError
125
+ # OK, just release the file handle
126
+ 0
127
+ ensure
128
+ release_handle(args.last&.fh)
129
+ end
130
+ end
131
+
132
+ def init(ctx, fuse_conn_info)
133
+ super
134
+ self
135
+ end
136
+
137
+ def lock(ctx, path, ffi, cmd, lock)
138
+ super(ctx, path, ffi, FFI::Flock::Enums::LockCmd.to_h[cmd], Flock.new(lock))
139
+ 0
140
+ end
141
+
142
+ def fuse_respond_to?(fuse_callback)
143
+ return true if super
144
+
145
+ case fuse_callback
146
+ when :release
147
+ # Ensure file handles to be cleaned up at release
148
+ %i[open create].any? { |m| super(m) }
149
+ when :release_dir
150
+ super(:open_dir)
151
+ when :utimens
152
+ super(:utime)
153
+ else
154
+ false
155
+ end
156
+ end
157
+
158
+ def open_files
159
+ handles
160
+ end
161
+
162
+ private
163
+
164
+ # Prevent filehandles from being GCd
165
+ def handles
166
+ @handles ||= Set.new.compare_by_identity
167
+ end
168
+
169
+ def store_handle(file_handle)
170
+ handles << file_handle if file_handle
171
+ end
172
+
173
+ def release_handle(file_handle)
174
+ handles.delete(file_handle)
175
+ end
176
+ end
177
+
178
+
179
+ # @!method readdir(context,path,filler,offset,ffi)
180
+ #
181
+ # List contents of a directory
182
+ #
183
+ # @param [Context] context
184
+ # @param [String] path
185
+ # @param [Filler] filler
186
+ # @param [Fixnum] offset
187
+ # @param [FileInfo] ffi
188
+ #
189
+ # @return [void]
190
+ # @raise [Errno]
191
+
192
+ # @!method readlink(path)
193
+ # @abstract
194
+ # @param [String] path
195
+ # @return [String] the link target
196
+
197
+ # @!method mknod(context,path,mode,major,minor)
198
+ # Create a file node
199
+ # @abstract Fuse Operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#1465eb2268cec2bb5ed11cb09bbda42f mknod}
200
+ #
201
+ # @param [Context] context
202
+ # @param [String] path
203
+ # @param [Integer] mode type & permissions
204
+ # @param [Integer] major
205
+ # @param [Integer] minor
206
+ #
207
+ # @return[void]
208
+ #
209
+ # This is called for creation of all non-directory, non-symlink nodes. If the filesystem defines {#create}, then for regular files that will be called instead.
210
+
211
+ # @!method getattr(ctx,path)
212
+ # @param [FuseContext ctx]
213
+ # @param [String] path
214
+ # @return [Stat] the stat information (or something that can fill a stat)
215
+
216
+ # @!method fgetattr(ctx,path,ffi)
217
+ # @param [FuseContext ctx]
218
+ # @param [String] path
219
+ # @return [Stat] the stat information (or something that can fill a stat)
220
+
221
+ # @!method utime(ctx,path,atime,mtime)
222
+ # @abstract
223
+ # @deprecated prefer {utimens}
224
+ #
225
+ # @param [Context] context
226
+ # @param [String] path
227
+ # @param [Integer] atime access time in seconds or nil if only setting mtime
228
+ # @param [Integer] mtime modification time in seconds or nil if only setting atime
229
+ #
230
+ # @return [void]
231
+ # @raise [Errno]
232
+
233
+ # @!method utimens(ctx,path,atime,mtime)
234
+ # @abstract
235
+ # @param [Context] context
236
+ # @param [String] path
237
+ # @param [Integer] atime access time in nanoseconds or nil if only setting mtime
238
+ # @param [Integer] mtime modification time in nanoseconds or nil if only setting atime
239
+ #
240
+ # @return [void]
241
+ # @raise [Errno]
242
+
243
+ # @!method read(ctx,path,size,offset,info)
244
+ # @abstract
245
+ # @param [FuseContext ctx]
246
+ # @param [String] path
247
+ # @param [Integer] size
248
+ # @param [Integer] offset
249
+ # @param [FuseFileInfo] info
250
+ #
251
+ # @return [String] the data, expected to be exactly size bytes
252
+
253
+ # @!method write(ctx,path,data,offset,info)
254
+ # @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#897d1ece4b8b04c92d97b97b2dbf9768 write}
255
+ # Write data to an open file
256
+ #
257
+ # @param [Context] context
258
+ # @param [String] path
259
+ # @param [String] data
260
+ # @param [Integer] offset
261
+ # @param [FileInfo] ffi
262
+ #
263
+ # @return [Integer] exactly the number of bytes requested except on error
264
+ # @raise [Errno]
265
+
266
+ # Set extended attributes
267
+ #
268
+ # @!method setxattr(context,path,name,data,flags)
269
+ # @abstract Fuse operation {http://fuse.sourceforge.net/doxygen/structfuse__operations.html#988ced7091c2821daa208e6c96d8b598 setxattr}
270
+ # @param [Context] context
271
+ # @param [String] path
272
+ # @param [String] name
273
+ # @param [String] data
274
+ # @param [Integer] flags
275
+ #
276
+ # @return [void]
277
+ # @raise [Errno]
278
+
279
+ # @method getxattr(ctx,path,name)
280
+ # @abstract
281
+ # @param [FuseContext ctx]
282
+ # @param [String] path
283
+ # @param [String] name the attribute name
284
+ # @return [String|nil] the attribute value or nil if it does not exist
285
+
286
+ # @method listxattr(ctx,path)
287
+ # @abstract
288
+ # @param [FuseContext ctx]
289
+ # @param [String] path
290
+ # @return [Array<String>] list of attribute names for path
291
+
292
+ # @!visibility private
293
+
294
+ def fuse_wrappers(*wrappers)
295
+ # Change signatures to match legacy RFuse
296
+ wrappers.unshift({
297
+ wrapper: proc { |_fm, *args, &b| b.call(FFI::Libfuse::FuseContext.get, *args) },
298
+ excludes: %i[destroy]
299
+ })
300
+
301
+ return wrappers unless defined?(super)
302
+
303
+ super(*wrappers)
304
+ end
305
+
306
+ def default_errno
307
+ Errno::ENOENT::Errno
308
+ end
309
+
310
+ def self.included(mod)
311
+ mod.prepend(Prepend)
312
+ mod.include(FFI::Libfuse::Adapter::Fuse3Support)
313
+ mod.include(FFI::Libfuse::Adapter::Safe)
314
+ end
315
+
316
+ end
317
+ end
318
+
data/lib/rfuse/stat.rb ADDED
@@ -0,0 +1,43 @@
1
+ module RFuse
2
+ # Helper class to return from :getattr method
3
+ class Stat
4
+
5
+ # See FFI::Stat constants
6
+ def self.const_missing(const)
7
+ return super unless FFI::Stat.const_defined?(const)
8
+ FFI::Stat.const_get(const)
9
+ end
10
+
11
+ # @param [Fixnum] mode file permissions
12
+ # @param [Hash<Symbol,Fixnum>] values initial values for other attributes
13
+ #
14
+ # @return [Stat] representing a directory
15
+ def self.directory(mode = 0, values = {})
16
+ new(S_IFDIR, mode, values)
17
+ end
18
+
19
+ # @param [Fixnum] mode file permissions
20
+ # @param [Hash<Symbol,Fixnum>] values initial values for other attributes
21
+ #
22
+ # @return [Stat] representing a regular file
23
+ def self.file(mode = 0, values = {})
24
+ new(S_IFREG, mode, values)
25
+ end
26
+
27
+ # @return [Integer] see stat(2)
28
+ attr_accessor :uid, :gid, :mode, :size, :dev, :ino, :nlink, :rdev, :blksize, :blocks
29
+
30
+ # @return [Integer, Time] see stat(2)
31
+ attr_accessor :atime, :mtime, :ctime
32
+
33
+ def initialize(type, permissions, values = {})
34
+ values[:mode] = ((type & S_IFMT) | (permissions & 0o7777))
35
+ @uid, @gid, @size, @mode, @atime, @mtime, @ctime, @dev, @ino, @nlink, @rdev, @blksize, @blocks = Array.new(
36
+ 13, 0
37
+ )
38
+ values.each_pair do |k, v|
39
+ instance_variable_set("@#{k}", v)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ module RFuse
2
+
3
+ # Helper class to return from :statfs (eg for df output)
4
+ # All attributes are Integers and default to 0
5
+ class StatVfs
6
+ # @return [Integer]
7
+ attr_accessor :f_bsize, :f_frsize, :f_blocks, :f_bfree, :f_bavail
8
+
9
+ # @return [Integer]
10
+ attr_accessor :f_files, :f_ffree, :f_favail, :f_fsid, :f_flag, :f_namemax
11
+
12
+ # values can be symbols or strings but drop the pointless f_ prefix
13
+ def initialize(values = {})
14
+ @f_bsize, @f_frsize, @f_blocks, @f_bfree, @f_bavail, @f_files, @f_ffree, @f_favail, @f_fsid, @f_flag, @f_namemax = Array.new(
15
+ 13, 0
16
+ )
17
+ values.each_pair do |k, v|
18
+ prefix = k.to_s.start_with?('f_') ? '' : 'f_'
19
+ instance_variable_set("@#{prefix}#{k}", v)
20
+ end
21
+ end
22
+
23
+ def respond_to_missing?(method, private=false)
24
+ !method.start_with?('f_') && respond_to?("f_#{method}", private)
25
+ end
26
+
27
+ def method_missing(method, *args)
28
+ return super if method.start_with?('f_')
29
+
30
+ send("f_#{method}", *args)
31
+ end
32
+ end
33
+ end
data/lib/rfuse/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RFuse
2
- VERSION = "1.2.3"
2
+ VERSION = "2.0.0"
3
3
  end