rfuse 1.0.0
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.
- data/.gitignore +5 -0
- data/CHANGES.md +40 -0
- data/Gemfile +4 -0
- data/LICENSE +340 -0
- data/README.md +61 -0
- data/Rakefile +12 -0
- data/ext/.gitignore +2 -0
- data/ext/rfuse/bufferwrapper.c +48 -0
- data/ext/rfuse/bufferwrapper.h +10 -0
- data/ext/rfuse/context.c +70 -0
- data/ext/rfuse/context.h +5 -0
- data/ext/rfuse/extconf.rb +12 -0
- data/ext/rfuse/file_info.c +140 -0
- data/ext/rfuse/file_info.h +13 -0
- data/ext/rfuse/filler.c +60 -0
- data/ext/rfuse/filler.h +15 -0
- data/ext/rfuse/helper.c +93 -0
- data/ext/rfuse/helper.h +22 -0
- data/ext/rfuse/intern_rfuse.c +84 -0
- data/ext/rfuse/intern_rfuse.h +22 -0
- data/ext/rfuse/pollhandle.c +54 -0
- data/ext/rfuse/pollhandle.h +10 -0
- data/ext/rfuse/rfuse.c +2045 -0
- data/ext/rfuse/rfuse.h +3 -0
- data/ext/rfuse/rfuse_mod.c +12 -0
- data/lib/rfuse/version.rb +3 -0
- data/lib/rfuse-ng.rb +1 -0
- data/lib/rfuse.rb +211 -0
- data/lib/rfuse_ng.rb +3 -0
- data/rfuse.gemspec +26 -0
- data/sample/test-ruby.rb +339 -0
- data/spec/basic_spec.rb +176 -0
- data/spec/fuse_file_info_spec.rb +46 -0
- data/spec/ruby_loop_spec.rb +65 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/xattr_spec.rb +39 -0
- metadata +164 -0
data/ext/rfuse/rfuse.h
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#include "rfuse.h"
|
2
|
+
#include "filler.h"
|
3
|
+
#include "file_info.h"
|
4
|
+
#include "context.h"
|
5
|
+
|
6
|
+
void Init_rfuse() {
|
7
|
+
VALUE mRFuse=rb_define_module("RFuse");
|
8
|
+
file_info_init(mRFuse);
|
9
|
+
context_init(mRFuse);
|
10
|
+
rfiller_init(mRFuse);
|
11
|
+
rfuse_init(mRFuse);
|
12
|
+
}
|
data/lib/rfuse-ng.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rfuse'
|
data/lib/rfuse.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'fcntl'
|
2
|
+
require 'rfuse/version'
|
3
|
+
require 'rfuse/rfuse'
|
4
|
+
|
5
|
+
# Ruby FUSE (Filesystem in USErspace) binding
|
6
|
+
module RFuse
|
7
|
+
|
8
|
+
# Used by listxattr
|
9
|
+
def self.packxattr(xattrs)
|
10
|
+
case xattrs
|
11
|
+
when Array
|
12
|
+
xattrs.join("\000")
|
13
|
+
when String
|
14
|
+
#assume already \0 separated list of keys
|
15
|
+
xattrs
|
16
|
+
else
|
17
|
+
raise RFuse::Error, ":listxattr must return Array or String, got #{xattrs.inspect}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Fuse
|
22
|
+
|
23
|
+
# Main processing loop
|
24
|
+
#
|
25
|
+
# Use {#exit} to stop processing (or externally call fusermount -u)
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# Other ruby threads can continue while loop is running, however
|
29
|
+
# no thread can operate on the filesystem itself (ie with File or Dir methods)
|
30
|
+
#
|
31
|
+
# @return [void]
|
32
|
+
# @raise [RFuse::Error] if already running or not mounted
|
33
|
+
#
|
34
|
+
def loop()
|
35
|
+
raise RFuse::Error, "Already running!" if @running
|
36
|
+
raise RFuse::Error, "FUSE not mounted" unless mounted?
|
37
|
+
@running = true
|
38
|
+
while @running do
|
39
|
+
begin
|
40
|
+
ready, ignore, errors = IO.select([@fuse_io,@pr],[],[@fuse_io])
|
41
|
+
|
42
|
+
if ready.include?(@pr)
|
43
|
+
|
44
|
+
@pr.getc
|
45
|
+
@running = false
|
46
|
+
|
47
|
+
elsif errors.include?(@fuse_io)
|
48
|
+
|
49
|
+
@running = false
|
50
|
+
raise RFuse::Error, "FUSE error"
|
51
|
+
|
52
|
+
elsif ready.include?(@fuse_io)
|
53
|
+
if process() < 0
|
54
|
+
# Fuse has been unmounted externally
|
55
|
+
# TODO: mounted? should now return false
|
56
|
+
# fuse_exited? is not true...
|
57
|
+
@running = false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rescue Interrupt
|
61
|
+
#oh well...
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Stop processing {#loop}
|
67
|
+
# eg called from Signal handlers, or some other monitoring thread
|
68
|
+
def exit
|
69
|
+
@pw.putc(0)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Called by the C iniitialize
|
75
|
+
# afer the filesystem has been mounted successfully
|
76
|
+
def ruby_initialize
|
77
|
+
@pr,@pw = IO.pipe()
|
78
|
+
|
79
|
+
# The FD was created by FUSE so we don't want
|
80
|
+
# ruby to do anything with it during GC
|
81
|
+
@fuse_io = IO.for_fd(fd(),"r",:autoclose => false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#This class is useful to make your filesystem implementation
|
86
|
+
#debuggable and testable without needing to mount an actual filesystem
|
87
|
+
#or inherit from {Fuse}
|
88
|
+
class FuseDelegator < Fuse
|
89
|
+
|
90
|
+
# Available fuse methods -see http://fuse.sourceforge.net/doxygen/structfuse__operations.html
|
91
|
+
# Note :getdir and :utime are deprecated
|
92
|
+
# :ioctl, :poll are not implemented in the C extension
|
93
|
+
FUSE_METHODS = [ :getattr, :readlink, :getdir, :mknod, :mkdir,
|
94
|
+
:unlink, :rmdir, :symlink, :rename, :link,
|
95
|
+
:chmod, :chown, :truncate, :utime, :open,
|
96
|
+
:create, :read, :write, :statfs, :flush,
|
97
|
+
:release, :fsync, :setxattr, :getxattr, :listxattr,:removexattr,
|
98
|
+
:opendir, :readdir, :releasedir, :fsycndir,
|
99
|
+
:init, :destroy, :access, :ftruncate, :fgetattr, :lock,
|
100
|
+
:utimens, :bmap, :ioctl, :poll ]
|
101
|
+
|
102
|
+
# @param [Object] fuse_object your filesystem object that responds to fuse methods
|
103
|
+
# @param [String] mountpoint existing directory where the filesystem will be mounted
|
104
|
+
# @param [String...] options fuse mount options (use "-h" to see a list)
|
105
|
+
#
|
106
|
+
# Create and mount a filesystem
|
107
|
+
#
|
108
|
+
# If ruby debug is enabled then each call to fuse_object will be represented on $stderr
|
109
|
+
def initialize(fuse_object,mountpoint,*options)
|
110
|
+
@fuse_delegate = fuse_object
|
111
|
+
define_fuse_methods(fuse_object)
|
112
|
+
super(mountpoint,options)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def define_fuse_methods(fuse_object)
|
117
|
+
#Wrap all the rfuse methods in a context block
|
118
|
+
FUSE_METHODS.each do |method|
|
119
|
+
if fuse_object.respond_to?(method)
|
120
|
+
method_name = method.id2name
|
121
|
+
instance_eval(<<-EOM, "(__FUSE_DELEGATE__)",1)
|
122
|
+
def #{method_name} (*args,&block)
|
123
|
+
begin
|
124
|
+
$stderr.puts "==> #{ self }.#{ method_name }(\#{args.inspect })" if $DEBUG
|
125
|
+
result = @fuse_delegate.send(:#{method_name},*args,&block)
|
126
|
+
$stderr.puts "<== #{ self }.#{ method_name }()" if $DEBUG
|
127
|
+
result
|
128
|
+
rescue Exception => ex
|
129
|
+
$@.delete_if{|s| /^\\(__FUSE_DELEGATE__\\):/ =~ s}
|
130
|
+
$stderr.puts(ex.message) unless ex.respond_to?(:errno) || $DEBUG
|
131
|
+
Kernel::raise
|
132
|
+
end
|
133
|
+
end
|
134
|
+
EOM
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end #class FuseDelegator
|
140
|
+
|
141
|
+
# Helper class to return from :getattr method
|
142
|
+
class Stat
|
143
|
+
# Format mask
|
144
|
+
S_IFMT = 0170000
|
145
|
+
# Directory
|
146
|
+
S_IFDIR = 0040000
|
147
|
+
# Character device
|
148
|
+
S_IFCHR = 0020000
|
149
|
+
# Block device
|
150
|
+
S_IFBLK = 0060000
|
151
|
+
# Regular file
|
152
|
+
S_IFREG = 0100000
|
153
|
+
# FIFO.
|
154
|
+
S_IFIFO = 0010000
|
155
|
+
# Symbolic link
|
156
|
+
S_IFLNK = 0120000
|
157
|
+
# Socket
|
158
|
+
S_IFSOCK = 0140000
|
159
|
+
|
160
|
+
# @param [Fixnum] mode file permissions
|
161
|
+
# @param [Hash<Symbol,Fixnum>] values initial values for other attributes
|
162
|
+
#
|
163
|
+
# @return [Stat] representing a directory
|
164
|
+
def self.directory(mode=0,values = { })
|
165
|
+
return self.new(S_IFDIR,mode,values)
|
166
|
+
end
|
167
|
+
|
168
|
+
# @param [Fixnum] mode file permissions
|
169
|
+
# @param [Hash<Symbol,Fixnum>] values initial values for other attributes
|
170
|
+
#
|
171
|
+
# @return [Stat] representing a regular file
|
172
|
+
def self.file(mode=0,values = { })
|
173
|
+
return self.new(S_IFREG,mode,values)
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Integer] see stat(2)
|
177
|
+
attr_accessor :uid,:gid,:mode,:size, :dev,:ino,:nlink,:rdev,:blksize,:blocks
|
178
|
+
|
179
|
+
# @return [Integer, Time] see stat(2)
|
180
|
+
attr_accessor :atime,:mtime,:ctime
|
181
|
+
|
182
|
+
def initialize(type,permissions,values = { })
|
183
|
+
values[:mode] = ((type & S_IFMT) | (permissions & 07777))
|
184
|
+
@uid,@gid,@size,@mode,@atime,@mtime,@ctime,@dev,@ino,@nlink,@rdev,@blksize,@blocks = Array.new(13,0)
|
185
|
+
values.each_pair do |k,v|
|
186
|
+
instance_variable_set("@#{ k }",v)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Helper class to return from :statfs (eg for df output)
|
192
|
+
# All attributes are Integers and default to 0
|
193
|
+
class StatVfs
|
194
|
+
|
195
|
+
# @return [Integer]
|
196
|
+
attr_accessor :f_bsize,:f_frsize,:f_blocks,:f_bfree,:f_bavail
|
197
|
+
|
198
|
+
# @return [Integer]
|
199
|
+
attr_accessor :f_files,:f_ffree,:f_favail,:f_fsid,:f_flag,:f_namemax
|
200
|
+
|
201
|
+
# values can be symbols or strings but drop the pointless f_ prefix
|
202
|
+
def initialize(values={ })
|
203
|
+
@f_bsize, @f_frsize, @f_blocks, @f_bfree, @f_bavail, @f_files, @f_ffree, @f_favail,@f_fsid, @f_flag,@f_namemax = Array.new(13,0)
|
204
|
+
values.each_pair do |k,v|
|
205
|
+
prefix = k.startswith?("f_") ? "" : "f_"
|
206
|
+
instance_variable_set("@#{prefix}#{k}",v)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end #Module RFuse
|
data/lib/rfuse_ng.rb
ADDED
data/rfuse.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rfuse/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rfuse"
|
7
|
+
s.version = RFuse::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Grant Gardner"]
|
10
|
+
s.email = ["grant@lastweekend.com.au"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/rfuse"
|
12
|
+
s.summary = %q{Ruby language binding for FUSE}
|
13
|
+
s.description = %q{Ruby language binding for FUSE. It was forked from rfuse and modified for Ruby 1.9.2.}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.extensions = 'ext/rfuse/extconf.rb'
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency("rake")
|
22
|
+
s.add_development_dependency("rspec")
|
23
|
+
s.add_development_dependency("yard")
|
24
|
+
s.add_development_dependency("redcarpet")
|
25
|
+
s.add_development_dependency("ffi-xattr")
|
26
|
+
end
|
data/sample/test-ruby.rb
ADDED
@@ -0,0 +1,339 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# TestFS for RFuse
|
4
|
+
|
5
|
+
require "rfuse"
|
6
|
+
|
7
|
+
class MyDir < Hash
|
8
|
+
attr_accessor :name, :mode , :actime, :modtime, :uid, :gid
|
9
|
+
def initialize(name,mode)
|
10
|
+
@uid=0
|
11
|
+
@gid=0
|
12
|
+
@actime=Time.now
|
13
|
+
@modtime=Time.now
|
14
|
+
@xattr=Hash.new
|
15
|
+
@name=name
|
16
|
+
@mode=mode
|
17
|
+
end
|
18
|
+
|
19
|
+
def stat
|
20
|
+
RFuse::Stat.directory(mode,:uid => uid, :gid => gid, :atime => actime, :mtime => modtime,
|
21
|
+
:size => size)
|
22
|
+
end
|
23
|
+
|
24
|
+
def listxattr()
|
25
|
+
@xattr.keys()
|
26
|
+
end
|
27
|
+
def setxattr(name,value,flag)
|
28
|
+
@xattr[name]=value #TODO:don't ignore flag
|
29
|
+
end
|
30
|
+
def getxattr(name)
|
31
|
+
return @xattr[name]
|
32
|
+
end
|
33
|
+
def removexattr(name)
|
34
|
+
@xattr.delete(name)
|
35
|
+
end
|
36
|
+
def size
|
37
|
+
return 48 #for testing only
|
38
|
+
end
|
39
|
+
def isdir
|
40
|
+
true
|
41
|
+
end
|
42
|
+
def insert_obj(obj,path)
|
43
|
+
d=self.search(File.dirname(path))
|
44
|
+
if d.isdir then
|
45
|
+
d[obj.name]=obj
|
46
|
+
else
|
47
|
+
raise Errno::ENOTDIR.new(d.name)
|
48
|
+
end
|
49
|
+
return d
|
50
|
+
end
|
51
|
+
def remove_obj(path)
|
52
|
+
d=self.search(File.dirname(path))
|
53
|
+
d.delete(File.basename(path))
|
54
|
+
end
|
55
|
+
def search(path)
|
56
|
+
p=path.split('/').delete_if {|x| x==''}
|
57
|
+
if p.length==0 then
|
58
|
+
return self
|
59
|
+
else
|
60
|
+
return self.follow(p)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def follow (path_array)
|
64
|
+
if path_array.length==0 then
|
65
|
+
return self
|
66
|
+
else
|
67
|
+
d=self[path_array.shift]
|
68
|
+
if d then
|
69
|
+
return d.follow(path_array)
|
70
|
+
else
|
71
|
+
raise Errno::ENOENT.new
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def to_s
|
76
|
+
return "Dir: " + @name + "(" + @mode.to_s + ")"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class MyFile
|
81
|
+
attr_accessor :name, :mode, :actime, :modtime, :uid, :gid, :content
|
82
|
+
def initialize(name,mode,uid,gid)
|
83
|
+
@actime=0
|
84
|
+
@modtime=0
|
85
|
+
@xattr=Hash.new
|
86
|
+
@content=""
|
87
|
+
@uid=uid
|
88
|
+
@gid=gid
|
89
|
+
@name=name
|
90
|
+
@mode=mode
|
91
|
+
end
|
92
|
+
|
93
|
+
def stat
|
94
|
+
RFuse::Stat.file(mode,:uid => uid, :gid => gid, :atime => actime, :mtime => modtime,
|
95
|
+
:size => size)
|
96
|
+
end
|
97
|
+
|
98
|
+
def listxattr()
|
99
|
+
@xattr.keys
|
100
|
+
end
|
101
|
+
|
102
|
+
def setxattr(name,value,flag)
|
103
|
+
@xattr[name]=value #TODO:don't ignore flag
|
104
|
+
end
|
105
|
+
|
106
|
+
def getxattr(name)
|
107
|
+
return @xattr[name]
|
108
|
+
end
|
109
|
+
def removexattr(name)
|
110
|
+
@xattr.delete(name)
|
111
|
+
end
|
112
|
+
def size
|
113
|
+
return content.size
|
114
|
+
end
|
115
|
+
def isdir
|
116
|
+
false
|
117
|
+
end
|
118
|
+
def follow(path_array)
|
119
|
+
if path_array.length != 0 then
|
120
|
+
raise Errno::ENOTDIR.new
|
121
|
+
else
|
122
|
+
return self
|
123
|
+
end
|
124
|
+
end
|
125
|
+
def to_s
|
126
|
+
return "File: " + @name + "(" + @mode.to_s + ")"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class MyFuse
|
131
|
+
|
132
|
+
def initialize(root)
|
133
|
+
@root=root
|
134
|
+
end
|
135
|
+
|
136
|
+
# The new readdir way, c+p-ed from getdir
|
137
|
+
def readdir(ctx,path,filler,offset,ffi)
|
138
|
+
d=@root.search(path)
|
139
|
+
if d.isdir then
|
140
|
+
d.each {|name,obj|
|
141
|
+
filler.push(name,obj.stat,0)
|
142
|
+
}
|
143
|
+
else
|
144
|
+
raise Errno::ENOTDIR.new(path)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def getattr(ctx,path)
|
149
|
+
d = @root.search(path)
|
150
|
+
return d.stat
|
151
|
+
end #getattr
|
152
|
+
|
153
|
+
def mkdir(ctx,path,mode)
|
154
|
+
@root.insert_obj(MyDir.new(File.basename(path),mode),path)
|
155
|
+
end #mkdir
|
156
|
+
|
157
|
+
def mknod(ctx,path,mode,major,minor)
|
158
|
+
@root.insert_obj(MyFile.new(File.basename(path),mode,ctx.uid,ctx.gid),path)
|
159
|
+
end #mknod
|
160
|
+
|
161
|
+
def open(ctx,path,ffi)
|
162
|
+
end
|
163
|
+
|
164
|
+
#def release(ctx,path,fi)
|
165
|
+
#end
|
166
|
+
|
167
|
+
#def flush(ctx,path,fi)
|
168
|
+
#end
|
169
|
+
|
170
|
+
def chmod(ctx,path,mode)
|
171
|
+
d=@root.search(path)
|
172
|
+
d.mode=mode
|
173
|
+
end
|
174
|
+
|
175
|
+
def chown(ctx,path,uid,gid)
|
176
|
+
d=@root.search(path)
|
177
|
+
d.uid=uid
|
178
|
+
d.gid=gid
|
179
|
+
end
|
180
|
+
|
181
|
+
def truncate(ctx,path,offset)
|
182
|
+
d=@root.search(path)
|
183
|
+
d.content = d.content[0..offset]
|
184
|
+
end
|
185
|
+
|
186
|
+
def utime(ctx,path,actime,modtime)
|
187
|
+
d=@root.search(path)
|
188
|
+
d.actime=actime
|
189
|
+
d.modtime=modtime
|
190
|
+
end
|
191
|
+
|
192
|
+
def unlink(ctx,path)
|
193
|
+
@root.remove_obj(path)
|
194
|
+
end
|
195
|
+
|
196
|
+
def rmdir(ctx,path)
|
197
|
+
@root.remove_obj(path)
|
198
|
+
end
|
199
|
+
|
200
|
+
#def symlink(ctx,path,as)
|
201
|
+
#end
|
202
|
+
|
203
|
+
def rename(ctx,path,as)
|
204
|
+
d = @root.search(path)
|
205
|
+
@root.remove_obj(path)
|
206
|
+
@root.insert_obj(d,path)
|
207
|
+
end
|
208
|
+
|
209
|
+
#def link(ctx,path,as)
|
210
|
+
#end
|
211
|
+
|
212
|
+
def read(ctx,path,size,offset,fi)
|
213
|
+
d = @root.search(path)
|
214
|
+
if (d.isdir)
|
215
|
+
raise Errno::EISDIR.new(path)
|
216
|
+
return nil
|
217
|
+
else
|
218
|
+
return d.content[offset..offset + size - 1]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def write(ctx,path,buf,offset,fi)
|
223
|
+
d=@root.search(path)
|
224
|
+
if (d.isdir)
|
225
|
+
raise Errno::EISDIR.new(path)
|
226
|
+
else
|
227
|
+
d.content[offset..offset+buf.length - 1] = buf
|
228
|
+
end
|
229
|
+
return buf.length
|
230
|
+
end
|
231
|
+
|
232
|
+
def setxattr(ctx,path,name,value,size,flags)
|
233
|
+
d=@root.search(path)
|
234
|
+
d.setxattr(name,value,flags)
|
235
|
+
end
|
236
|
+
|
237
|
+
def getxattr(ctx,path,name)
|
238
|
+
d=@root.search(path)
|
239
|
+
if (d)
|
240
|
+
value=d.getxattr(name)
|
241
|
+
if (!value)
|
242
|
+
value=""
|
243
|
+
#raise Errno::ENOENT.new #TODO raise the correct error :
|
244
|
+
#NOATTR which is not implemented in Linux/glibc
|
245
|
+
end
|
246
|
+
else
|
247
|
+
raise Errno::ENOENT.new
|
248
|
+
end
|
249
|
+
return value
|
250
|
+
end
|
251
|
+
|
252
|
+
def listxattr(ctx,path)
|
253
|
+
d=@root.search(path)
|
254
|
+
value= d.listxattr()
|
255
|
+
return value
|
256
|
+
end
|
257
|
+
|
258
|
+
def removexattr(ctx,path,name)
|
259
|
+
d=@root.search(path)
|
260
|
+
d.removexattr(name)
|
261
|
+
end
|
262
|
+
|
263
|
+
#def opendir(ctx,path,ffi)
|
264
|
+
#end
|
265
|
+
|
266
|
+
#def releasedir(ctx,path,ffi)
|
267
|
+
#end
|
268
|
+
|
269
|
+
#def fsyncdir(ctx,path,meta,ffi)
|
270
|
+
#end
|
271
|
+
|
272
|
+
# Some random numbers to show with df command
|
273
|
+
def statfs(ctx,path)
|
274
|
+
s = RFuse::StatVfs.new()
|
275
|
+
s.f_bsize = 1024
|
276
|
+
s.f_frsize = 1024
|
277
|
+
s.f_blocks = 1000000
|
278
|
+
s.f_bfree = 500000
|
279
|
+
s.f_bavail = 990000
|
280
|
+
s.f_files = 10000
|
281
|
+
s.f_ffree = 9900
|
282
|
+
s.f_favail = 9900
|
283
|
+
s.f_fsid = 23423
|
284
|
+
s.f_flag = 0
|
285
|
+
s.f_namemax = 10000
|
286
|
+
return s
|
287
|
+
end
|
288
|
+
|
289
|
+
def ioctl(ctx, path, cmd, arg, ffi, flags, data)
|
290
|
+
# FT: I was not been able to test it.
|
291
|
+
print "*** IOCTL: command: ", cmd, "\n"
|
292
|
+
end
|
293
|
+
|
294
|
+
def poll(ctx, path, ffi, ph, reventsp)
|
295
|
+
print "*** POLL: ", path, "\n"
|
296
|
+
# This is how we notify the caller if something happens:
|
297
|
+
ph.notifyPoll();
|
298
|
+
# when the GC harvests the object it calls fuse_pollhandle_destroy
|
299
|
+
# by itself.
|
300
|
+
end
|
301
|
+
|
302
|
+
def init(ctx,rfuseconninfo)
|
303
|
+
print "RFuse TestFS started\n"
|
304
|
+
print "init called\n"
|
305
|
+
print "proto_major:#{rfuseconninfo.proto_major}\n"
|
306
|
+
end
|
307
|
+
|
308
|
+
end #class Fuse
|
309
|
+
|
310
|
+
if ARGV.length == 0
|
311
|
+
print "\n"
|
312
|
+
print "Usage: [ruby [--debug]] #{$0} mountpoint [mount_options...]\n"
|
313
|
+
print "\n"
|
314
|
+
print " mountpoint must be an existing directory\n"
|
315
|
+
print " mount_option '-h' will list supported options\n"
|
316
|
+
print "\n"
|
317
|
+
print " For verbose debugging output use --debug to ruby\n"
|
318
|
+
print " and '-odebug' as mount_option\n"
|
319
|
+
print "\n"
|
320
|
+
exit(1)
|
321
|
+
end
|
322
|
+
|
323
|
+
fs = MyFuse.new(MyDir.new("",0777));
|
324
|
+
|
325
|
+
fo = RFuse::FuseDelegator.new(fs,*ARGV)
|
326
|
+
|
327
|
+
if fo.mounted?
|
328
|
+
Signal.trap("TERM") { print "Caught TERM\n" ; fo.exit }
|
329
|
+
Signal.trap("INT") { print "Caught INT\n"; fo.exit }
|
330
|
+
|
331
|
+
begin
|
332
|
+
fo.loop
|
333
|
+
rescue
|
334
|
+
print "Error:" + $!
|
335
|
+
ensure
|
336
|
+
fo.unmount if fo.mounted?
|
337
|
+
print "Unmounted #{ARGV[0]}\n"
|
338
|
+
end
|
339
|
+
end
|