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.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/History.rdoc +20 -0
- data/README.rdoc +20 -15
- data/Rakefile +10 -17
- data/TODO.txt +1 -2
- data/lib/fuse/fusedir.rb +202 -0
- data/lib/fuse/rfusefs-fuse.rb +402 -482
- data/lib/fusefs/dirlink.rb +1 -1
- data/lib/fusefs/metadir.rb +240 -240
- data/lib/fusefs/pathmapper.rb +189 -188
- data/lib/rfusefs/version.rb +3 -0
- data/lib/rfusefs.rb +109 -301
- data/samples/demo.rb +9 -14
- data/samples/dictfs.rb +4 -14
- data/samples/hello.rb +1 -2
- data/spec/metadir_spec.rb +295 -0
- data/spec/pathmapper_spec.rb +112 -0
- data/spec/rfusefs_spec.rb +77 -76
- data/spec/sample_spec.rb +3 -2
- data/spec/spec_helper.rb +7 -1
- metadata +112 -124
- data/.gemtest +0 -0
- data/History.txt +0 -9
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -1
data/lib/fusefs/pathmapper.rb
CHANGED
@@ -1,193 +1,194 @@
|
|
1
1
|
|
2
2
|
module FuseFS
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
3
|
+
|
4
|
+
# A FuseFS that maps files from files from their original location into a new path
|
5
|
+
# eg tagged audio files can be mapped by title etc...
|
6
|
+
class PathMapperFS < FuseDir
|
7
|
+
# Convert raw_mode strings to IO open mode strings
|
8
|
+
def self.open_mode(raw_mode)
|
9
|
+
case raw_mode
|
10
|
+
when "r"
|
11
|
+
"r"
|
12
|
+
when "ra"
|
13
|
+
"r" #not really sensible..
|
14
|
+
when "rw"
|
15
|
+
"w+"
|
16
|
+
when "rwa"
|
17
|
+
"a+"
|
18
|
+
when
|
19
|
+
"w"
|
20
|
+
when "wa"
|
21
|
+
"a"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
attr_accessor :use_raw_file_access, :allow_write
|
25
|
+
#Creates a PathMapperFS
|
26
|
+
#See #mapDirectory
|
27
|
+
def PathMapperFS.create(dir,options={ },&block)
|
28
|
+
pm_fs = PathMapperFS.new(options)
|
29
|
+
pm_fs.mapDirectory(dir) do |file|
|
30
|
+
block.call(file)
|
31
|
+
end
|
32
|
+
return pm_fs
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(options = { })
|
36
|
+
@root = { }
|
37
|
+
@use_raw_file_access = options[:use_raw_file_access]
|
38
|
+
@allow_write = options[:allow_write]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Adds new_path to our list of mapped files
|
42
|
+
#
|
43
|
+
# Returns a hash entry which stores the real_path under the :pm_real_path key.
|
44
|
+
def mapFile(real_path,new_path)
|
45
|
+
#split path into components
|
46
|
+
components = new_path.scan(/[^\/]+/)
|
47
|
+
|
48
|
+
#create a hash of hashes to represent our directory structure
|
49
|
+
new_file = components.inject(@root) { |directory, file|
|
50
|
+
directory[file] ||= Hash.new()
|
51
|
+
}
|
52
|
+
new_file[:pm_real_path] = real_path
|
53
|
+
return new_file
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convenience method to recursively map all files according to the given block
|
57
|
+
def mapDirectory(*dirs)
|
58
|
+
require 'find'
|
59
|
+
Find.find(*dirs) do |file|
|
60
|
+
new_path = yield file
|
61
|
+
mapFile(file,new_path) if new_path
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Takes a mapped file name and returns the original real_path
|
66
|
+
def unmap(path)
|
67
|
+
possible_file = node(path)
|
68
|
+
return possible_file ? possible_file[:pm_real_path] : nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns true for any directory referenced by a mapped file
|
72
|
+
# See FuseFS API.txt
|
73
|
+
def directory?(path)
|
74
|
+
possible_dir = node(path)
|
75
|
+
possible_dir && !possible_dir[:pm_real_path]
|
76
|
+
end
|
77
|
+
|
78
|
+
# See FuseFS API.txt
|
79
|
+
# expects to be called only if directory? returns true
|
80
|
+
def contents(path)
|
81
|
+
node(path).keys
|
82
|
+
end
|
83
|
+
|
84
|
+
# See FuseFS API.txt
|
85
|
+
def file?(path)
|
86
|
+
filename = unmap(path)
|
87
|
+
filename && File.file?(filename)
|
88
|
+
end
|
89
|
+
|
90
|
+
# See FuseFS API.txt
|
91
|
+
# only called if option :raw_reads is not set
|
92
|
+
def read_file(path)
|
93
|
+
IO.read(unmap(path))
|
94
|
+
end
|
95
|
+
|
96
|
+
# We can only write to existing files
|
97
|
+
# because otherwise we don't have anything to back it
|
98
|
+
def can_write?(path)
|
99
|
+
@allow_write && file?(path)
|
100
|
+
end
|
101
|
+
|
102
|
+
# TODO: This can't possibly work- the path is not unmapped
|
103
|
+
# and we don't open the file for writing
|
104
|
+
def write_to(path,contents)
|
105
|
+
File.open(path) do |f|
|
106
|
+
f.print(contents)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# See FuseFS API.txt
|
111
|
+
def size(path)
|
112
|
+
File.size(unmap(path))
|
113
|
+
end
|
114
|
+
|
115
|
+
# See RFuseFS API.txt
|
116
|
+
def times(path)
|
117
|
+
realpath = unmap(path)
|
118
|
+
if (realpath)
|
119
|
+
stat = File.stat(realpath)
|
120
|
+
return [ stat.atime, stat.mtime, stat.ctime ]
|
121
|
+
else
|
122
|
+
# We're a directory
|
123
|
+
return [0,0,0]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# See FuseFS API.txt
|
128
|
+
# Will create, store and return a File object for the underlying file
|
129
|
+
# for subsequent use with the raw_read/raw_close methods
|
130
|
+
# expects file? to return true before this method is called
|
131
|
+
def raw_open(path,mode,rfusefs = nil)
|
132
|
+
|
133
|
+
return false unless @use_raw_file_access
|
134
|
+
|
135
|
+
return false if mode.include?("w") && (!@allow_writes)
|
136
|
+
|
137
|
+
@openfiles ||= Hash.new() unless rfusefs
|
138
|
+
|
139
|
+
real_path = unmap(path)
|
140
|
+
|
141
|
+
unless real_path
|
142
|
+
if rfusefs
|
143
|
+
raise Errno::ENOENT.new(path)
|
144
|
+
else
|
145
|
+
#fusefs will go on to call file?
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
file = File.new(real_path,PathMapperFS.open_mode(mode))
|
151
|
+
|
152
|
+
@openfiles[path] = file unless rfusefs
|
153
|
+
|
154
|
+
return file
|
155
|
+
end
|
156
|
+
|
157
|
+
# See (R)FuseFS API.txt
|
158
|
+
def raw_read(path,off,sz,file=nil)
|
159
|
+
file = @openfiles[path] unless file
|
160
|
+
file.sysseek(off)
|
161
|
+
file.sysread(sz)
|
162
|
+
end
|
163
|
+
|
164
|
+
# See (R)FuseFS API.txt
|
165
|
+
def raw_write(path,offset,sz,buf,file=nil)
|
166
|
+
file = @openfiles[path] unless file
|
167
|
+
file.sysseek(off)
|
168
|
+
file.syswrite(buf[0,sz])
|
169
|
+
end
|
170
|
+
|
171
|
+
# See (R)FuseFS API.txt
|
172
|
+
def raw_close(path,file=nil)
|
173
|
+
unless file
|
174
|
+
file = @openfiles.delete(path)
|
175
|
+
end
|
176
|
+
file.close if file
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
# returns a hash representing a given node, if we have a mapped entry for it, nil otherwise
|
181
|
+
# this entry is a file if it has_key?(:pm_real_path), otherwise it is a directory.
|
182
|
+
def node(path)
|
183
|
+
path_components = scan_path(path)
|
184
|
+
|
185
|
+
#not actually injecting anything here, we're just following the hash of hashes...
|
186
|
+
path_components.inject(@root) { |dir,file|
|
187
|
+
break unless dir[file]
|
188
|
+
dir[file]
|
189
|
+
}
|
190
|
+
end
|
189
191
|
end
|
190
|
-
|
191
|
-
|
192
|
+
|
192
193
|
end
|
193
194
|
|