pfuse 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/fusefs.rb ADDED
@@ -0,0 +1,114 @@
1
+ # FuseFS.rb
2
+ #
3
+ # The ruby portion of FuseFS main library
4
+ #
5
+ # Helper functions
6
+
7
+ # TODO sig handler?
8
+
9
+ require File.dirname(__FILE__) + '/../ext/fusefs_lib'
10
+
11
+ module FuseFS
12
+ S_IFDIR = 0o0040000
13
+ S_IFREG = 0o0100000
14
+
15
+ @running = true
16
+
17
+ class << self
18
+ def run
19
+ fd = fuse_fd
20
+
21
+ begin
22
+ io = IO.for_fd(fd)
23
+ rescue Errno::EBADF
24
+ raise "fuse is not mounted"
25
+ end
26
+
27
+ while @running
28
+ IO.select([io])
29
+ process
30
+ end
31
+ end
32
+
33
+ def unmount
34
+ system("umount #{@mountpoint}")
35
+ end
36
+
37
+ def exit
38
+ @running = false
39
+ end
40
+
41
+ def Entries(path, entries)
42
+ entries.map do |entry|
43
+ @root.getattr(File.join(path, entry))
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ class Stat
50
+ attr_accessor :st_mode
51
+ attr_accessor :st_nlink
52
+ attr_accessor :st_size
53
+ attr_accessor :st_uid
54
+ attr_accessor :st_gid
55
+ attr_accessor :st_mtime
56
+ attr_accessor :st_atime
57
+ attr_accessor :st_ctime
58
+ attr_accessor :name
59
+
60
+ def initialize(name='undefined')
61
+ @st_mode = 0o755 | mode_mask
62
+ @st_nlink = 3
63
+ @st_size = 0
64
+ @st_uid = Process.uid
65
+ @st_gid = Process.gid
66
+ @st_mtime = Time.now.to_i
67
+ @st_atime = Time.now.to_i
68
+ @st_ctime = Time.now.to_i
69
+ @name = name
70
+ end
71
+
72
+ def mode_mask
73
+ self.class == FileEntry ? S_IFREG : S_IFDIR
74
+ end
75
+ end
76
+
77
+ class FileEntry < Stat
78
+ end
79
+
80
+ class DirEntry < Stat
81
+ def initialize(*args)
82
+ super(*args)
83
+ @st_size = 4096
84
+ end
85
+ end
86
+
87
+ class StatVFS
88
+ attr_accessor :f_bsize
89
+ attr_accessor :f_frsize
90
+ attr_accessor :f_blocks
91
+ attr_accessor :f_bfree
92
+ attr_accessor :f_bavail
93
+ attr_accessor :f_files
94
+ attr_accessor :f_ffree
95
+ attr_accessor :f_favail
96
+ attr_accessor :f_fsid
97
+ attr_accessor :f_flag
98
+ attr_accessor :f_namemax
99
+
100
+ def initialize
101
+ @f_bsize = 0
102
+ @f_frsize = 0
103
+ @f_blocks = 0
104
+ @f_bfree = 0
105
+ @f_bavail = 0
106
+ @f_files = 0
107
+ @f_ffree = 0
108
+ @f_favail = 0
109
+ @f_fsid = 0
110
+ @f_flag = 0
111
+ @f_namemax = 0
112
+ end
113
+ end
114
+ end
data/pfuse.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{pfuse}
8
+ s.version = "0.7.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["David Turnbull", "Kyle Maxwell"]
12
+ s.date = %q{2010-02-26}
13
+ s.description = %q{Gemified}
14
+ s.email = %q{dsturnbull@gmail.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/extconf.rb",
32
+ "ext/fusefs_fuse.c",
33
+ "ext/fusefs_fuse.h",
34
+ "ext/fusefs_lib.c",
35
+ "ext/fusefs_lib.h",
36
+ "hello.sh",
37
+ "lib/fusefs.rb",
38
+ "pfuse.gemspec",
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/dsturnbull/pfuse}
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/fusefs_test.rb",
56
+ "test/test_helper.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/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
data/sample/hello.rb ADDED
@@ -0,0 +1,27 @@
1
+ require "rubygems"
2
+ require 'fusefs'
3
+
4
+ class HelloDir
5
+ def contents(path)
6
+ ['hello.txt']
7
+ end
8
+
9
+ def file?(path)
10
+ path == '/hello.txt'
11
+ end
12
+
13
+ def read_file(path)
14
+ "Hello, World!\n"
15
+ end
16
+
17
+ def size(path)
18
+ read_file(path).size
19
+ end
20
+ end
21
+
22
+ hellodir = HelloDir.new
23
+ FuseFS.set_root( hellodir )
24
+
25
+ # Mount under a directory given on the command line.
26
+ FuseFS.mount_under ARGV.shift
27
+ FuseFS.run
@@ -0,0 +1,53 @@
1
+ # openurifs.rb
2
+ #
3
+
4
+ require "rubygems"
5
+ require 'fusefs'
6
+ include FuseFS
7
+
8
+ require 'open-uri'
9
+
10
+ class OpenUriFS < FuseFS::FuseDir
11
+ def contents(path)
12
+ # The 'readme' file
13
+ []
14
+ end
15
+ def directory?(path)
16
+ uri = scan_path(path)
17
+ fn = uri.pop
18
+ return true if fn =~ /\.(com|org|net|us|de|jp|ru|uk|biz|info)$/
19
+ return true if fn =~ /^\d+\.\d+\.\d+\.\d+$/
20
+ ! (fn =~ /\./) # Does the last item doesn't contain a '.' ?
21
+ end
22
+ def file?(path)
23
+ !directory?(path)
24
+ end
25
+ def read_file(path)
26
+ proto, rest = split_path(path)
27
+ uri = "#{proto}://#{rest}"
28
+ open(uri).read
29
+ end
30
+ end
31
+
32
+ if (File.basename($0) == File.basename(__FILE__))
33
+ if (ARGV.size != 1)
34
+ puts "Usage: #{$0} <directory>"
35
+ exit
36
+ end
37
+
38
+ dirname = ARGV.shift
39
+
40
+ unless File.directory?(dirname)
41
+ puts "Usage: #{dirname} is not a directory."
42
+ exit
43
+ end
44
+
45
+ root = OpenUriFS.new
46
+
47
+ # Set the root FuseFS
48
+ FuseFS.set_root(root)
49
+
50
+ FuseFS.mount_under(dirname)
51
+
52
+ FuseFS.run # This doesn't return until we're unmounted.
53
+ end
data/sample/railsfs.rb ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # RailsFS, as written by _why_the_lucky_stiff
4
+ #
5
+ # Full instructions:
6
+ # http://redhanded.hobix.com/inspect/railsfsAfterACoupleMinutesOfToolingWithFuseWhoa.html
7
+ #
8
+ =begin
9
+ Instructions cut and paste from _why's blog:
10
+
11
+ Save the railfs.rb script as script/filesys in your Rails app. (If you'd
12
+ rather not cut-and-paste the above, it's here.)
13
+
14
+ Now, run mkdir ~/railsmnt. Then, script/filesys ~/railsmnt. The rules are as
15
+ follows:
16
+
17
+ * ls ~/railsmnt will give you a list of tables.
18
+ * ls ~/railsmnt/table will list IDs from the table.
19
+ * cat ~/railsmnt/table/id will display a record in YAML.
20
+ * vim ~/railsmnt/table/id to edit the record in YAML!
21
+
22
+ =end
23
+
24
+ require "rubygems"
25
+ require 'fusefs'
26
+ require File.dirname(__FILE__) + '/../config/environment'
27
+
28
+ class RailsFS < FuseFS::FuseDir
29
+ def initialize
30
+ @classes = {}
31
+ require 'find'
32
+ Find.find( File.join(RAILS_ROOT, 'app/models') ) do |model|
33
+ if /(\w+)\.rb$/ =~ model
34
+ model = $1
35
+ ( @classes[model] = Kernel::const_get( Inflector.classify( model ) ) ).
36
+ find :first rescue @classes.delete( model )
37
+ end
38
+ end
39
+ end
40
+ def directory? path
41
+ tname, key = scan_path path
42
+ table = @classes[tname]
43
+ if table.nil?; false # /table
44
+ elsif key; false # /table/id
45
+ else; true end
46
+ end
47
+ def file? path
48
+ tname, key = scan_path path
49
+ table = @classes[tname]
50
+ key and table and table.find( key )
51
+ end
52
+ def can_delete?; true end
53
+ def can_write? path; file? path end
54
+ def contents path
55
+ tname, key = scan_path path
56
+ table = @classes[tname]
57
+ if tname.nil?; @classes.keys.sort # /
58
+ else; table.find( :all ).map { |o| o.id.to_s } end # /table
59
+ end
60
+ def write_to path, body
61
+ obj = YAML::load( body )
62
+ obj.save
63
+ end
64
+ def read_file path
65
+ tname, key = scan_path path
66
+ table = @classes[tname]
67
+ YAML::dump( table.find( key ) )
68
+ end
69
+ end
70
+
71
+ if (File.basename($0) == File.basename(__FILE__))
72
+ root = RailsFS.new
73
+ FuseFS.set_root(root)
74
+ FuseFS.mount_under(ARGV[0])
75
+ FuseFS.run # This doesn't return until we're unmounted.
76
+ end
77
+
data/sample/sqlfs.rb ADDED
@@ -0,0 +1,134 @@
1
+ # sqlfs.rb
2
+ #
3
+ # The SQL-db proof of concept for FuseFS
4
+ #
5
+ # Author: Greg Millam
6
+
7
+ require "rubygems"
8
+ require 'fusefs'
9
+
10
+ require 'mysql'
11
+
12
+ class SqlFS < FuseFS::FuseDir
13
+ class DBTable
14
+ attr_accessor :name, :key, :fields
15
+ end
16
+ def initialize(host,user,pass,db)
17
+ @sql = Mysql.connect(host,user,pass,db)
18
+ @tables = Hash.new(nil)
19
+
20
+ tables = @sql.query('show tables')
21
+
22
+ tables.each do |i,|
23
+ table = DBTable.new
24
+ table.name = i
25
+ table.fields = {}
26
+ res = @sql.query("describe #{i}")
27
+ res.each do |field,type,null,key,default,extra|
28
+ table.fields[field] = type
29
+ if (key =~ /pri/i)
30
+ table.key = field
31
+ end
32
+ end
33
+ @tables[i] = table if table.key
34
+ end
35
+ end
36
+ def directory?(path)
37
+ tname, key, field = scan_path(path)
38
+ table = @tables[tname]
39
+ case
40
+ when tname.nil?
41
+ true # This means "/"
42
+ when table.nil?
43
+ false
44
+ when field
45
+ false # Always a file
46
+ when key
47
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
48
+ res.num_rows > 0 # If there was a result, it exists.
49
+ else
50
+ true # It's just a table.
51
+ end
52
+ end
53
+ def file?(path)
54
+ tname, key, field = scan_path(path)
55
+ table = @tables[tname]
56
+ case
57
+ when field.nil?
58
+ false # Only field entries are files.
59
+ when table.nil?
60
+ false
61
+ when ! @tables[tname].fields.include?(field)
62
+ false # Invalid field.
63
+ when field
64
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
65
+ res.num_rows > 0
66
+ end
67
+ end
68
+ def can_delete?(path)
69
+ # This helps editors, but we don't really use it.
70
+ true
71
+ end
72
+ def can_write?(path)
73
+ # Since this is basically only for editing files,
74
+ # we just call file?
75
+ file?(path)
76
+ end
77
+ def contents(path)
78
+ # since this is only called when directory? is true,
79
+ # We'll assume valid entries.
80
+ tname, key, field = scan_path(path)
81
+ table = @tables[tname]
82
+ case
83
+ when tname.nil?
84
+ @tables.keys.sort # Just the tables.
85
+ when key
86
+ table.fields.keys.sort
87
+ else
88
+ # I limit to 200 so 'ls' doesn't hang all the time :D
89
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} ORDER BY #{table.key} LIMIT 100")
90
+ ret = []
91
+ res.each do |val,one|
92
+ ret << val if val.size > 0
93
+ end
94
+ ret
95
+ end
96
+ end
97
+ def write_to(path,body)
98
+ # Since this is only called after can_write?(), we assume
99
+ # Valid fields.
100
+ tname, key, field = scan_path(path)
101
+ table = @tables[tname]
102
+ res = @sql.query("UPDATE #{table.name} SET #{field} = '#{Mysql.escape_string(body)}' WHERE #{table.key} = '#{key}'")
103
+ end
104
+ def read_file(path)
105
+ # Again, as this is only called after file?, assume valid fields.
106
+ tname, key, field = scan_path(path)
107
+ table = @tables[tname]
108
+ res = @sql.query("SELECT #{field} FROM #{table.name} WHERE #{table.key} = '#{key}'")
109
+ res.fetch_row[0]
110
+ end
111
+ end
112
+
113
+ if (File.basename($0) == File.basename(__FILE__))
114
+ if ARGV.size != 5
115
+ puts "Usage: #{$0} <directory> <host> <user> <pass> <db>"
116
+ exit
117
+ end
118
+
119
+ dirname, host, user, pass, db = ARGV
120
+
121
+ if (! File.directory?(dirname))
122
+ puts "#{dirname} is not a directory"
123
+ end
124
+
125
+ root = SqlFS.new(host,user,pass,db)
126
+
127
+ # Set the root FuseFS
128
+ FuseFS.set_root(root)
129
+
130
+ # root.contents("/quotes")
131
+
132
+ FuseFS.mount_under(dirname)
133
+ FuseFS.run # This doesn't return until we're unmounted.
134
+ end