## @file csfile.py # @brief Provide a module to read, write and treat with a csback # checksumfiles. # # ----------------------------------------------------------------------------- # # $Id$ # @author Daniel Armbruster # \date 15/09/2011 # # Purpose: Provide a module to read, write and treat with a csback # checksumfiles. # # ---- # This file is part of csback. # # csback is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # csback is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with csback. If not, see . # ---- # # Copyright (c) 2011 by Daniel Armbruster # # REVISIONS and CHANGES # 15/09/2011 V0.1 Daniel Armbruster # # ============================================================================= import os import re import sys import hashlib from datetime import datetime __version__ = "V0.1" __subversion__ = "$Id$" __license__ = "GPLv2" __author__ = "Daniel Armbruster" __copyright__ = "Copyright (c) 2012 by Daniel Armbruster" # ----------------------------------------------------------------------------- # global variables chunkSize = 131072 # 128kB # ----------------------------------------------------------------------------- class CsFileError(Exception): def __init__(self, msg): self.msg = msg def display(self): sys.stderr.write("csFile (ERROR): " + self.msg + "\n") # ----------------------------------------------------------------------------- class CsFile: def __init__(self, filepath, hashfunc='sha256'): self.__filepath = filepath self.__filename = ".cs" self.__cslines = [] self.__hashfunc = hashfunc createFile() def createFile(self): path = self.__filepath+os.sep+self.__filename if not os.path.isfile(path): try: csfile = open(path, 'w') finally: csfile.close() def read(self): path = self.__filepath+os.sep+self.__filename if not os.path.isfile(path): raise CsFileError("CSFILE does not exist.") try: csfile = open(path) self.__cslines = [CsLine(line.split()) for line in csfile \ if len(line.rstrip()) and line[0] != '#'] finally: csfile.close() def append(self, cslines): path = self.__filepath+os.sep+self.__filename # Maybe not necessary to raise an exception here if 0 == len(cslines): raise CsFileError("Invalid argument. Empty list.") try: csfile = open(path, 'a') for csline in cslines: if isinstance(csline, CsLine): csfile.write(str(csline) + '\n') else: raise CsFileError("Argument must be of type CsLine.") except IOError as err: raise CsFileError(err.msg) finally: csfile.close() def update(self, regexes=[]): if not isinstance(regexes, list) raise CsFileError("Pass regular expressions in a list of strings") # fetch cslines in current csfile read() # IMPORTANT NOTE: Check again if it is more convenient to whole path or sep = os.sep registeredFiles = [csline.path.split(sep)[len(csline.path.split(sep))] \ for csline in self.__cslines] # fetch files excluding regex matches newFiles = list(set([file for file in os.listdir(self.__filepath) \ if os.path.isfile(file) for regex in regexes \ if None == re.search(regex,file)])) # exclude registered files newFiles = list(set([file for file in newFiles \ for registeredFile in registeredFiles if registeredFile != file])) # generate cslines of newFiles csLines = [CsLine(self.__filepath+os.sep+file, self.__hashfunc) \ for file in newFiles] for csline in csLines csline.generate(chunkSize) append(csLines) def checkLines(self, srcDir): if 0 == len(self.__cslines): raise CsFileError("CSFILE does not contain any lines.") for line in self.__cslines: # TODO: get here filename of file in checksum line.check(srcDir) def displayLines(self): if 0 == len(self.__cslines): raise CsFileError("CSFILE does not contain any lines.") for line in self.__cslines: sys.stdout.write(line) def addLine(self, csline): if isinstance(csline, CsLine): self.__cslines.append(csline) else: raise CsFileError("Argument must be of type CsLine.") def removeLine(self, index): if 0 <= index and len(self.__cslines) >= index: del self.__cslines[index] else: raise CsFileError("Index out of range.") # ----------------------------------------------------------------------------- class CsLine: def __init__(self, path, hashfunc='sha256'): self.checksum = '' self.path = path self.hashfunc = hashfunc self.creationDateFile = '' self.creationLocationChecksum = '' self.creationDateChecksum = '' self.dateLastCheck = '' self.statusLastCheck = '' def __init__(self, argList): if not isinstance(argList, list): raise CsFileError("Invalid argument.") self.checksum = argList[0] self.path = argList[1] self.hashfunc = argList[2] self.creationDateFile = argList[3] self.creationLocationChecksum = argList[4] self.creationDateChecksum = argList[5] self.dateLastCheck = argList[6] self.statusLastCheck = argList[7] def generate(self, chunkSize): # generate checksum try: hashfunc = hashlib.new(self.hashfunc) blockSize = chunkSize * hashfunc.block_size with open(self.path, "rb") as file: for chunk in iter(lambda: f.read(blockSize), ''): hasfunc.update(chunk) self.checksum = hashfunc.hexdigest() except IOError as err: raise CsFileError(err.msg) # set remaining data self.creationDateFile = \ datetime.fromtimestamp(os.path.getctime(self.path)).strftime( \ "%Y/%m/%d-%H:%M:%S") self.creationLocationChecksum = os.uname()[1] self.creationDateChecksum = datetime.now().strftime("%Y/%m/%d-%H:%M:%S") self.dateLastCheck = self.creationDateChecksum self.statusLastCheck = 'ok' def check(self, src=''): pass def __str__(self): return '{0} {1} {2} {3} {4} {5} {6} {7}'.format(self.checksum, self.path, \ self.hashfunc, self.creationDateFile, self.creationLocationChecksum, \ self.creationDateChecksum, self.dateLastCheck, self.statusLastCheck) # ----------------------------------------------------------------------------- if __name__ == '__main__': pass # ----- END OF csfile.py -----