asdf
[public/mirror.git] / debian-check-md5sum
1 #!/usr/bin/python2.5
2 import sys, os, re, gzip, bz2, hashlib
3
4 package_file_map = {
5     'Packages' : file,
6     'Packages.gz' : gzip.GzipFile,
7     'Packages.bz2' : bz2.BZ2File,
8     'Sources' : file,
9     'Sources.gz' : gzip.GzipFile,
10     'Sources.bz2' : bz2.BZ2File,
11 }
12
13 def parse_packages_file(path):
14     try:
15         open_func = package_file_map[os.path.basename(path)]
16         file = open_func(path)
17     except IOError, e:
18         print "WARNING: failed to open %s: %s" % (path, e)
19         return {}
20     cur_dict = {}
21     key, value = None, ''
22     ret_list = []
23     while True:
24         try:
25             line = file.readline()
26         except IOError, e:
27             print "WARNING: failed to read %s: %s" % (path, e)
28             print "WARNING: %s" % e
29             return {}
30
31         # check if we are done with current value
32         if (line == '' or line[0] == '\n' or line[0] != ' ') and key != None:
33             cur_dict[key] = value
34
35         if line == '' or line == '\n': # done current block
36             if cur_dict != {}:
37                 ret_list.append(cur_dict)
38                 cur_dict = {}
39                 key = None
40             if line == '': break
41         elif line[0] == ' ': # multi-line value
42             value += '\n' + line[1:-1]
43         else:
44             if line[-1] == '\n': line = line[:-1]
45             pos = line.find(':')
46             key = line[:pos]
47             if key == '': key = None
48             value = line[pos+2:]
49     return ret_list
50
51 def find_packages_files(path):
52     files = []
53     for file in os.listdir(path):
54         file_path = "%s/%s" % (path, file)
55         if os.path.islink(file_path):
56             continue
57         elif os.path.isdir(file_path):
58             files += find_packages_files(file_path)
59         elif file in package_file_map:
60             files.append(file_path)
61     return files
62
63 if len(sys.argv) != 2:
64     print "Usage: debian-check-md5sum.py base-dir"
65     sys.exit(1)
66 base_dir = sys.argv[1]
67
68 all = {}
69 files_regex = re.compile('(\S+)\s+(\S+)\s+(\S+)')
70 for file in find_packages_files(base_dir):
71     file_type = os.path.basename(file).split('.')[0]
72     a = parse_packages_file(file)
73     for package in parse_packages_file(file):
74         if file_type == 'Packages':
75             if 'Filename' in package:
76                 all[package['Filename']] = package
77         elif file_type == 'Sources':
78             files = package['Files'].split('\n')
79             for file in files:
80                 if file == '': continue
81                 match = files_regex.match(file)
82                 file_path = '%s/%s' % (package['Directory'], match.group(3))
83                 all[file_path] = { 'MD5sum' : match.group(1) }
84 print "NOTICE:  need to check %d files" % len(all)
85
86 ret_val = 0
87 block_size = 65536
88 for (file, package) in all.iteritems():
89     path = '%s/%s' % (base_dir, file)
90     try:
91         file = open(path, 'rb')
92     except IOError:
93         print "WARNING: missing %s" % path
94         continue
95     if 'SHA256' in package:
96         md = hashlib.sha256()
97         hash = package['SHA256']
98     elif 'SHA1' in package:
99         md = hashlib.sha1()
100         hash = package['SHA1']
101     elif 'MD5sum' in package:
102         md = hashlib.md5()
103         hash = package['MD5sum']
104     else:
105         print "WARNING: no hash found for %s" % path
106         print package
107         exit(1)
108     while True:
109         data = file.read(block_size)
110         if data == '': break
111         md.update(data)
112     hash_calc = md.hexdigest()
113     if hash == hash_calc:
114         print "NOTICE:  hash ok for %s [hash = %s]" % (path, hash)
115     else:
116         print "ERROR:   hash mismatch for %s [hash = %s, hash_calc = %s]" % \
117             (path, hash, hash_calc)
118         ret_val = 1
119 exit(ret_val)