Look at checksums before processing a changes file (closes #88374)

This should ensure we don't end up with files in the repositories that come from different builds. It's still possible for this to fail if the files get overwritten between the check and the move; this could be fixed by first moving files to a staging area, doing the check, then moving them to their destination. One step at a time, though.

authorJulien Cristau <julien.cristau@logilab.fr>
changeset2e1cffdaf60e
branchdefault
phasepublic
hiddenno
parent revision#842da0bcd94e new incoming command (closes #88751)
child revision#730ee1008f34 [packaging] remove trailing / from directory name in MANIFEST.in (closes #90427)
files modified by this revision
debfiles.py
ldi.py
# HG changeset patch
# User Julien Cristau <julien.cristau@logilab.fr>
# Date 1329206424 -3600
# Tue Feb 14 09:00:24 2012 +0100
# Node ID 2e1cffdaf60e4cb35570d4dd757f5e47f28b8a5d
# Parent 842da0bcd94e312908d944f7b7a337556f1f6fe7
Look at checksums before processing a changes file (closes #88374)

This should ensure we don't end up with files in the repositories that
come from different builds. It's still possible for this to fail if the
files get overwritten between the check and the move; this could be
fixed by first moving files to a staging area, doing the check, then
moving them to their destination. One step at a time, though.

diff --git a/debfiles.py b/debfiles.py
@@ -15,10 +15,11 @@
1  # 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
2  """helper classes to manipulate debian packages"""
3 
4  import os.path as osp
5  from subprocess import Popen, PIPE
6 +import hashlib
7 
8  try:
9      from debian import deb822
10  except ImportError:
11      from debian_bundle import deb822
@@ -36,10 +37,19 @@
12      pipe.stderr.read()
13      status = pipe.wait()
14      if status != 0:
15          raise BadSignature('%s is not properly signed' % filename)
16 
17 +def hash_file(hashfun, filename):
18 +    with open(filename, 'rb') as f:
19 +        hashobj = hashfun()
20 +        while True:
21 +            buf = f.read(4096)
22 +            if buf == '':
23 +                break
24 +            hashobj.update(buf)
25 +        return hashobj.hexdigest()
26 
27  class Changes(object):
28      def __init__(self, path):
29          self.path = path
30          self.filename = osp.basename(path)
@@ -114,5 +124,21 @@
31              if not success:
32                  errors.append('checker %s is in error on %s: \n%s\n%s'
33                                % (check, self.path, stdout, stderr))
34          if errors:
35              raise CheckerError('\n'.join(errors))
36 +
37 +    def check_hashes(self):
38 +        for attr, hashfield, hashfun in (
39 +                ('Checksums-Sha256', 'sha256', hashlib.sha256),
40 +                ('Checksums-Sha1', 'sha1', hashlib.sha1),
41 +                ('Files', 'md5sum', hashlib.md5)):
42 +            try:
43 +                checksums = self[attr]
44 +            except KeyError:
45 +                continue
46 +            for f in checksums:
47 +                path = osp.join(osp.dirname(self.path), f['name'])
48 +                if hash_file(hashfun, path) != f[hashfield]:
49 +                    return False
50 +            return True
51 +        raise Exception('malformed changes files %s, no checksum found' % self.path)
diff --git a/ldi.py b/ldi.py
@@ -278,10 +278,13 @@
52              return result
53          return set()
54 
55      def process_changes_file(self, changes, distribdir, group,
56                               move=sht.cp, rm=False, force=False):
57 +        if not changes.check_hashes():
58 +            self.logger.warn("skipping %s, checksum mismatch", changes.path)
59 +            return
60          allfiles = changes.get_all_files()
61          # Logilab uses trivial Debian repository and put all generated files in
62          # the same place. Badly, it occurs some problems in case of several
63          # supported architectures and multiple Debian revision (in this order)
64          if move is sht.mv: