homefs 0.1.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.
- 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:
|