om@2: #!/bin/env python om@2: # -*- coding: utf-8 -*- om@2: om@2: # ------------------------------------------------------------ om@2: # mirrorfuse om@2: # om@2: # create a mirror filesystem folder as a new filesystem to mount om@2: # om@2: # This is directly based on xmp.py of the om@2: # dev-python/fuse-python example om@2: # om@2: # Autor: Oliver Maurhart, om@2: # om@2: # Copyright (C) 2013 AIT Austrian Institute of Technology om@2: # AIT Austrian Institute of Technology GmbH om@2: # Donau-City-Strasse 1 | 1220 Vienna | Austria om@2: # http://www.ait.ac.at om@2: # om@2: # This program is free software; you can redistribute it and/or om@2: # modify it under the terms of the GNU General Public License om@2: # as published by the Free Software Foundation version 2. om@2: # om@2: # This program is distributed in the hope that it will be useful, om@2: # but WITHOUT ANY WARRANTY; without even the implied warranty of om@2: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the om@2: # GNU General Public License for more details. om@2: # om@2: # You should have received a copy of the GNU General Public License om@2: # along with this program; if not, write to the Free Software om@2: # Foundation, Inc., 51 Franklin Street, Fifth Floor, om@2: # Boston, MA 02110-1301, USA. om@2: # ------------------------------------------------------------ om@2: om@2: om@2: # ------------------------------------------------------------ om@2: # imports om@2: om@2: import errno om@2: import fcntl om@2: import fuse om@2: import os om@2: import sys om@2: om@2: from fuse import Fuse om@2: om@2: # ------------------------------------------------------------ om@2: # const om@2: om@2: om@2: __version__ = "0.1" om@2: om@2: om@2: # ------------------------------------------------------------ om@2: # code om@2: om@2: om@2: class MirrorFuse(Fuse): om@2: om@2: """This is the Mirror FUSE in python. om@2: om@2: This is to represnt a file hierarchy elsewhere (and intercept each file system call) om@2: """ om@2: om@2: def __init__(self, *args, **kw): om@2: fuse.fuse_python_api = (0, 2) om@2: super(MirrorFuse, self).__init__(*args, **kw) om@2: self.root = '/' om@2: self.os_server_url = '' om@2: om@2: def getattr(self, path): om@2: return os.lstat("." + path) om@2: om@2: om@2: # om@2: # links are not allowed for a mirrored FS om@2: # om@2: def readlink(self, path): om@2: eturn -errno.EACCES om@2: om@2: om@2: def readdir(self, path, offset): om@2: for e in os.listdir("." + path): om@2: yield fuse.Direntry(e) om@2: om@2: om@2: def unlink(self, path): om@2: sys.stdout.write("===\nInsert Hook here! Deleting file %s\n===\n" % path) om@2: os.unlink("." + path) om@2: om@2: om@2: def rmdir(self, path): om@2: sys.stdout.write("===\nInsert Hook here! Deleting folder %s\n===\n" % path) om@2: os.rmdir("." + path) om@2: om@2: om@2: # om@2: # links are not allowed for a mirrored FS om@2: # om@2: def symlink(self, path, path1): om@2: eturn -errno.EACCES om@2: om@2: om@2: def rename(self, path, path1): om@2: sys.stdout.write("===\nInsert Hook here! Moving file %s --> %s\n===\n" % path % path1) om@2: os.rename("." + path, "." + path1) om@2: om@2: om@2: # om@2: # links are not allowed for a mirrored FS om@2: # om@2: def link(self, path, path1): om@2: return -errno.EACCES om@2: om@2: om@2: # om@2: # changing access mode is not allowed in mirrored FS om@2: # om@2: def chmod(self, path, mode): om@2: return -errno.EACCES om@2: om@2: om@2: # om@2: # changing ownership is not allowed in mirrored FS om@2: # om@2: def chown(self, path, user, group): om@2: return -errno.EACCES om@2: om@2: om@2: def truncate(self, path, len): om@2: f = open("." + path, "a") om@2: f.truncate(len) om@2: f.close() om@2: om@2: om@2: def mknod(self, path, mode, dev): om@2: sys.stdout.write("===\nInsert Hook here! Creating file %s\n===\n" % path) om@2: os.mknod("." + path, mode, dev) om@2: om@2: om@2: def mkdir(self, path, mode): om@2: sys.stdout.write("===\nInsert Hook here! Creating folder %s\n===\n" % path) om@2: os.mkdir("." + path, mode) om@2: om@2: om@2: def utime(self, path, times): om@2: os.utime("." + path, times) om@2: om@2: om@2: def access(self, path, mode): om@2: if not os.access("." + path, mode): om@2: return -errno.EACCES om@2: om@2: om@2: def statfs(self): om@2: return os.statvfs(".") om@2: om@2: om@2: def fsinit(self): om@2: os.chdir(self.root) om@2: om@2: om@2: def main(self, *a, **kw): om@2: self.file_class = MirrorFuseFile om@2: return Fuse.main(self, *a, **kw) om@2: om@2: om@2: class MirrorFuseFile(object): om@2: om@2: """This is a single "File" in the Mirror FUSE""" om@2: om@2: def __init__(self, path, flags, *mode): om@2: sys.stdout.write("===\nInsert Hook here! Opening file %s\n===\n" % path) om@2: self.file = os.fdopen(os.open("." + path, flags, *mode), flag2mode(flags)) om@2: self.fd = self.file.fileno() om@2: om@2: om@2: def read(self, length, offset): om@2: self.file.seek(offset) om@2: return self.file.read(length) om@2: om@2: om@2: def write(self, buf, offset): om@2: self.file.seek(offset) om@2: self.file.write(buf) om@2: return len(buf) om@2: om@2: om@2: def release(self, flags): om@2: self.file.close() om@2: om@2: om@2: def _fflush(self): om@2: if 'w' in self.file.mode or 'a' in self.file.mode: om@2: self.file.flush() om@2: om@2: def fsync(self, isfsyncfile): om@2: self._fflush() om@2: if isfsyncfile and hasattr(os, 'fdatasync'): om@2: os.fdatasync(self.fd) om@2: else: om@2: os.fsync(self.fd) om@2: om@2: om@2: def flush(self): om@2: self._fflush() om@2: os.close(os.dup(self.fd)) om@2: om@2: om@2: def fgetattr(self): om@2: return os.fstat(self.fd) om@2: om@2: om@2: def ftruncate(self, len): om@2: self.file.truncate(len) om@2: om@2: om@2: def lock(self, cmd, owner, **kw): om@2: op = {fcntl.F_UNLCK : fcntl.LOCK_UN, fcntl.F_RDLCK : fcntl.LOCK_SH, fcntl.F_WRLCK : fcntl.LOCK_EX}[kw['l_type']] om@2: if cmd == fcntl.F_GETLK: om@2: return -EOPNOTSUPP om@2: elif cmd == fcntl.F_SETLK: om@2: if op != fcntl.LOCK_UN: om@2: op |= fcntl.LOCK_NB om@2: elif cmd == fcntl.F_SETLKW: om@2: pass om@2: else: om@2: return -errno.EINVAL om@2: om@2: fcntl.lockf(self.fd, op, kw['l_start'], kw['l_len']) om@2: om@2: om@2: def flag2mode(flags): om@2: om@2: """Turn os flags into mode chars""" om@2: om@2: md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} om@2: m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] om@2: if flags | os.O_APPEND: om@2: m = m.replace('w', 'a', 1) om@2: return m om@2: om@2: om@2: def main(): om@2: om@2: usage = """ om@2: mirror the a file tree from some point on. om@2: om@2: """ + Fuse.fusage om@2: om@2: # launch the Fuse server om@2: server = MirrorFuse(version = "%prog " + __version__, usage = usage, dash_s_do = 'setsingle') om@2: server.parser.add_option(mountopt = "root", metavar = "PATH", default='/', help="mirror filesystem from under PATH [default: %default]") om@2: server.parser.add_option(mountopt = "os_server_url", metavar = "URL", default='http://localhost:8080', help="URL to OpenSecurity Server [default: %default]") om@2: server.parse(values=server, errex=1) om@2: om@2: try: om@2: if server.fuse_args.mount_expected(): om@2: os.chdir(server.root) om@2: except OSError: om@2: print >> sys.stderr, "can't enter root of underlying filesystem" om@2: sys.exit(1) om@2: om@2: server.main() om@2: om@2: om@2: # start om@2: if __name__ == "__main__": om@2: main() om@2: om@2: