rfusefs 0.8.0 → 1.0.0.RC0

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.
@@ -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