Package duplicity :: Module file_naming
[hide private]
[frames] | no frames]

Source Code for Module duplicity.file_naming

  1  # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- 
  2  # 
  3  # Copyright 2002 Ben Escoto <ben@emerose.org> 
  4  # Copyright 2007 Kenneth Loafman <kenneth@loafman.com> 
  5  # 
  6  # This file is part of duplicity. 
  7  # 
  8  # Duplicity is free software; you can redistribute it and/or modify it 
  9  # under the terms of the GNU General Public License as published by the 
 10  # Free Software Foundation; either version 2 of the License, or (at your 
 11  # option) any later version. 
 12  # 
 13  # Duplicity is distributed in the hope that it will be useful, but 
 14  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 16  # General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with duplicity; if not, write to the Free Software Foundation, 
 20  # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 21   
 22  """Produce and parse the names of duplicity's backup files""" 
 23   
 24  import re 
 25  from duplicity import dup_time 
 26  from duplicity import globals 
 27   
 28  full_vol_re = re.compile("^duplicity-full" 
 29                           "\\.(?P<time>.*?)" 
 30                           "\\.vol(?P<num>[0-9]+)" 
 31                           "\\.difftar" 
 32                           "(?P<partial>(\\.part))?" 
 33                           "($|\\.)") 
 34   
 35  full_vol_re_short = re.compile("^df" 
 36                                 "\\.(?P<time>[0-9a-z]+?)" 
 37                                 "\\.(?P<num>[0-9a-z]+)" 
 38                                 "\\.dt" 
 39                                 "(?P<partial>(\\.p))?" 
 40                                 "($|\\.)") 
 41   
 42  full_manifest_re = re.compile("^duplicity-full" 
 43                                "\\.(?P<time>.*?)" 
 44                                "\\.manifest" 
 45                                "(?P<partial>(\\.part))?" 
 46                                "($|\\.)") 
 47   
 48  full_manifest_re_short = re.compile("^df" 
 49                                      "\\.(?P<time>[0-9a-z]+?)" 
 50                                      "\\.m" 
 51                                      "(?P<partial>(\\.p))?" 
 52                                      "($|\\.)") 
 53   
 54  inc_vol_re = re.compile("^duplicity-inc" 
 55                          "\\.(?P<start_time>.*?)" 
 56                          "\\.to\\.(?P<end_time>.*?)" 
 57                          "\\.vol(?P<num>[0-9]+)" 
 58                          "\\.difftar" 
 59                          "($|\\.)") 
 60   
 61  inc_vol_re_short = re.compile("^di" 
 62                                "\\.(?P<start_time>[0-9a-z]+?)" 
 63                                "\\.(?P<end_time>[0-9a-z]+?)" 
 64                                "\\.(?P<num>[0-9a-z]+)" 
 65                                "\\.dt" 
 66                                "($|\\.)") 
 67   
 68  inc_manifest_re = re.compile("^duplicity-inc" 
 69                               "\\.(?P<start_time>.*?)" 
 70                               "\\.to" 
 71                               "\\.(?P<end_time>.*?)" 
 72                               "\\.manifest" 
 73                               "(?P<partial>(\\.part))?" 
 74                               "(\\.|$)") 
 75   
 76  inc_manifest_re_short = re.compile("^di" 
 77                                     "\\.(?P<start_time>[0-9a-z]+?)" 
 78                                     "\\.(?P<end_time>[0-9a-z]+?)" 
 79                                     "\\.m" 
 80                                     "(?P<partial>(\\.p))?" 
 81                                     "(\\.|$)") 
 82   
 83  full_sig_re = re.compile("^duplicity-full-signatures" 
 84                           "\\.(?P<time>.*?)" 
 85                           "\\.sigtar" 
 86                           "(?P<partial>(\\.part))?" 
 87                           "(\\.|$)") 
 88   
 89  full_sig_re_short = re.compile("^dfs" 
 90                                 "\\.(?P<time>[0-9a-z]+?)" 
 91                                 "\\.st" 
 92                                 "(?P<partial>(\\.p))?" 
 93                                 "(\\.|$)") 
 94   
 95  new_sig_re = re.compile("^duplicity-new-signatures" 
 96                          "\\.(?P<start_time>.*?)" 
 97                          "\\.to" 
 98                          "\\.(?P<end_time>.*?)" 
 99                          "\\.sigtar" 
100                          "(?P<partial>(\\.part))?" 
101                          "(\\.|$)") 
102   
103  new_sig_re_short = re.compile("^dns" 
104                                "\\.(?P<start_time>[0-9a-z]+?)" 
105                                "\\.(?P<end_time>[0-9a-z]+?)" 
106                                "\\.st" 
107                                "(?P<partial>(\\.p))?" 
108                                "(\\.|$)") 
109   
110   
111 -def to_base36(n):
112 """ 113 Return string representation of n in base 36 (use 0-9 and a-z) 114 """ 115 div, mod = divmod(n, 36) 116 if mod <= 9: 117 last_digit = str(mod) 118 else: 119 last_digit = chr(ord('a') + mod - 10) 120 if n == mod: 121 return last_digit 122 else: 123 return to_base36(div)+last_digit
124 125
126 -def from_base36(s):
127 """ 128 Convert string s in base 36 to long int 129 """ 130 total = 0L 131 for i in range(len(s)): 132 total *= 36 133 digit_ord = ord(s[i]) 134 if ord('0') <= digit_ord <= ord('9'): 135 total += digit_ord - ord('0') 136 elif ord('a') <= digit_ord <= ord('z'): 137 total += digit_ord - ord('a') + 10 138 else: 139 assert 0, "Digit %s in %s not in proper range" % (s[i], s) 140 return total
141 142
143 -def get_suffix(encrypted, gzipped):
144 """ 145 Return appropriate suffix depending on status of 146 encryption, compression, and short_filenames. 147 """ 148 assert not (encrypted and gzipped) 149 if encrypted: 150 if globals.short_filenames: 151 suffix = '.g' 152 else: 153 suffix = ".gpg" 154 elif gzipped: 155 if globals.short_filenames: 156 suffix = ".z" 157 else: 158 suffix = '.gz' 159 else: 160 suffix = "" 161 return suffix
162 163
164 -def get(type, volume_number = None, manifest = False, 165 encrypted = False, gzipped = False, partial = False):
166 """ 167 Return duplicity filename of specified type 168 169 type can be "full", "inc", "full-sig", or "new-sig". volume_number 170 can be given with the full and inc types. If manifest is true the 171 filename is of a full or inc manifest file. 172 """ 173 assert dup_time.curtimestr 174 assert not (encrypted and gzipped) 175 suffix = get_suffix(encrypted, gzipped) 176 part_string = "" 177 if globals.short_filenames: 178 if partial: 179 part_string = ".p" 180 else: 181 if partial: 182 part_string = ".part" 183 184 if type == "full-sig" or type == "new-sig": 185 assert not volume_number and not manifest 186 assert not (volume_number and part_string) 187 if type == "full-sig": 188 if globals.short_filenames: 189 return ("dfs.%s.st%s%s" % 190 (to_base36(dup_time.curtime), part_string, suffix)) 191 else: 192 return ("duplicity-full-signatures.%s.sigtar%s%s" % 193 (dup_time.curtimestr, part_string, suffix)) 194 elif type == "new-sig": 195 if globals.short_filenames: 196 return ("dns.%s.%s.st%s%s" % 197 (to_base36(dup_time.prevtime), to_base36(dup_time.curtime), 198 part_string, suffix)) 199 else: 200 return ("duplicity-new-signatures.%s.to.%s.sigtar%s%s" % 201 (dup_time.prevtimestr, dup_time.curtimestr, 202 part_string, suffix)) 203 else: 204 assert volume_number or manifest 205 assert not (volume_number and manifest) 206 if volume_number: 207 if globals.short_filenames: 208 vol_string = "%s.dt" % to_base36(volume_number) 209 else: 210 vol_string = "vol%d.difftar" % volume_number 211 else: 212 if globals.short_filenames: 213 vol_string = "m" 214 else: 215 vol_string = "manifest" 216 if type == "full": 217 if globals.short_filenames: 218 return ("df.%s.%s%s%s" % (to_base36(dup_time.curtime), 219 vol_string, part_string, suffix)) 220 else: 221 return ("duplicity-full.%s.%s%s%s" % (dup_time.curtimestr, 222 vol_string, part_string, suffix)) 223 elif type == "inc": 224 if globals.short_filenames: 225 return ("di.%s.%s.%s%s%s" % (to_base36(dup_time.prevtime), 226 to_base36(dup_time.curtime), 227 vol_string, part_string, suffix)) 228 else: 229 return ("duplicity-inc.%s.to.%s.%s%s%s" % (dup_time.prevtimestr, 230 dup_time.curtimestr, 231 vol_string, part_string, suffix)) 232 else: 233 assert 0
234 235
236 -def parse(filename):
237 """ 238 Parse duplicity filename, return None or ParseResults object 239 """ 240 filename = filename.lower() 241 def str2time(timestr, short): 242 """ 243 Return time in seconds if string can be converted, None otherwise 244 """ 245 if short: 246 t = from_base36(timestr) 247 else: 248 try: 249 t = dup_time.genstrtotime(timestr.upper()) 250 except dup_time.TimeException: 251 return None 252 return t
253 254 def get_vol_num(s, short): 255 """ 256 Return volume number from volume number string 257 """ 258 if short: 259 return from_base36(s) 260 else: 261 return int(s) 262 263 def check_full(): 264 """ 265 Return ParseResults if file is from full backup, None otherwise 266 """ 267 short = True 268 m1 = full_vol_re_short.search(filename) 269 m2 = full_manifest_re_short.search(filename) 270 if not m1 and not m2 and not globals.short_filenames: 271 short = False 272 m1 = full_vol_re.search(filename) 273 m2 = full_manifest_re.search(filename) 274 if m1 or m2: 275 t = str2time((m1 or m2).group("time"), short) 276 if t: 277 if m1: 278 return ParseResults("full", time = t, 279 volume_number = get_vol_num(m1.group("num"), short)) 280 else: 281 return ParseResults("full", time = t, manifest = True, 282 partial = (m2.group("partial") != None)) 283 return None 284 285 def check_inc(): 286 """ 287 Return ParseResults if file is from inc backup, None otherwise 288 """ 289 short = True 290 m1 = inc_vol_re_short.search(filename) 291 m2 = inc_manifest_re_short.search(filename) 292 if not m1 and not m2 and not globals.short_filenames: 293 short = False 294 m1 = inc_vol_re.search(filename) 295 m2 = inc_manifest_re.search(filename) 296 if m1 or m2: 297 t1 = str2time((m1 or m2).group("start_time"), short) 298 t2 = str2time((m1 or m2).group("end_time"), short) 299 if t1 and t2: 300 if m1: 301 return ParseResults("inc", start_time = t1, 302 end_time = t2, volume_number = get_vol_num(m1.group("num"), short)) 303 else: 304 return ParseResults("inc", start_time = t1, end_time = t2, manifest = 1, 305 partial = (m2.group("partial") != None)) 306 return None 307 308 def check_sig(): 309 """ 310 Return ParseResults if file is a signature, None otherwise 311 """ 312 short = True 313 m = full_sig_re_short.search(filename) 314 if not m and not globals.short_filenames: 315 short = False 316 m = full_sig_re.search(filename) 317 if m: 318 t = str2time(m.group("time"), short) 319 if t: 320 return ParseResults("full-sig", time = t, 321 partial = (m.group("partial") != None)) 322 else: 323 return None 324 325 short = True 326 m = new_sig_re_short.search(filename) 327 if not m and not globals.short_filenames: 328 short = False 329 m = new_sig_re.search(filename) 330 if m: 331 t1 = str2time(m.group("start_time"), short) 332 t2 = str2time(m.group("end_time"), short) 333 if t1 and t2: 334 return ParseResults("new-sig", start_time = t1, end_time = t2, 335 partial = (m.group("partial") != None)) 336 return None 337 338 def set_encryption_or_compression(pr): 339 """ 340 Set encryption and compression flags in ParseResults pr 341 """ 342 if (filename.endswith('.z') or 343 not globals.short_filenames and filename.endswith('gz')): 344 pr.compressed = 1 345 else: 346 pr.compressed = None 347 348 if (filename.endswith('.g') or 349 not globals.short_filenames and filename.endswith('.gpg')): 350 pr.encrypted = 1 351 else: 352 pr.encrypted = None 353 354 pr = check_full() 355 if not pr: 356 pr = check_inc() 357 if not pr: 358 pr = check_sig() 359 if not pr: 360 return None 361 set_encryption_or_compression(pr) 362 return pr 363 364
365 -class ParseResults:
366 """ 367 Hold information taken from a duplicity filename 368 """
369 - def __init__(self, type, manifest = None, volume_number = None, 370 time = None, start_time = None, end_time = None, 371 encrypted = None, compressed = None, partial = False):
372 373 assert type in ["full-sig", "new-sig", "inc", "full"] 374 375 self.type = type 376 if type == "inc" or type == "full": 377 assert manifest or volume_number 378 if type == "inc" or type == "new-sig": 379 assert start_time and end_time 380 else: 381 assert time 382 383 self.manifest = manifest 384 self.volume_number = volume_number 385 self.time = time 386 self.start_time, self.end_time = start_time, end_time 387 388 self.compressed = compressed # true if gzip compressed 389 self.encrypted = encrypted # true if gpg encrypted 390 391 self.partial = partial
392