bpo-32713: Fix tarfile.itn for large/negative float values. (GH-5434)
[python-delta-tar] / backup.py
1 #!/usr/bin/env python3
2
3 # Copyright (C) 2013 Intra2net AG
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published
7 # by the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see
17 # <http://www.gnu.org/licenses/lgpl-3.0.html>
18
19 import argparse
20 import binascii
21 import json
22 import logging
23 import os
24 import re
25 import random
26 import shutil
27 import sys
28 from datetime import datetime
29 from functools import partial
30
31 from deltatar.deltatar import DeltaTar, NO_MATCH, MATCH, PARENT_MATCH
32 from deltatar.tarfile import TarFile, GNU_FORMAT
33
34 consoleLogger = logging.StreamHandler()
35 consoleLogger.setLevel(logging.DEBUG)
36
37 def check_equal_dirs(path1, path2, deltatar):
38     '''
39     compare the two directories source_dir and target_dir and check
40     # they are the same
41     '''
42     nbars1 = len(path1.split('/'))
43     nbars2 = len(path2.split('/'))
44
45     source_it = deltatar._recursive_walk_dir(path1)
46     source_it = deltatar.jsonize_path_iterator(source_it, strip=nbars1)
47     target_it = deltatar._recursive_walk_dir(path2)
48     target_it = deltatar.jsonize_path_iterator(target_it, strip=nbars2)
49     while True:
50         try:
51             sitem = next(source_it)
52             titem = next(target_it)
53         except StopIteration:
54             try:
55                 titem = next(target_it)
56                 raise Exception("iterators do not stop at the same time")
57             except StopIteration:
58                 break
59         try:
60             assert deltatar._equal_stat_dicts(sitem, titem)
61         except Exception as e:
62             print(sitem)
63             print(titem)
64             print("FAIL")
65             raise
66
67 if __name__ == "__main__":
68     #import tracemalloc
69     #tracemalloc.enable()
70     #top = tracemalloc.DisplayTop(25)
71     #top.show_lineno = True
72     #top.start(20)
73     parser = argparse.ArgumentParser()
74
75     parser.add_argument("-m", "--mode", default='',
76                         help=
77                             """Mode in which to read/write the backup.
78                             Valid modes are:
79                                        ''           open uncompressed;
80                                        'gz'         open with gzip compression;
81                                        'bz2'        open with bzip2 compression;
82                                        '#gz'        encrypted stream of individually
83                                                     compressed tar blocks.
84                             To enable encryption, supply a password.
85                             """)
86     parser.add_argument("-t", "--targetpath", help="Target path directory.")
87     parser.add_argument("-s", "--sourcepath", help="Source path directory.")
88     epw = os.getenv ("PDTCRYPT_PASSWORD")
89     parser.add_argument("-p", "--password",
90                         default=epw.strip () if epw is not None else None,
91                         help="Password for symmetric encryption. "
92                              "The environment variable PDTCRYPT_PASSWORD should "
93                              "be preferred to this. Enables encryption.")
94     parser.add_argument("-v", "--volsize", default=None,
95                         help="Maximum volume size, in megabytes.")
96     parser.add_argument("-r", "--restore", action='store_true',
97                         help="Restore a backup.")
98     parser.add_argument("-R", "--recover", action='store_true',
99                         help="Recover a potentially damaged backup with an index "
100                         "file. **Caution**: recovery mode is insecure; it ignores "
101                         "data integrity checks on encrypted backup sets which may "
102                         "allow unauthorized decryption of confidential information.")
103     parser.add_argument("-f", "--full", action='store_true',
104                         help="Create a full backup.")
105     parser.add_argument("-d", "--diff", action='store_true',
106                         help="Create a diff backup.")
107     parser.add_argument("-i", "--indexes", nargs='+', help="Indexes paths.")
108     parser.add_argument("-l", "--list-files", action='store_true',
109                         help="List files in a tarball.")
110     parser.add_argument("-x", "--excluded", nargs='+', default=[],
111                         help="Files to exclude from backup.")
112     parser.add_argument("-inc", "--included", nargs='+', default=[],
113                         help="Files to include in the backup.")
114     parser.add_argument("-ip", "--included-path", default=None,
115                         help="Path to a file containing a list of included paths.")
116     parser.add_argument("-xp", "--excluded-path", default=None,
117                         help="Path to a file containing a list of excluded paths.")
118     parser.add_argument("-e", "--equals", action='store_true',
119                         help="Check if two dirs are equal.")
120
121     args = parser.parse_args()
122
123     if args.excluded_path:
124         f = open(args.excluded_path, 'r')
125         excluded_files = f.readlines()
126         f.close()
127     else:
128         excluded_files = args.excluded
129
130     if args.included_path:
131         f = open(args.included_path, 'r')
132         included_files = f.readlines()
133         f.close()
134     else:
135         included_files = args.included
136
137     deltatar = DeltaTar(mode=args.mode, password=args.password,
138         logger=consoleLogger, excluded_files=excluded_files,
139         included_files=included_files)
140
141     if args.full:
142         deltatar.create_full_backup(args.sourcepath, args.targetpath, args.volsize)
143     elif args.diff:
144         deltatar.create_diff_backup(args.sourcepath, args.targetpath, args.indexes[0], args.volsize)
145     elif args.list_files:
146         deltatar.list_backup(args.sourcepath, lambda e: print (e.name))
147     elif args.restore:
148         if args.indexes is not None:
149             deltatar.restore_backup(args.targetpath, backup_indexes_paths=args.indexes)
150         else:
151             deltatar.restore_backup(args.targetpath, backup_tar_path=args.sourcepath)
152     elif args.recover:
153         if args.sourcepath is not None:
154             print("Disaster recovery conflicts with --sourcepath; please supply"
155                   " an\nindex file (--indexes).", file=sys.stderr)
156         failed = deltatar.recover_backup(args.targetpath,
157                                          backup_indexes_paths=args.indexes)
158         if len (failed) > 0:
159             logger = logging.getLogger('deltatar.DeltaTar')
160             print ("%d files could not be restored:" % len (failed))
161             for i, f in enumerate (failed):
162                 print ("   [%d] %s (%s)" % (i, f [0], f [1]))
163
164     elif args.equals:
165         check_equal_dirs(os.path.abspath(args.sourcepath), os.path.abspath(args.targetpath), deltatar)
166     else:
167         print("Nothing to do.\nPlease specify one of --full, --diff, --list-files, "
168               "--restore, --equals.\n", file=sys.stderr)
169         parser.print_help(file=sys.stderr)
170
171