"Fossies" - the Fresh Open Source Software Archive

Member "Tardis-1.2.1/src/Tardis/CacheDir.py" (9 Jun 2021, 6804 Bytes) of package /linux/privat/Tardis-1.2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "CacheDir.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.1.5_vs_1.2.1.

    1 # vim: set et sw=4 sts=4 fileencoding=utf-8:
    2 #
    3 # Tardis: A Backup System
    4 # Copyright 2013-2020, Eric Koldinger, All Rights Reserved.
    5 # kolding@washington.edu
    6 #
    7 # Redistribution and use in source and binary forms, with or without
    8 # modification, are permitted provided that the following conditions are met:
    9 #
   10 #     * Redistributions of source code must retain the above copyright
   11 #       notice, this list of conditions and the following disclaimer.
   12 #     * Redistributions in binary form must reproduce the above copyright
   13 #       notice, this list of conditions and the following disclaimer in the
   14 #       documentation and/or other materials provided with the distribution.
   15 #     * Neither the name of the copyright holder nor the
   16 #       names of its contributors may be used to endorse or promote products
   17 #       derived from this software without specific prior written permission.
   18 #
   19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   23 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29 # POSSIBILITY OF SUCH DAMAGE.
   30 
   31 import os
   32 import os.path
   33 import socket
   34 import logging
   35 import shutil
   36 import configparser
   37 
   38 from functools import reduce
   39 
   40 from . import Defaults
   41 
   42 logger = logging.getLogger("CacheDir")
   43 
   44 class CacheDirDoesNotExist(Exception):
   45     pass
   46 
   47 PARTSIZE    = "partsize"
   48 PARTS       = "parts"
   49 CONFIGFILE  = ".cachedir"
   50 
   51 class CacheDir:
   52     def __init__(self, root, parts=2, partsize=2, create=True, user=None, group=None, skipFile=Defaults.getDefault("TARDIS_SKIP")):
   53         self.root = os.path.abspath(root)
   54         self.user  = user if user else -1
   55         self.group = group if group else -1
   56         self.chown = user or group
   57 
   58 
   59         if not os.path.isdir(self.root):
   60             if create:
   61                 os.makedirs(self.root)
   62                 if self.chown:
   63                     os.chown(self.root, self.user, self.group)
   64                 if skipFile:
   65                     with open(os.path.join(self.root, skipFile), 'a'):
   66                         pass
   67             else:
   68                 raise CacheDirDoesNotExist("CacheDir does not exist: " + root)
   69 
   70         # Read a config file if it exists, create it if not
   71         defaults = {"parts": str(parts), "partsize": str(partsize) }
   72         section = "CacheDir"
   73 
   74         configFile = os.path.join(self.root, CONFIGFILE)
   75         config = configparser.ConfigParser(defaults)
   76         config.add_section(section)
   77         config.read(configFile)
   78 
   79         try:
   80             self.parts = int(config.get(section, PARTS))
   81             self.partsize = int(config.get(section, PARTSIZE))
   82         except ValueError:
   83             logger.error("Invalid configuration.  Using defaults")
   84             self.parts    = defaults[PARTS]
   85             self.partsize = defaults[PARTSIZE]
   86 
   87         config.set(section, PARTS,    str(self.parts))
   88         config.set(section, PARTSIZE, str(self.partsize))
   89         if create:
   90             try:
   91                 with open(configFile, "w") as f:
   92                     config.write(f)
   93             except Exception as e:
   94                 logger.warning("Could not write configpration file: %s: %s", configFile, str(e))
   95 
   96     def comps(self, name):
   97         return [name[(i * self.partsize):((i + 1) * self.partsize)] for i in range(0, self.parts)]
   98 
   99     def dirPath(self, name):
  100         return reduce(os.path.join, self.comps(name), self.root)
  101 
  102     def path(self, name):
  103         return os.path.join(self.dirPath(name), name)
  104 
  105     def exists(self, name):
  106         return os.path.lexists(self.path(name))
  107 
  108     def size(self, name):
  109         try:
  110             s = os.stat(self.path(name))
  111             return s.st_size
  112         except:
  113             return 0
  114 
  115     def mkdir(self, name):
  116         directory = self.dirPath(name)
  117         if not os.path.isdir(directory):
  118             os.makedirs(directory)
  119             if self.chown:
  120                 path = self.root
  121                 for i in self.comps(name):
  122                     path = os.path.join(path, i)
  123                     os.chown(path, self.user, self.group)
  124 
  125     def open(self, name, mode, streaming=False):
  126         iswrite = mode.startswith('w') or mode.startswith('a')
  127         if iswrite:
  128             self.mkdir(name)
  129         path = self.path(name)
  130         f = open(path, mode)
  131         if iswrite and self.chown:
  132             os.fchown(f.fileno(), self.user, self.group)
  133         return f
  134 
  135     def insert(self, name, source, link=False):
  136         self.mkdir(name)
  137         path = self.path(name)
  138         if link:
  139             os.link(source, path)
  140         else:
  141             shutil.move(source, path)
  142         if self.chown:
  143             os.chown(path, self.user, self.group)
  144 
  145     def link(self, source, dest, soft=True):
  146         self.mkdir(dest)
  147         dstpath = self.path(dest)
  148         if soft:
  149             srcpath = os.path.relpath(self.path(source), self.dirPath(dest))
  150             os.symlink(srcpath, dstpath)
  151         else:
  152             srcpath = self.path(source)
  153             os.link(srcpath, dstpath)
  154         return True
  155 
  156     def remove(self, name):
  157         try:
  158             os.remove(self.path(name))
  159             return True
  160         except OSError:
  161             return False
  162 
  163     def removeSuffixes(self, name, suffixes):
  164         deleted = 0
  165         for suffix in suffixes:
  166             if self.remove(name + suffix):
  167                 #logger.debug("Removed %s", name + suffix)
  168                 deleted += 1
  169         return deleted
  170 
  171     def move(self, oldname, newname):
  172         try:
  173             self.mkdir(newname)
  174             os.rename(self.path(oldname), self.path(newname))
  175             return True
  176         except OSError:
  177             return False
  178 
  179 if __name__ == "__main__":
  180     test = "abcdefghijklmnop"
  181     testPath = os.path.join("cache", socket.gethostname())
  182     c = CacheDir(testPath, 4, 2, True)
  183     print(c.comps(test))
  184     print(c.dirPath(test))
  185     print(c.path(test))
  186     print(c.exists(test))
  187 
  188     try:
  189         c.open(test, "r")
  190     except IOError as ex:
  191         print("Caught IOError")
  192 
  193     with c.open(test, "w") as fd:
  194         fd.write("I'm henry the 8'th I am\n")
  195         fd.write("Henry the 8th, I am I am\n")
  196 
  197     with c.open(test, "r") as fd:
  198         for line in fd:
  199             print(line, end=' ')
  200     print(c.exists(test))