def collectFileInfo(filename, tardis, crypt): """ Collect information about a file in all the backupsets Note that we sometimes need to reduce the pathlength. It's done here, on a directory by directory basis. """ lookup = crypt.encryptPath(filename) if crypt else filename fInfos = {} lInfo = {} if filename == '/': fInfos = makeFakeRootInfo() elif args.reduce: for bset in backupSets: temp = lookup temp = Util.reducePath(tardis, bset['backupset'], temp, args.reduce) # No crypt, as we've already run that to get to lookup if lInfo and lInfo['firstset'] <= bset['backupset'] <= lInfo['lastset']: fInfos[bset['backupset']] = lInfo else: lInfo = tardis.getFileInfoByPath(temp, bset['backupset']) fInfos[bset['backupset']] = lInfo else: fSet = backupSets[0]['backupset'] lSet = backupSets[-1]['backupset'] for (bset, info) in tardis.getFileInfoByPathForRange(lookup, fSet, lSet): logger.debug("Bset: %s, info: %s", bset, info) fInfos[bset] = info return fInfos
def collectFileInfo(filename, tardis, crypt): """ Collect information about a file in all the backupsets Note that we sometimes need to reduce the pathlength. It's done here, on a directory by directory basis. """ lookup = crypt.encryptPath(filename) if crypt else filename fInfos = {} lInfo = {} if filename == '/': fInfos = makeFakeRootInfo() elif args.reduce: for bset in backupSets: temp = lookup temp = Util.reducePath(tardis, bset['backupset'], temp, args.reduce) # No crypt, as we've already run that to get to lookup if lInfo and lInfo['firstset'] <= bset['backupset'] <= lInfo['lastset']: fInfos[bset['backupset']] = lInfo else: lInfo = tardis.getFileInfoByPath(temp, bset['backupset']) fInfos[bset['backupset']] = lInfo else: fSet = backupSets[0]['backupset'] lSet = backupSets[-1]['backupset'] for (bset, info) in tardis.getFileInfoByPathForRange(lookup, fSet, lSet): fInfos[bset] = info return fInfos
def findLastPath(path, reduce): logger.debug("findLastPath: %s", path) # Search all the sets in backwards order bsets = list(tardis.listBackupSets()) for bset in reversed(bsets): logger.debug("Checking for path %s in %s (%d)", path, bset['name'], bset['backupset']) tmp = Util.reducePath(tardis, bset['backupset'], os.path.abspath(path), reduce, crypt) tmp2 = tmp if args.crypt and crypt: tmp2 = crypt.encryptPath(tmp) info = tardis.getFileInfoByPath(tmp2, bset['backupset']) if info: logger.debug("Found %s in backupset %s: %s", path, bset['name'], tmp) return bset['backupset'], tmp, bset['name'] return (None, None, None)
def getFileInfo(path, bset, tardis, crypt, reducePath): p = Util.reducePath(tardis, bset, path, reducePath, crypt) e = crypt.encryptPath(p) if crypt else p info = tardis.getFileInfoByPath(e, bset) return info, p
def main(): global logger, crypt, tardis, args, owMode args = parseArgs() logger = Util.setupLogging(args.verbose, stream=sys.stderr) try: password = Util.getPassword(args.password, args.passwordfile, args.passwordprog, prompt="Password for %s: " % (args.client)) args.password = None (tardis, cache, crypt) = Util.setupDataConnection(args.database, args.client, password, args.keys, args.dbname, args.dbdir) r = Regenerator.Regenerator(cache, tardis, crypt=crypt) except TardisDB.AuthenticationException as e: logger.error("Authentication failed. Bad password") #if args.exceptions: #logger.exception(e) sys.exit(1) except Exception as e: logger.error("Regeneration failed: %s", e) sys.exit(1) try: bset = False if args.date: cal = parsedatetime.Calendar() (then, success) = cal.parse(args.date) if success: timestamp = time.mktime(then) logger.info("Using time: %s", time.asctime(then)) bsetInfo = tardis.getBackupSetInfoForTime(timestamp) if bsetInfo and bsetInfo['backupset'] != 1: bset = bsetInfo['backupset'] logger.debug("Using backupset: %s %d", bsetInfo['name'], bsetInfo['backupset']) else: logger.critical("No backupset at date: %s (%s)", args.date, time.asctime(then)) sys.exit(1) else: logger.critical("Could not parse date string: %s", args.date) sys.exit(1) elif args.backup: #bsetInfo = tardis.getBackupSetInfo(args.backup) bsetInfo = Util.getBackupSet(tardis, args.backup) if bsetInfo: bset = bsetInfo['backupset'] else: logger.critical("No backupset at for name: %s", args.backup) sys.exit(1) outputdir = None output = sys.stdout.buffer outname = None linkDB = None owMode = overwriteNames[args.overwrite] if args.output: if len(args.files) > 1: outputdir = mkOutputDir(args.output) elif os.path.isdir(args.output): outputdir = args.output else: outname = args.output logger.debug("Outputdir: %s Outname: %s", outputdir, outname) if args.hardlinks: linkDB = {} #if args.cksum and (args.settime or args.setperm): #logger.warning("Unable to set time or permissions on files specified by checksum.") permChecker = setupPermissionChecks() retcode = 0 hasher = None # do the work here if args.cksum: for i in args.files: try: if args.auth: hasher = Util.getHash(crypt) ckname = i if args.recovername: ckname = recoverName(i) f = r.recoverChecksum(i, args.auth) if f: logger.info("Recovering checksum %s", ckname) # Generate an output name if outname: # Note, this should ONLY be true if only one file output = open(outname, "wb") elif outputdir: outname = os.path.join(outputdir, ckname) if os.path.exists(outname) and owMode == OW_NEVER: logger.warning("File %s exists. Skipping", outname) continue logger.debug("Writing output to %s", outname) output = open(outname, "wb") elif outname: # Note, this should ONLY be true if only one file if os.path.exists(outname) and owMode == OW_NEVER: logger.warning("File %s exists. Skipping", outname) continue output = file(outname, "wb") try: x = f.read(64 * 1024) while x: output.write(x) if hasher: hasher.update(x) x = f.read(64 * 1024) except Exception as e: logger.error("Unable to read file: {}: {}".format(i, repr(e))) raise finally: f.close() if output is not sys.stdout.buffer: output.close() if args.auth: logger.debug("Checking authentication") outname = doAuthenticate(outname, i, hasher.hexdigest()) except TardisDB.AuthenticationException as e: logger.error("Authentication failed. Bad password") #if args.exceptions: #logger.exception(e) sys.exit(1) except Exception as e: logger.error("Could not recover: %s: %s", i, e) if args.exceptions: logger.exception(e) retcode += 1 else: # Not checksum, but acutal pathnames for i in args.files: try: i = os.path.abspath(i) logger.info("Processing %s", Util.shortPath(i)) path = None f = None if args.last: (bset, path, name) = findLastPath(i, args.reduce) if bset is None: logger.error("Unable to find a latest version of %s", i) raise Exception("Unable to find a latest version of " + i) logger.info("Found %s in backup set %s", i, name) elif args.reduce: path = Util.reducePath(tardis, bset, i, args.reduce, crypt) logger.debug("Reduced path %s to %s", path, i) if not path: logger.error("Unable to find a compute path for %s", i) raise Exception("Unable to compute path for " + i) else: path = i if args.crypt and crypt: actualPath = crypt.encryptPath(path) else: actualPath = path logger.debug("Actual path is %s -- %s", actualPath, bset) info = tardis.getFileInfoByPath(actualPath, bset) if info: retcode += recoverObject(r, info, bset, outputdir, path, linkDB, name=outname, authenticate=args.auth) else: logger.error("Could not recover info for %s (File not found)", i) retcode += 1 except TardisDB.AuthenticationException as e: logger.error("Authentication failed. Bad password") #if args.exceptions: #logger.exception(e) sys.exit(1) except Exception as e: logger.error("Could not recover: %s: %s", i, e) if args.exceptions: logger.exception(e) except KeyboardInterrupt: logger.error("Recovery interupted") except TardisDB.AuthenticationException as e: logger.error("Authentication failed. Bad password") if args.exceptions: logger.exception(e) except Exception as e: logger.error("Regeneration failed: %s", e) if args.exceptions: logger.exception(e) if errors: logger.warning("%d files could not be recovered.") return retcode