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