homefs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/homefs +53 -0
- data/lib/homefs/homefs.rb +172 -0
- data/lib/homefs.rb +1 -0
- 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:
|