rfusefs 0.8.0 → 1.0.0.RC0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  module FuseFS
2
2
 
3
3
  # A FuseFS over an existing directory
4
- class DirLink
4
+ class DirLink < FuseDir
5
5
 
6
6
  def initialize(dir)
7
7
  File.directory?(dir) or raise ArgumentError, "DirLink.initialize expects a valid directory!"
@@ -1,244 +1,244 @@
1
1
  module FuseFS
2
-
3
-
4
-
5
- # A full in-memory filesystem defined with hashes. It is writable to the
6
- # user that mounted it
7
- # may create and edit files within it, as well as the programmer
8
- # === Usage
9
- # root = Metadir.new()
10
- # root.mkdir("/hello")
11
- # root.write_to("/hello/world","Hello World!\n")
12
- # root.write_to("/hello/everybody","Hello Everyone!\n")
13
- #
14
- # FuseFS.start(mntpath,root)
15
- #
16
- # Because Metadir is fully recursive, you can mount your own or other defined
17
- # directory structures under it. For example, to mount a dictionary filesystem
18
- # (see samples/dictfs.rb), use:
19
- #
20
- # root.mkdir("/dict",DictFS.new())
21
- #
22
- class MetaDir < FuseDir
23
-
24
- def initialize()
25
- @subdirs = Hash.new(nil)
26
- @files = Hash.new(nil)
27
- end
28
-
29
- def directory?(path)
30
- pathmethod(:directory?,path) do |filename|
31
- !filename || filename == "/" || @subdirs.has_key?(filename)
32
- end
33
- end
34
-
35
- def file?(path)
36
- pathmethod(:file?,path) do |filename|
37
- @files.has_key?(filename)
38
- end
39
- end
40
-
41
- #List directory contents
42
- def contents(path)
43
- pathmethod(:contents,path) do | filename |
44
- if !filename
45
- (@files.keys + @subdirs.keys).sort.uniq
46
- else
47
- @subdirs[filename].contents("/")
48
- end
49
- end
50
- end
51
-
52
- def read_file(path)
53
- pathmethod(:read_file,path) do |filename|
54
- @files[filename].to_s
55
- end
56
- end
57
-
58
- def size(path)
59
- pathmethod(:size,path) do | filename |
60
- return @files[filename].to_s.length
61
- end
62
- end
63
-
64
- #can_write only applies to files... see can_mkdir for directories...
65
- def can_write?(path)
66
- # we have to recurse here because it might not be a MetaDir at
67
- # the end of the path, but we don't have to check it is a file
68
- # as the API guarantees that
69
- pathmethod(:can_write?,path) do |filename|
70
- return mount_user?
71
- end
72
- end
73
-
74
- def write_to(path,contents)
75
- pathmethod(:write_to,path,contents) do |filename, filecontents |
76
- @files[filename] = filecontents
77
- end
78
- end
79
-
80
- # Delete a file
81
- def can_delete?(path)
82
- pathmethod(:can_delete?,path) do |filename|
83
- return mount_user?
84
- end
85
- end
86
-
87
- def delete(path)
88
- pathmethod(:delete,path) do |filename|
89
- @files.delete(filename)
90
- end
91
- end
92
-
93
-
94
- #mkdir - does not make intermediate dirs!
95
- def can_mkdir?(path)
96
- pathmethod(:can_mkdir?,path) do |dirname|
97
- return mount_user?
98
- end
99
- end
100
-
101
- def mkdir(path,dir=nil)
102
- pathmethod(:mkdir,path,dir) do | dirname,dirobj |
103
- dirobj ||= MetaDir.new
104
- @subdirs[dirname] = dirobj
105
- end
106
- end
107
-
108
- # Delete an existing directory make sure it is not empty
109
- def can_rmdir?(path)
110
- pathmethod(:can_rmdir?,path) do |dirname|
111
- return mount_user? && @subdirs.has_key?(dirname) && @subdirs[dirname].contents("/").empty?
112
- end
113
- end
114
-
115
- def rmdir(path)
116
- pathmethod(:rmdir,path) do |dirname|
117
- @subdirs.delete(dirname)
118
- end
119
- end
120
-
121
- def rename(from_path,to_path,to_fusefs = self)
122
-
123
- from_base,from_rest = split_path(from_path)
124
-
125
- case
126
- when !from_base
127
- # Shouldn't ever happen.
128
- raise Errno::EACCES.new("Can't move root")
129
- when !from_rest
130
- # So now we have a file or directory to move
131
- if @files.has_key?(from_base)
132
- return false unless can_delete?(from_base) && to_fusefs.can_write?(to_path)
133
- to_fusefs.write_to(to_path,@files[from_base])
134
- @files.delete(from_base)
135
- elsif @subdirs.has_key?(from_base)
136
- # we don't check can_rmdir? because that would prevent us
137
- # moving non empty directories
138
- return false unless mount_user? && to_fusefs.can_mkdir?(to_path)
139
- begin
140
- to_fusefs.mkdir(to_path,@subdirs[from_base])
141
- @subdirs.delete(from_base)
142
- rescue ArgumentError
143
- # to_rest does not support mkdir with an arbitrary object
144
- return false
145
- end
146
- else
147
- #We shouldn't get this either
148
- return false
149
- end
150
- when @subdirs.has_key?(from_base)
151
- begin
152
- if to_fusefs != self
153
- #just keep recursing..
154
- return @subdirs[from_base].rename(from_rest,to_path,to_fusefs)
155
- else
156
- to_base,to_rest = split_path(to_path)
157
- if from_base == to_base
158
- #mv within a subdir, just pass it on
159
- return @subdirs[from_base].rename(from_rest,to_rest)
2
+
3
+ # A full in-memory filesystem defined with hashes. It is writable to the
4
+ # user that mounted it
5
+ # may create and edit files within it, as well as the programmer
6
+ # === Usage
7
+ # root = Metadir.new()
8
+ # root.mkdir("/hello")
9
+ # root.write_to("/hello/world","Hello World!\n")
10
+ # root.write_to("/hello/everybody","Hello Everyone!\n")
11
+ #
12
+ # FuseFS.start(mntpath,root)
13
+ #
14
+ # Because Metadir is fully recursive, you can mount your own or other defined
15
+ # directory structures under it. For example, to mount a dictionary filesystem
16
+ # (see samples/dictfs.rb), use:
17
+ #
18
+ # root.mkdir("/dict",DictFS.new())
19
+ #
20
+ class MetaDir
21
+
22
+ DEFAULT_FS = FuseDir.new()
23
+
24
+ def initialize()
25
+ @subdirs = Hash.new(nil)
26
+ @files = Hash.new(nil)
27
+ end
28
+
29
+ def split_path(path)
30
+ DEFAULT_FS.split_path(path)
31
+ end
32
+
33
+ def scan_path
34
+ DEFAULT_FS.scan_path(path)
35
+ end
36
+
37
+ def directory?(path)
38
+ pathmethod(:directory?,path) do |filename|
39
+ !filename || filename == "/" || @subdirs.has_key?(filename)
40
+ end
41
+ end
42
+
43
+ def file?(path)
44
+ pathmethod(:file?,path) do |filename|
45
+ @files.has_key?(filename)
46
+ end
47
+ end
48
+
49
+ #List directory contents
50
+ def contents(path)
51
+ pathmethod(:contents,path) do | filename |
52
+ if !filename
53
+ (@files.keys + @subdirs.keys).sort.uniq
54
+ else
55
+ @subdirs[filename].contents("/")
56
+ end
57
+ end
58
+ end
59
+
60
+ def read_file(path)
61
+ pathmethod(:read_file,path) do |filename|
62
+ @files[filename].to_s
63
+ end
64
+ end
65
+
66
+ def size(path)
67
+ pathmethod(:size,path) do | filename |
68
+ return @files[filename].to_s.length
69
+ end
70
+ end
71
+
72
+ #can_write only applies to files... see can_mkdir for directories...
73
+ def can_write?(path)
74
+ pathmethod(:can_write?,path) do |filename|
75
+ return mount_user?
76
+ end
77
+ end
78
+
79
+ def write_to(path,contents)
80
+ pathmethod(:write_to,path,contents) do |filename, filecontents |
81
+ @files[filename] = filecontents
82
+ end
83
+ end
84
+
85
+ # Delete a file
86
+ def can_delete?(path)
87
+ pathmethod(:can_delete?,path) do |filename|
88
+ return mount_user?
89
+ end
90
+ end
91
+
92
+ def delete(path)
93
+ pathmethod(:delete,path) do |filename|
94
+ @files.delete(filename)
95
+ end
96
+ end
97
+
98
+ #mkdir - does not make intermediate dirs!
99
+ def can_mkdir?(path)
100
+ pathmethod(:can_mkdir?,path) do |dirname|
101
+ return mount_user?
102
+ end
103
+ end
104
+
105
+ def mkdir(path,dir=nil)
106
+ pathmethod(:mkdir,path,dir) do | dirname,dirobj |
107
+ dirobj ||= MetaDir.new
108
+ @subdirs[dirname] = dirobj
109
+ end
110
+ end
111
+
112
+ # Delete an existing directory make sure it is not empty
113
+ def can_rmdir?(path)
114
+ pathmethod(:can_rmdir?,path) do |dirname|
115
+ return mount_user? && @subdirs.has_key?(dirname) && @subdirs[dirname].contents("/").empty?
116
+ end
117
+ end
118
+
119
+ def rmdir(path)
120
+ pathmethod(:rmdir,path) do |dirname|
121
+ @subdirs.delete(dirname)
122
+ end
123
+ end
124
+
125
+ def rename(from_path,to_path,to_fusefs = self)
126
+
127
+ from_base,from_rest = split_path(from_path)
128
+
129
+ case
130
+ when !from_base
131
+ # Shouldn't ever happen.
132
+ raise Errno::EACCES.new("Can't move root")
133
+ when !from_rest
134
+ # So now we have a file or directory to move
135
+ if @files.has_key?(from_base)
136
+ return false unless can_delete?(from_base) && to_fusefs.can_write?(to_path)
137
+ to_fusefs.write_to(to_path,@files[from_base])
138
+ @files.delete(from_base)
139
+ elsif @subdirs.has_key?(from_base)
140
+ # we don't check can_rmdir? because that would prevent us
141
+ # moving non empty directories
142
+ return false unless mount_user? && to_fusefs.can_mkdir?(to_path)
143
+ begin
144
+ to_fusefs.mkdir(to_path,@subdirs[from_base])
145
+ @subdirs.delete(from_base)
146
+ rescue ArgumentError
147
+ # to_rest does not support mkdir with an arbitrary object
148
+ return false
149
+ end
150
+ else
151
+ #We shouldn't get this either
152
+ return false
153
+ end
154
+ when @subdirs.has_key?(from_base)
155
+ begin
156
+ if to_fusefs != self
157
+ #just keep recursing..
158
+ return @subdirs[from_base].rename(from_rest,to_path,to_fusefs)
159
+ else
160
+ to_base,to_rest = split_path(to_path)
161
+ if from_base == to_base
162
+ #mv within a subdir, just pass it on
163
+ return @subdirs[from_base].rename(from_rest,to_rest)
164
+ else
165
+ #OK, this is the tricky part, we want to move something further down
166
+ #our tree into something in another part of the tree.
167
+ #from this point on we keep a reference to the fusefs that owns
168
+ #to_path (ie us) and pass it down, but only if the eventual path
169
+ #is writable anyway!
170
+ if (file?(to_path))
171
+ return false unless can_write?(to_path)
172
+ else
173
+ return false unless can_mkdir?(to_path)
174
+ end
175
+
176
+ return @subdirs[from_base].rename(from_rest,to_path,self)
177
+ end
178
+ end
179
+ rescue NoMethodError
180
+ #sub dir doesn't support rename
181
+ return false
182
+ rescue ArgumentError
183
+ #sub dir doesn't support rename with additional to_fusefs argument
184
+ return false
185
+ end
160
186
  else
161
- #OK, this is the tricky part, we want to move something further down
162
- #our tree into something in another part of the tree.
163
- #from this point on we keep a reference to the fusefs that owns
164
- #to_path (ie us) and pass it down, but only if the eventual path
165
- #is writable anyway!
166
- if (file?(to_path))
167
- return false unless can_write?(to_path)
168
- else
169
- return false unless can_mkdir?(to_path)
170
- end
171
-
172
- return @subdirs[from_base].rename(from_rest,to_path,self)
173
- end
174
- end
175
-
176
-
177
- rescue NoMethodError
178
- #sub dir doesn't support rename
179
- return false
180
- rescue ArgumentError
181
- #sub dir doesn't support rename with additional to_fusefs argument
182
- return false
183
- end
184
- else
185
- return false
186
- end
187
- end
188
-
189
- private
190
-
191
- # If api method not explicitly defined above, then pass it on
192
- # to a potential FuseFS further down the chain
193
- # If that turns out to be one of us then return the default
194
- def method_missing(method,*args)
195
- if (RFuseFSAPI::API_METHODS.has_key?(method))
196
- pathmethod(method,*args) do
197
- return RFuseFS::API_METHODS[method]
198
- end
199
- else
200
- super
201
- end
202
- end
203
- # is the accessing user the same as the user that mounted our FS?, used for
204
- # all write activity
205
- def mount_user?
206
- return Process.uid == FuseFS.reader_uid
207
- end
208
-
209
- #All our FuseFS methods follow the same pattern...
210
- def pathmethod(method, path,*args)
211
- base,rest = split_path(path)
212
- case
213
- when ! base
214
- #request for the root of our fs
215
- yield(nil,*args)
216
- when ! rest
217
- #base is the filename, no more directories to traverse
218
- yield(base,*args)
219
- when @subdirs.has_key?(base)
220
- #base is a subdirectory, pass it on if we can
221
- begin
222
- @subdirs[base].send(method,rest,*args)
223
- rescue NoMethodError
224
- #Oh well
225
- return RFuseFSAPI::API_METHODS[method]
226
- rescue ArgumentError
227
- #can_mkdir,mkdir
228
- if args.pop.nil?
229
- #possibly a default arg, try sending again with one fewer arg
230
- @subdirs[base].send(method,rest,*args)
231
- else
232
- #definitely not a default arg, reraise
233
- Kernel.raise
234
- end
235
- end
236
- else
237
- #return the default response
238
- return RFuseFSAPI::API_METHODS[method]
239
- end
187
+ return false
188
+ end
189
+ end
190
+
191
+ default_methods = FuseDir.public_instance_methods.select { |m|
192
+ !self.public_method_defined?(m) && FuseDir.instance_method(m).owner == FuseDir
193
+ }
194
+
195
+ default_methods.each do |m|
196
+ define_method(m) do |*args|
197
+ pathmethod(m,*args) { |*args| DEFAULT_FS.send(m,*args) }
198
+ end
199
+ end
200
+
201
+ private
202
+ # is the accessing user the same as the user that mounted our FS?, used for
203
+ # all write activity
204
+ def mount_user?
205
+ return Process.uid == FuseFS.reader_uid
206
+ end
207
+
208
+ #All our FuseFS methods follow the same pattern...
209
+ def pathmethod(method, path,*args)
210
+ base,rest = split_path(path)
211
+
212
+ case
213
+ when ! base
214
+ #request for the root of our fs
215
+ yield(nil,*args)
216
+ when ! rest
217
+ #base is the filename, no more directories to traverse
218
+ yield(base,*args)
219
+ when @subdirs.has_key?(base)
220
+ #base is a subdirectory, pass it on if we can
221
+ begin
222
+ @subdirs[base].send(method,rest,*args)
223
+ rescue NoMethodError
224
+ #Oh well
225
+ return DEFAULT_FS.send(method,rest,*args)
226
+ rescue ArgumentError
227
+ #can_mkdir,mkdir
228
+ if args.pop.nil?
229
+ #possibly a default arg, try sending again with one fewer arg
230
+ @subdirs[base].send(method,rest,*args)
231
+ else
232
+ #definitely not a default arg, reraise
233
+ Kernel.raise
234
+ end
235
+ end
236
+ else
237
+ #return the default response
238
+ return DEFAULT_FS.send(method,path,*args)
239
+ end
240
+ end
241
+
242
+
240
243
  end
241
-
242
-
243
- end
244
244
  end