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