om@2
|
1 |
#!/bin/env python
|
om@2
|
2 |
# -*- coding: utf-8 -*-
|
om@2
|
3 |
|
om@2
|
4 |
# ------------------------------------------------------------
|
om@2
|
5 |
# mirrorfuse
|
om@2
|
6 |
#
|
om@2
|
7 |
# create a mirror filesystem folder as a new filesystem to mount
|
om@2
|
8 |
#
|
om@2
|
9 |
# This is directly based on xmp.py of the
|
om@2
|
10 |
# dev-python/fuse-python example
|
om@2
|
11 |
#
|
om@2
|
12 |
# Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
|
om@2
|
13 |
#
|
om@2
|
14 |
# Copyright (C) 2013 AIT Austrian Institute of Technology
|
om@2
|
15 |
# AIT Austrian Institute of Technology GmbH
|
om@2
|
16 |
# Donau-City-Strasse 1 | 1220 Vienna | Austria
|
om@2
|
17 |
# http://www.ait.ac.at
|
om@2
|
18 |
#
|
om@2
|
19 |
# This program is free software; you can redistribute it and/or
|
om@2
|
20 |
# modify it under the terms of the GNU General Public License
|
om@2
|
21 |
# as published by the Free Software Foundation version 2.
|
om@2
|
22 |
#
|
om@2
|
23 |
# This program is distributed in the hope that it will be useful,
|
om@2
|
24 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
om@2
|
25 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
om@2
|
26 |
# GNU General Public License for more details.
|
om@2
|
27 |
#
|
om@2
|
28 |
# You should have received a copy of the GNU General Public License
|
om@2
|
29 |
# along with this program; if not, write to the Free Software
|
om@2
|
30 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
om@2
|
31 |
# Boston, MA 02110-1301, USA.
|
om@2
|
32 |
# ------------------------------------------------------------
|
om@2
|
33 |
|
om@2
|
34 |
|
om@2
|
35 |
# ------------------------------------------------------------
|
om@2
|
36 |
# imports
|
om@2
|
37 |
|
om@2
|
38 |
import errno
|
om@2
|
39 |
import fcntl
|
om@2
|
40 |
import fuse
|
om@2
|
41 |
import os
|
om@2
|
42 |
import sys
|
om@2
|
43 |
|
om@2
|
44 |
from fuse import Fuse
|
om@2
|
45 |
|
om@2
|
46 |
# ------------------------------------------------------------
|
om@2
|
47 |
# const
|
om@2
|
48 |
|
om@2
|
49 |
|
om@2
|
50 |
__version__ = "0.1"
|
om@2
|
51 |
|
om@2
|
52 |
|
om@2
|
53 |
# ------------------------------------------------------------
|
om@2
|
54 |
# code
|
om@2
|
55 |
|
om@2
|
56 |
|
om@2
|
57 |
class MirrorFuse(Fuse):
|
om@2
|
58 |
|
om@2
|
59 |
"""This is the Mirror FUSE in python.
|
om@2
|
60 |
|
om@2
|
61 |
This is to represnt a file hierarchy elsewhere (and intercept each file system call)
|
om@2
|
62 |
"""
|
om@2
|
63 |
|
om@2
|
64 |
def __init__(self, *args, **kw):
|
om@2
|
65 |
fuse.fuse_python_api = (0, 2)
|
om@2
|
66 |
super(MirrorFuse, self).__init__(*args, **kw)
|
om@2
|
67 |
self.root = '/'
|
om@2
|
68 |
self.os_server_url = ''
|
om@2
|
69 |
|
om@2
|
70 |
def getattr(self, path):
|
om@2
|
71 |
return os.lstat("." + path)
|
om@2
|
72 |
|
om@2
|
73 |
|
om@2
|
74 |
#
|
om@2
|
75 |
# links are not allowed for a mirrored FS
|
om@2
|
76 |
#
|
om@2
|
77 |
def readlink(self, path):
|
om@2
|
78 |
eturn -errno.EACCES
|
om@2
|
79 |
|
om@2
|
80 |
|
om@2
|
81 |
def readdir(self, path, offset):
|
om@2
|
82 |
for e in os.listdir("." + path):
|
om@2
|
83 |
yield fuse.Direntry(e)
|
om@2
|
84 |
|
om@2
|
85 |
|
om@2
|
86 |
def unlink(self, path):
|
om@2
|
87 |
sys.stdout.write("===\nInsert Hook here! Deleting file %s\n===\n" % path)
|
om@2
|
88 |
os.unlink("." + path)
|
om@2
|
89 |
|
om@2
|
90 |
|
om@2
|
91 |
def rmdir(self, path):
|
om@2
|
92 |
sys.stdout.write("===\nInsert Hook here! Deleting folder %s\n===\n" % path)
|
om@2
|
93 |
os.rmdir("." + path)
|
om@2
|
94 |
|
om@2
|
95 |
|
om@2
|
96 |
#
|
om@2
|
97 |
# links are not allowed for a mirrored FS
|
om@2
|
98 |
#
|
om@2
|
99 |
def symlink(self, path, path1):
|
om@2
|
100 |
eturn -errno.EACCES
|
om@2
|
101 |
|
om@2
|
102 |
|
om@2
|
103 |
def rename(self, path, path1):
|
om@2
|
104 |
sys.stdout.write("===\nInsert Hook here! Moving file %s --> %s\n===\n" % path % path1)
|
om@2
|
105 |
os.rename("." + path, "." + path1)
|
om@2
|
106 |
|
om@2
|
107 |
|
om@2
|
108 |
#
|
om@2
|
109 |
# links are not allowed for a mirrored FS
|
om@2
|
110 |
#
|
om@2
|
111 |
def link(self, path, path1):
|
om@2
|
112 |
return -errno.EACCES
|
om@2
|
113 |
|
om@2
|
114 |
|
om@2
|
115 |
#
|
om@2
|
116 |
# changing access mode is not allowed in mirrored FS
|
om@2
|
117 |
#
|
om@2
|
118 |
def chmod(self, path, mode):
|
om@2
|
119 |
return -errno.EACCES
|
om@2
|
120 |
|
om@2
|
121 |
|
om@2
|
122 |
#
|
om@2
|
123 |
# changing ownership is not allowed in mirrored FS
|
om@2
|
124 |
#
|
om@2
|
125 |
def chown(self, path, user, group):
|
om@2
|
126 |
return -errno.EACCES
|
om@2
|
127 |
|
om@2
|
128 |
|
om@2
|
129 |
def truncate(self, path, len):
|
om@2
|
130 |
f = open("." + path, "a")
|
om@2
|
131 |
f.truncate(len)
|
om@2
|
132 |
f.close()
|
om@2
|
133 |
|
om@2
|
134 |
|
om@2
|
135 |
def mknod(self, path, mode, dev):
|
om@2
|
136 |
sys.stdout.write("===\nInsert Hook here! Creating file %s\n===\n" % path)
|
om@2
|
137 |
os.mknod("." + path, mode, dev)
|
om@2
|
138 |
|
om@2
|
139 |
|
om@2
|
140 |
def mkdir(self, path, mode):
|
om@2
|
141 |
sys.stdout.write("===\nInsert Hook here! Creating folder %s\n===\n" % path)
|
om@2
|
142 |
os.mkdir("." + path, mode)
|
om@2
|
143 |
|
om@2
|
144 |
|
om@2
|
145 |
def utime(self, path, times):
|
om@2
|
146 |
os.utime("." + path, times)
|
om@2
|
147 |
|
om@2
|
148 |
|
om@2
|
149 |
def access(self, path, mode):
|
om@2
|
150 |
if not os.access("." + path, mode):
|
om@2
|
151 |
return -errno.EACCES
|
om@2
|
152 |
|
om@2
|
153 |
|
om@2
|
154 |
def statfs(self):
|
om@2
|
155 |
return os.statvfs(".")
|
om@2
|
156 |
|
om@2
|
157 |
|
om@2
|
158 |
def fsinit(self):
|
om@2
|
159 |
os.chdir(self.root)
|
om@2
|
160 |
|
om@2
|
161 |
|
om@2
|
162 |
def main(self, *a, **kw):
|
om@2
|
163 |
self.file_class = MirrorFuseFile
|
om@2
|
164 |
return Fuse.main(self, *a, **kw)
|
om@2
|
165 |
|
om@2
|
166 |
|
om@2
|
167 |
class MirrorFuseFile(object):
|
om@2
|
168 |
|
om@2
|
169 |
"""This is a single "File" in the Mirror FUSE"""
|
om@2
|
170 |
|
om@2
|
171 |
def __init__(self, path, flags, *mode):
|
om@2
|
172 |
sys.stdout.write("===\nInsert Hook here! Opening file %s\n===\n" % path)
|
om@2
|
173 |
self.file = os.fdopen(os.open("." + path, flags, *mode), flag2mode(flags))
|
om@2
|
174 |
self.fd = self.file.fileno()
|
om@2
|
175 |
|
om@2
|
176 |
|
om@2
|
177 |
def read(self, length, offset):
|
om@2
|
178 |
self.file.seek(offset)
|
om@2
|
179 |
return self.file.read(length)
|
om@2
|
180 |
|
om@2
|
181 |
|
om@2
|
182 |
def write(self, buf, offset):
|
om@2
|
183 |
self.file.seek(offset)
|
om@2
|
184 |
self.file.write(buf)
|
om@2
|
185 |
return len(buf)
|
om@2
|
186 |
|
om@2
|
187 |
|
om@2
|
188 |
def release(self, flags):
|
om@2
|
189 |
self.file.close()
|
om@2
|
190 |
|
om@2
|
191 |
|
om@2
|
192 |
def _fflush(self):
|
om@2
|
193 |
if 'w' in self.file.mode or 'a' in self.file.mode:
|
om@2
|
194 |
self.file.flush()
|
om@2
|
195 |
|
om@2
|
196 |
def fsync(self, isfsyncfile):
|
om@2
|
197 |
self._fflush()
|
om@2
|
198 |
if isfsyncfile and hasattr(os, 'fdatasync'):
|
om@2
|
199 |
os.fdatasync(self.fd)
|
om@2
|
200 |
else:
|
om@2
|
201 |
os.fsync(self.fd)
|
om@2
|
202 |
|
om@2
|
203 |
|
om@2
|
204 |
def flush(self):
|
om@2
|
205 |
self._fflush()
|
om@2
|
206 |
os.close(os.dup(self.fd))
|
om@2
|
207 |
|
om@2
|
208 |
|
om@2
|
209 |
def fgetattr(self):
|
om@2
|
210 |
return os.fstat(self.fd)
|
om@2
|
211 |
|
om@2
|
212 |
|
om@2
|
213 |
def ftruncate(self, len):
|
om@2
|
214 |
self.file.truncate(len)
|
om@2
|
215 |
|
om@2
|
216 |
|
om@2
|
217 |
def lock(self, cmd, owner, **kw):
|
om@2
|
218 |
op = {fcntl.F_UNLCK : fcntl.LOCK_UN, fcntl.F_RDLCK : fcntl.LOCK_SH, fcntl.F_WRLCK : fcntl.LOCK_EX}[kw['l_type']]
|
om@2
|
219 |
if cmd == fcntl.F_GETLK:
|
om@2
|
220 |
return -EOPNOTSUPP
|
om@2
|
221 |
elif cmd == fcntl.F_SETLK:
|
om@2
|
222 |
if op != fcntl.LOCK_UN:
|
om@2
|
223 |
op |= fcntl.LOCK_NB
|
om@2
|
224 |
elif cmd == fcntl.F_SETLKW:
|
om@2
|
225 |
pass
|
om@2
|
226 |
else:
|
om@2
|
227 |
return -errno.EINVAL
|
om@2
|
228 |
|
om@2
|
229 |
fcntl.lockf(self.fd, op, kw['l_start'], kw['l_len'])
|
om@2
|
230 |
|
om@2
|
231 |
|
om@2
|
232 |
def flag2mode(flags):
|
om@2
|
233 |
|
om@2
|
234 |
"""Turn os flags into mode chars"""
|
om@2
|
235 |
|
om@2
|
236 |
md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
|
om@2
|
237 |
m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
|
om@2
|
238 |
if flags | os.O_APPEND:
|
om@2
|
239 |
m = m.replace('w', 'a', 1)
|
om@2
|
240 |
return m
|
om@2
|
241 |
|
om@2
|
242 |
|
om@2
|
243 |
def main():
|
om@2
|
244 |
|
om@2
|
245 |
usage = """
|
om@2
|
246 |
mirror the a file tree from some point on.
|
om@2
|
247 |
|
om@2
|
248 |
""" + Fuse.fusage
|
om@2
|
249 |
|
om@2
|
250 |
# launch the Fuse server
|
om@2
|
251 |
server = MirrorFuse(version = "%prog " + __version__, usage = usage, dash_s_do = 'setsingle')
|
om@2
|
252 |
server.parser.add_option(mountopt = "root", metavar = "PATH", default='/', help="mirror filesystem from under PATH [default: %default]")
|
om@2
|
253 |
server.parser.add_option(mountopt = "os_server_url", metavar = "URL", default='http://localhost:8080', help="URL to OpenSecurity Server [default: %default]")
|
om@2
|
254 |
server.parse(values=server, errex=1)
|
om@2
|
255 |
|
om@2
|
256 |
try:
|
om@2
|
257 |
if server.fuse_args.mount_expected():
|
om@2
|
258 |
os.chdir(server.root)
|
om@2
|
259 |
except OSError:
|
om@2
|
260 |
print >> sys.stderr, "can't enter root of underlying filesystem"
|
om@2
|
261 |
sys.exit(1)
|
om@2
|
262 |
|
om@2
|
263 |
server.main()
|
om@2
|
264 |
|
om@2
|
265 |
|
om@2
|
266 |
# start
|
om@2
|
267 |
if __name__ == "__main__":
|
om@2
|
268 |
main()
|
om@2
|
269 |
|
om@2
|
270 |
|