homefs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/homefs +53 -0
  3. data/lib/homefs/homefs.rb +172 -0
  4. data/lib/homefs.rb +1 -0
  5. metadata +51 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bd9b532279081ee10b0b4d63e5bf21e93f7316bf
4
+ data.tar.gz: 9bf006b0347c6e0a67f3b5e22de6bc2e3d16e916
5
+ SHA512:
6
+ metadata.gz: f011c0e7dd3ce87b40d9acdda973c3f1f931680ba6f57da40129b8cbe159c9fba6811d07dc93cd3cf5b08ec8c4b1de970c2c8ca635b0089df48d40b47c99c3c5
7
+ data.tar.gz: 5737dba4cc80076d2c99c8fea79ba9b4fdd0ef33b1f78bbf9230b30b2d5069885b829481d4e66b91e9013d0b180b6706e2d9dca8ba9e531fef4f0653bf15f3b7
data/bin/homefs ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'homefs'
4
+ require 'rb-inotify'
5
+ require 'fileutils'
6
+
7
+ if ARGV.size < 2
8
+ warn "Usage:\n\t#{File.basename($0)} relative_directory mountpoint [options...]"
9
+ exit 1
10
+ end
11
+
12
+ # Return immediately
13
+ if fork
14
+ exit 0
15
+ end
16
+
17
+ reldir = ARGV.shift
18
+
19
+ fs = HomeFS.new(reldir)
20
+
21
+ # Shut up
22
+ $stdout = File.open("/dev/null", "w")
23
+ $stderr = File.open("/dev/null", "w")
24
+
25
+ pid = fork
26
+ if pid
27
+ # The child process will be the one actually handling the FuseFS,
28
+ # so we want to exit as soon as it dies
29
+ trap 'CLD' do
30
+ exit 0
31
+ end
32
+
33
+ # Set a watch for /etc/passwd, and update our hash of UIDs => homedirs
34
+ # when it changes
35
+ notifier = INotify::Notifier.new
36
+ notifier.watch('/etc/passwd', :modify) do
37
+ # Send a signal to the child process; it will catch USR1 and update
38
+ # the homedirs hash
39
+ Process::kill('USR1', pid)
40
+ end
41
+ notifier.run
42
+ else
43
+ # Here we trap the signal to be sent to us by our parent
44
+ # when /etc/passwd changes and update our hash accordingly
45
+ trap 'USR1' do
46
+ fs.read_passwd
47
+ end
48
+ end
49
+
50
+ # We set allow_other, because this filesystem doesn't really make sense
51
+ # without it (why direct different users to different places if only one
52
+ # user can access the filesystem?).
53
+ FuseFS.main(ARGV + ["-o", "allow_other"]) { fs }
@@ -0,0 +1,172 @@
1
+ require 'rfusefs'
2
+
3
+ class HomeFS
4
+ def initialize(path)
5
+ @relpath = path
6
+ @dirlinks = Hash.new
7
+ read_passwd
8
+ end
9
+
10
+ def read_passwd
11
+ # Here we map each line in /etc/passwd to an array,
12
+ # which Hash interprets as a key, value pair.
13
+ @homedirs = Hash[
14
+ File.readlines('/etc/passwd').map do |line|
15
+ next if line.strip.empty?
16
+ values = line.split(':')
17
+ # UID, home directory
18
+ [Integer(values[2]), values[5]]
19
+ end
20
+ ]
21
+ end
22
+
23
+ def homepath(path = nil)
24
+ uid = FuseFS.reader_uid
25
+ basepath = @homedirs[uid]
26
+ # basepath shouldn't ever be nil, but fail gracefully just
27
+ # in case.
28
+ raise Errno::ENOENT if basepath == nil
29
+ if path
30
+ "#{basepath}/#{@relpath}/#{path}"
31
+ else
32
+ "#{basepath}/#{@relpath}"
33
+ end
34
+ end
35
+
36
+ def mode_mask(file, mask, check_ids = true)
37
+ stat = File.stat(file)
38
+ # First digit: setuid (4), setgid (2), sticky bit (1)
39
+ # Second, third, and fourth digits: user, group, and
40
+ # world permissions for read (4), write (2), execute (1)
41
+ # (see `man chmod` for more)
42
+ fmode = stat.mode
43
+ if check_ids
44
+ fuid, fgid = stat.uid, stat.gid
45
+ uid, gid = FuseFS.reader_uid, FuseFS.reader_gid
46
+ # Zero out the third digit (in octal).
47
+ # We could use a constant here, but this works
48
+ # for a mask of any length
49
+ if uid != fuid
50
+ mask &= ~(mask & 0700)
51
+ end
52
+ if gid != fgid
53
+ mask &= ~(mask & 0070)
54
+ end
55
+ end
56
+ fmode & mask != 0
57
+ end
58
+
59
+ def rename(from_path, to_path)
60
+ FileUtils.mv(homepath(from_path), homepath(to_path))
61
+ end
62
+
63
+ def touch(path, modtime)
64
+ File.utime(modtime, modtime, homepath(path))
65
+ end
66
+
67
+ def rmdir(path)
68
+ FileUtils.rmdir(homepath(path))
69
+ end
70
+
71
+ def can_rmdir?(path)
72
+ File.writable?(homepath(path))
73
+ end
74
+
75
+ def mkdir(path)
76
+ FileUtils.mkdir(homepath(path))
77
+ end
78
+
79
+ def can_mkdir?(path)
80
+ writable?(File.dirname(homepath(path)))
81
+ end
82
+
83
+ def delete(path)
84
+ FileUtils.rm(homepath(path))
85
+ end
86
+
87
+ def can_delete?(path)
88
+ writable?(File.dirname(homepath(path)))
89
+ end
90
+
91
+ def write_to(path, str)
92
+ File.open(homepath(path), "wb") {|file| file.write(str) }
93
+ end
94
+
95
+ def writable?(path)
96
+ mode_mask(path, 0222)
97
+ end
98
+
99
+ def can_write?(path)
100
+ hpath = homepath(path)
101
+ if File.exist?(hpath)
102
+ writable?(hpath)
103
+ else
104
+ # FIXME: We don't support sticky bits
105
+ writable?(File.dirname(hpath))
106
+ end
107
+ end
108
+
109
+ def times(path)
110
+ atime = File.atime(homepath(path))
111
+ mtime = File.mtime(homepath(path))
112
+ ctime = File.ctime(homepath(path))
113
+ [atime, mtime, ctime]
114
+ end
115
+
116
+ def executable?(path)
117
+ mode_mask(homepath(path), 0111)
118
+ end
119
+
120
+ def read_file(path)
121
+ File.open(homepath(path), "rb") do |file|
122
+ file.read
123
+ end
124
+ end
125
+
126
+ def contents(path)
127
+ Dir.new(homepath(path)).to_a
128
+ end
129
+
130
+ def size(path)
131
+ File.size(homepath(path))
132
+ end
133
+
134
+ def file?(path)
135
+ File.file?(homepath(path))
136
+ end
137
+
138
+ def directory?(path)
139
+ File.directory?(homepath(path))
140
+ end
141
+
142
+ def raw_open(path, mode, rfusefs = nil)
143
+ mode = case mode
144
+ when "rw" then File::RDWR | File::CREAT | File::BINARY
145
+ when "r" then File::RDONLY | File::BINARY
146
+ when "w" then File::WRONLY | File::CREAT | File::BINARY
147
+ end
148
+ File.open(homepath(path), mode)
149
+ end
150
+
151
+ def raw_read(path, offset, size, raw = nil)
152
+ raw ||= raw_open(path, "r")
153
+ raw.seek(offset, :SET)
154
+ raw.read(size)
155
+ end
156
+
157
+ def raw_sync(path, datasync, raw = nil)
158
+ return if raw.nil? # Should we sync anyway?
159
+ raw.fdatasync
160
+ end
161
+
162
+ def raw_close(path, raw = nil)
163
+ return if raw.nil? # ???
164
+ raw.close
165
+ end
166
+
167
+ def raw_write(path, off, sz, buf, raw = nil)
168
+ raw ||= File.open(path, "w")
169
+ raw.seek(off, :SET)
170
+ raw.write(buf[0...sz])
171
+ end
172
+ end
data/lib/homefs.rb ADDED
@@ -0,0 +1 @@
1
+ require 'homefs/homefs'
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: homefs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dylan Frese
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-26 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |-
14
+ FuseFS currently written in Ruby that directs filesystem
15
+ calls to a directory relative to the calling user's home
16
+ directory.
17
+ email: dmfrese@gmail.com
18
+ executables:
19
+ - homefs
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - bin/homefs
24
+ - lib/homefs.rb
25
+ - lib/homefs/homefs.rb
26
+ homepage:
27
+ licenses:
28
+ - GPLv3
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.2.2
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: FUSE Filesystem
50
+ test_files: []
51
+ has_rdoc: