1# Copyright 2002 Ben Escoto 2# 3# This file is part of rdiff-backup. 4# 5# rdiff-backup is free software; you can redistribute it and/or modify 6# under the terms of the GNU General Public License as published by the 7# Free Software Foundation; either version 2 of the License, or (at your 8# option) any later version. 9# 10# rdiff-backup is distributed in the hope that it will be useful, but 11# WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with rdiff-backup; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18# 02110-1301, USA 19"""Provides functions and *ITR classes, for writing increment files""" 20 21import os 22from . import Globals, Time, rpath, Rdiff, log, statistics, robust 23 24 25def Increment(new, mirror, incpref): 26 """Main file incrementing function, returns inc file created 27 28 new is the file on the active partition, 29 mirror is the mirrored file from the last backup, 30 incpref is the prefix of the increment file. 31 32 This function basically moves the information about the mirror 33 file to incpref. 34 35 """ 36 log.Log("Incrementing mirror file %s" % mirror.get_safepath(), 5) 37 if ((new and new.isdir()) or mirror.isdir()) and not incpref.lstat(): 38 incpref.mkdir() 39 40 if not mirror.lstat(): 41 incrp = makemissing(incpref) 42 elif mirror.isdir(): 43 incrp = makedir(mirror, incpref) 44 elif new.isreg() and mirror.isreg(): 45 incrp = makediff(new, mirror, incpref) 46 else: 47 incrp = makesnapshot(mirror, incpref) 48 statistics.process_increment(incrp) 49 return incrp 50 51 52def makemissing(incpref): 53 """Signify that mirror file was missing""" 54 incrp = get_inc(incpref, "missing") 55 incrp.touch() 56 return incrp 57 58 59def iscompressed(mirror): 60 """Return true if mirror's increments should be compressed""" 61 return (Globals.compression 62 and not Globals.no_compression_regexp.match(mirror.path)) 63 64 65def makesnapshot(mirror, incpref): 66 """Copy mirror to incfile, since new is quite different""" 67 compress = iscompressed(mirror) 68 if compress and mirror.isreg(): 69 snapshotrp = get_inc(incpref, b"snapshot.gz") 70 else: 71 snapshotrp = get_inc(incpref, b"snapshot") 72 73 if mirror.isspecial(): # check for errors when creating special increments 74 eh = robust.get_error_handler("SpecialFileError") 75 if robust.check_common_error(eh, rpath.copy_with_attribs, 76 (mirror, snapshotrp, compress)) == 0: 77 snapshotrp.setdata() 78 if snapshotrp.lstat(): 79 snapshotrp.delete() 80 snapshotrp.touch() 81 else: 82 rpath.copy_with_attribs(mirror, snapshotrp, compress) 83 return snapshotrp 84 85 86def makediff(new, mirror, incpref): 87 """Make incfile which is a diff new -> mirror""" 88 compress = iscompressed(mirror) 89 if compress: 90 diff = get_inc(incpref, b"diff.gz") 91 else: 92 diff = get_inc(incpref, b"diff") 93 94 old_new_perms, old_mirror_perms = (None, None) 95 96 if Globals.process_uid != 0: 97 # Check for unreadable files 98 if not new.readable(): 99 old_new_perms = new.getperms() 100 new.chmod(0o400 | old_new_perms) 101 if not mirror.readable(): 102 old_mirror_perms = mirror.getperms() 103 mirror.chmod(0o400 | old_mirror_perms) 104 105 Rdiff.write_delta(new, mirror, diff, compress) 106 107 if old_new_perms: 108 new.chmod(old_new_perms) 109 if old_mirror_perms: 110 mirror.chmod(old_mirror_perms) 111 112 rpath.copy_attribs_inc(mirror, diff) 113 return diff 114 115 116def makedir(mirrordir, incpref): 117 """Make file indicating directory mirrordir has changed""" 118 dirsign = get_inc(incpref, "dir") 119 dirsign.touch() 120 rpath.copy_attribs_inc(mirrordir, dirsign) 121 return dirsign 122 123 124def get_inc(rp, typestr, time=None): 125 """Return increment like rp but with time and typestr suffixes 126 127 To avoid any quoting, the returned rpath has empty index, and the 128 whole filename is in the base (which is not quoted). 129 130 """ 131 if time is None: 132 time = Time.prevtime 133 134 def addtostr(s): 135 return b'.'.join(map(os.fsencode, (s, Time.timetostring(time), typestr))) 136 137 if rp.index: 138 incrp = rp.__class__(rp.conn, rp.base, 139 rp.index[:-1] + (addtostr(rp.index[-1]), )) 140 else: 141 dirname, basename = rp.dirsplit() 142 incrp = rp.__class__(rp.conn, dirname, (addtostr(basename), )) 143 assert not incrp.lstat(), incrp 144 return incrp 145