fusefs 0.7.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/.document +5 -0
- data/.gitignore +11 -0
- data/API.txt +279 -0
- data/Changes.txt +63 -0
- data/LICENSE +20 -0
- data/README +46 -0
- data/Rakefile +56 -0
- data/TODO +11 -0
- data/VERSION +1 -0
- data/ext/MANIFEST +4 -0
- data/ext/extconf.rb +7 -0
- data/ext/fusefs_fuse.c +149 -0
- data/ext/fusefs_fuse.h +19 -0
- data/ext/fusefs_lib.c +1514 -0
- data/fusefs.gemspec +69 -0
- data/hello.sh +10 -0
- data/lib/fusefs.rb +244 -0
- data/sample/demo.rb +100 -0
- data/sample/dictfs.rb +84 -0
- data/sample/hello.rb +27 -0
- data/sample/openurifs.rb +53 -0
- data/sample/railsfs.rb +77 -0
- data/sample/sqlfs.rb +134 -0
- data/sample/yamlfs.rb +168 -0
- data/test/fusefs_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +83 -0
data/fusefs.gemspec
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{fusefs}
|
8
|
+
s.version = "0.7.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Shane"]
|
12
|
+
s.date = %q{2010-03-15}
|
13
|
+
s.description = %q{Gemified}
|
14
|
+
s.email = %q{shane@duairc.com}
|
15
|
+
s.extensions = ["ext/extconf.rb"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE",
|
18
|
+
"README",
|
19
|
+
"TODO"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"API.txt",
|
25
|
+
"Changes.txt",
|
26
|
+
"LICENSE",
|
27
|
+
"README",
|
28
|
+
"Rakefile",
|
29
|
+
"TODO",
|
30
|
+
"VERSION",
|
31
|
+
"ext/MANIFEST",
|
32
|
+
"ext/extconf.rb",
|
33
|
+
"ext/fusefs_fuse.c",
|
34
|
+
"ext/fusefs_fuse.h",
|
35
|
+
"ext/fusefs_lib.c",
|
36
|
+
"fusefs.gemspec",
|
37
|
+
"hello.sh",
|
38
|
+
"lib/fusefs.rb",
|
39
|
+
"sample/demo.rb",
|
40
|
+
"sample/dictfs.rb",
|
41
|
+
"sample/hello.rb",
|
42
|
+
"sample/openurifs.rb",
|
43
|
+
"sample/railsfs.rb",
|
44
|
+
"sample/sqlfs.rb",
|
45
|
+
"sample/yamlfs.rb",
|
46
|
+
"test/fusefs_test.rb",
|
47
|
+
"test/test_helper.rb"
|
48
|
+
]
|
49
|
+
s.homepage = %q{http://github.com/duairc/fusefs}
|
50
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
51
|
+
s.require_paths = ["lib"]
|
52
|
+
s.rubygems_version = %q{1.3.5}
|
53
|
+
s.summary = %q{fusefs}
|
54
|
+
s.test_files = [
|
55
|
+
"test/test_helper.rb",
|
56
|
+
"test/fusefs_test.rb"
|
57
|
+
]
|
58
|
+
|
59
|
+
if s.respond_to? :specification_version then
|
60
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
61
|
+
s.specification_version = 3
|
62
|
+
|
63
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
64
|
+
else
|
65
|
+
end
|
66
|
+
else
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
data/hello.sh
ADDED
data/lib/fusefs.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# FuseFS.rb
|
2
|
+
#
|
3
|
+
# The ruby portion of FuseFS main library
|
4
|
+
#
|
5
|
+
# This includes helper functions, common uses, etc.
|
6
|
+
|
7
|
+
require File.dirname(__FILE__) + '/../ext/fusefs_lib'
|
8
|
+
|
9
|
+
module FuseFS
|
10
|
+
@running = true
|
11
|
+
def FuseFS.run
|
12
|
+
fd = FuseFS.fuse_fd
|
13
|
+
begin
|
14
|
+
io = IO.for_fd(fd)
|
15
|
+
rescue Errno::EBADF
|
16
|
+
raise "fuse is not mounted"
|
17
|
+
end
|
18
|
+
while @running
|
19
|
+
IO.select([io])
|
20
|
+
FuseFS.process
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def FuseFS.unmount
|
24
|
+
system("umount #{@mountpoint}")
|
25
|
+
end
|
26
|
+
def FuseFS.exit
|
27
|
+
@running = false
|
28
|
+
end
|
29
|
+
class FuseDir
|
30
|
+
def split_path(path)
|
31
|
+
cur, *rest = path.scan(/[^\/]+/)
|
32
|
+
if rest.empty?
|
33
|
+
[ cur, nil ]
|
34
|
+
else
|
35
|
+
[ cur, File.join(rest) ]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
def scan_path(path)
|
39
|
+
path.scan(/[^\/]+/)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
class MetaDir < FuseDir
|
43
|
+
def initialize
|
44
|
+
@subdirs = Hash.new(nil)
|
45
|
+
@files = Hash.new(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Contents of directory.
|
49
|
+
def contents(path)
|
50
|
+
base, rest = split_path(path)
|
51
|
+
case
|
52
|
+
when base.nil?
|
53
|
+
(@files.keys + @subdirs.keys).sort.uniq
|
54
|
+
when ! @subdirs.has_key?(base)
|
55
|
+
nil
|
56
|
+
when rest.nil?
|
57
|
+
@subdirs[base].contents('/')
|
58
|
+
else
|
59
|
+
@subdirs[base].contents(rest)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# File types
|
64
|
+
def directory?(path)
|
65
|
+
base, rest = split_path(path)
|
66
|
+
case
|
67
|
+
when base.nil?
|
68
|
+
true
|
69
|
+
when ! @subdirs.has_key?(base)
|
70
|
+
false
|
71
|
+
when rest.nil?
|
72
|
+
true
|
73
|
+
else
|
74
|
+
@subdirs[base].directory?(rest)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
def file?(path)
|
78
|
+
base, rest = split_path(path)
|
79
|
+
case
|
80
|
+
when base.nil?
|
81
|
+
false
|
82
|
+
when rest.nil?
|
83
|
+
@files.has_key?(base)
|
84
|
+
when ! @subdirs.has_key?(base)
|
85
|
+
false
|
86
|
+
else
|
87
|
+
@subdirs[base].file?(rest)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# File Reading
|
92
|
+
def read_file(path)
|
93
|
+
base, rest = split_path(path)
|
94
|
+
case
|
95
|
+
when base.nil?
|
96
|
+
nil
|
97
|
+
when rest.nil?
|
98
|
+
@files[base].to_s
|
99
|
+
when ! @subdirs.has_key?(base)
|
100
|
+
nil
|
101
|
+
else
|
102
|
+
@subdirs[base].read_file(rest)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# File sizing
|
107
|
+
def size(path)
|
108
|
+
base, rest = split_path(path)
|
109
|
+
case
|
110
|
+
when base.nil?
|
111
|
+
0
|
112
|
+
when rest.nil?
|
113
|
+
obj = @files[base]
|
114
|
+
obj.respond_to?(:size) ? obj.size : 0
|
115
|
+
when ! @subdirs.has_key?(base)
|
116
|
+
0
|
117
|
+
else
|
118
|
+
dir = @subdirs[base]
|
119
|
+
dir.respond_to?(:size) ? dir.size(rest) : 0
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Write to a file
|
124
|
+
def can_write?(path)
|
125
|
+
return false unless Process.uid == FuseFS.reader_uid
|
126
|
+
base, rest = split_path(path)
|
127
|
+
case
|
128
|
+
when base.nil?
|
129
|
+
true
|
130
|
+
when rest.nil?
|
131
|
+
true
|
132
|
+
when ! @subdirs.has_key?(base)
|
133
|
+
false
|
134
|
+
else
|
135
|
+
@subdirs[base].can_write?(rest)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
def write_to(path,file)
|
139
|
+
base, rest = split_path(path)
|
140
|
+
case
|
141
|
+
when base.nil?
|
142
|
+
false
|
143
|
+
when rest.nil?
|
144
|
+
@files[base] = file
|
145
|
+
when ! @subdirs.has_key?(base)
|
146
|
+
false
|
147
|
+
else
|
148
|
+
@subdirs[base].write_to(rest,file)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Delete a file
|
153
|
+
def can_delete?(path)
|
154
|
+
return false unless Process.uid == FuseFS.reader_uid
|
155
|
+
base, rest = split_path(path)
|
156
|
+
case
|
157
|
+
when base.nil?
|
158
|
+
false
|
159
|
+
when rest.nil?
|
160
|
+
@files.has_key?(base)
|
161
|
+
when ! @subdirs.has_key?(base)
|
162
|
+
false
|
163
|
+
else
|
164
|
+
@subdirs[base].can_delete?(rest)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
def delete(path)
|
168
|
+
base, rest = split_path(path)
|
169
|
+
case
|
170
|
+
when base.nil?
|
171
|
+
nil
|
172
|
+
when rest.nil?
|
173
|
+
# Delete it.
|
174
|
+
@files.delete(base)
|
175
|
+
when ! @subdirs.has_key?(base)
|
176
|
+
nil
|
177
|
+
else
|
178
|
+
@subdirs[base].delete(rest)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Make a new directory
|
183
|
+
def can_mkdir?(path)
|
184
|
+
return false unless Process.uid == FuseFS.reader_uid
|
185
|
+
base, rest = split_path(path)
|
186
|
+
case
|
187
|
+
when base.nil?
|
188
|
+
false
|
189
|
+
when rest.nil?
|
190
|
+
! (@subdirs.has_key?(base) || @files.has_key?(base))
|
191
|
+
when ! @subdirs.has_key?(base)
|
192
|
+
false
|
193
|
+
else
|
194
|
+
@subdirs[base].can_mkdir?(rest)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
def mkdir(path,dir=nil)
|
198
|
+
base, rest = split_path(path)
|
199
|
+
case
|
200
|
+
when base.nil?
|
201
|
+
false
|
202
|
+
when rest.nil?
|
203
|
+
dir ||= MetaDir.new
|
204
|
+
@subdirs[base] = dir
|
205
|
+
true
|
206
|
+
when ! @subdirs.has_key?(base)
|
207
|
+
false
|
208
|
+
else
|
209
|
+
@subdirs[base].mkdir(rest,dir)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Delete an existing directory.
|
214
|
+
def can_rmdir?(path)
|
215
|
+
return false unless Process.uid == FuseFS.reader_uid
|
216
|
+
base, rest = split_path(path)
|
217
|
+
case
|
218
|
+
when base.nil?
|
219
|
+
false
|
220
|
+
when rest.nil?
|
221
|
+
@subdirs.has_key?(base)
|
222
|
+
when ! @subdirs.has_key?(base)
|
223
|
+
false
|
224
|
+
else
|
225
|
+
@subdirs[base].can_rmdir?(rest)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
def rmdir(path)
|
229
|
+
base, rest = split_path(path)
|
230
|
+
dir ||= MetaDir.new
|
231
|
+
case
|
232
|
+
when base.nil?
|
233
|
+
false
|
234
|
+
when rest.nil?
|
235
|
+
@subdirs.delete(base)
|
236
|
+
true
|
237
|
+
when ! @subdirs.has_key?(base)
|
238
|
+
false
|
239
|
+
else
|
240
|
+
@subdirs[base].rmdir(rest,dir)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
data/sample/demo.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'fusefs'
|
3
|
+
include FuseFS
|
4
|
+
|
5
|
+
root = MetaDir.new
|
6
|
+
|
7
|
+
# if (ARGV.size != 1)
|
8
|
+
# puts "Usage: #{$0} <directory>"
|
9
|
+
# exit
|
10
|
+
# end
|
11
|
+
|
12
|
+
dirname = ARGV.shift
|
13
|
+
|
14
|
+
unless File.directory?(dirname)
|
15
|
+
puts "Usage: #{$0} <directory>"
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
class DirLink
|
20
|
+
def initialize(dir)
|
21
|
+
File.directory?(dir) or raise ArgumentError, "DirLink.initialize expects a valid directory!"
|
22
|
+
@base = dir
|
23
|
+
end
|
24
|
+
def directory?(path)
|
25
|
+
File.directory?(File.join(@base,path))
|
26
|
+
end
|
27
|
+
def file?(path)
|
28
|
+
File.file?(File.join(@base,path))
|
29
|
+
end
|
30
|
+
def contents(path)
|
31
|
+
fn = File.join(@base,path)
|
32
|
+
Dir.entries(fn).map { |file|
|
33
|
+
file = file.sub(/^#{fn}\/?/,'')
|
34
|
+
if ['..','.'].include?(file)
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
file
|
38
|
+
end
|
39
|
+
}.compact.sort
|
40
|
+
end
|
41
|
+
def read_file(path)
|
42
|
+
fn = File.join(@base,path)
|
43
|
+
if File.file?(fn)
|
44
|
+
IO.read(fn)
|
45
|
+
else
|
46
|
+
'No such file'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Counter
|
52
|
+
def initialize
|
53
|
+
@counter = 0
|
54
|
+
end
|
55
|
+
def to_s
|
56
|
+
@counter += 1
|
57
|
+
@counter.to_s + "\n"
|
58
|
+
end
|
59
|
+
def size
|
60
|
+
@counter.to_s.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Randwords
|
65
|
+
def initialize(*ary)
|
66
|
+
@ary = ary.flatten
|
67
|
+
end
|
68
|
+
def to_s
|
69
|
+
@ary[rand(@ary.size)].to_s + "\n"
|
70
|
+
end
|
71
|
+
def size
|
72
|
+
@size ||= @ary.map{|v| v.size}.max
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
root.write_to('/hello',"Hello, World!\n")
|
77
|
+
|
78
|
+
progress = '.'
|
79
|
+
|
80
|
+
root.write_to('/progress',progress)
|
81
|
+
|
82
|
+
Thread.new do
|
83
|
+
20.times do
|
84
|
+
sleep 5
|
85
|
+
progress << '.'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
root.write_to('/counter',Counter.new)
|
90
|
+
root.write_to('/color',Randwords.new('red','blue','green','purple','yellow','bistre','burnt sienna','jade'))
|
91
|
+
root.write_to('/animal',Randwords.new('duck','dog','cat','duck billed platypus','silly fella'))
|
92
|
+
|
93
|
+
root.mkdir("/#{ENV['USER']}",DirLink.new(ENV['HOME']))
|
94
|
+
|
95
|
+
# Set the root FuseFS
|
96
|
+
FuseFS.set_root(root)
|
97
|
+
|
98
|
+
FuseFS.mount_under(dirname, 'nolocalcaches', *ARGV)
|
99
|
+
|
100
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
data/sample/dictfs.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# dictfs.rb
|
2
|
+
#
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require 'fusefs'
|
6
|
+
include FuseFS
|
7
|
+
|
8
|
+
require 'dict'
|
9
|
+
|
10
|
+
class DictFS < FuseFS::FuseDir
|
11
|
+
def initialize
|
12
|
+
@servers = ['dict.org','alt0.dict.org']
|
13
|
+
@database = DICT::ALL_DATABASES
|
14
|
+
@strategy = 'exact'
|
15
|
+
@match_strategy = DICT::DEFAULT_MATCH_STRATEGY
|
16
|
+
@port = DICT::DEFAULT_PORT
|
17
|
+
|
18
|
+
@dict = DICT.new(@servers, @port, false, false)
|
19
|
+
@dict.client("%s v%s" % ["Dictionary","1.0"])
|
20
|
+
end
|
21
|
+
def contents(path)
|
22
|
+
# The 'readme' file
|
23
|
+
['readme']
|
24
|
+
end
|
25
|
+
def file?(path)
|
26
|
+
base, rest = split_path(path)
|
27
|
+
rest.nil? # DictFS doesn't have subdirs.
|
28
|
+
end
|
29
|
+
def read_file(path)
|
30
|
+
word, rest = split_path(path)
|
31
|
+
word.downcase!
|
32
|
+
if word == "readme"
|
33
|
+
return %Q[
|
34
|
+
DictFS: You may not see the files, but if you cat any file here, it will look
|
35
|
+
that file up on dict.org!
|
36
|
+
].lstrip
|
37
|
+
end
|
38
|
+
puts "Looking up #{word}"
|
39
|
+
m = @dict.match(@database, @strategy, word)
|
40
|
+
if m
|
41
|
+
contents = []
|
42
|
+
m.each do |db,words|
|
43
|
+
words.each do |w|
|
44
|
+
defs = @dict.define(db,w)
|
45
|
+
str = []
|
46
|
+
defs.each do |d|
|
47
|
+
str << "Definition of '#{w}' (by #{d.description})"
|
48
|
+
d.definition.each do |line|
|
49
|
+
str << " #{line.strip}"
|
50
|
+
end
|
51
|
+
contents << str.join("\n")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
contents << ''
|
56
|
+
contents.join("\n")
|
57
|
+
else
|
58
|
+
"No dictionary definitions found\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if (File.basename($0) == File.basename(__FILE__))
|
64
|
+
if (ARGV.size != 1)
|
65
|
+
puts "Usage: #{$0} <directory>"
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
dirname = ARGV.shift
|
70
|
+
|
71
|
+
unless File.directory?(dirname)
|
72
|
+
puts "Usage: #{dirname} is not a directory."
|
73
|
+
exit
|
74
|
+
end
|
75
|
+
|
76
|
+
root = DictFS.new
|
77
|
+
|
78
|
+
# Set the root FuseFS
|
79
|
+
FuseFS.set_root(root)
|
80
|
+
|
81
|
+
FuseFS.mount_under(dirname)
|
82
|
+
|
83
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
84
|
+
end
|