summaryrefslogtreecommitdiff
path: root/morphlib/bins.py
diff options
context:
space:
mode:
Diffstat (limited to 'morphlib/bins.py')
-rw-r--r--morphlib/bins.py34
1 files changed, 32 insertions, 2 deletions
diff --git a/morphlib/bins.py b/morphlib/bins.py
index eb783ae2..28542962 100644
--- a/morphlib/bins.py
+++ b/morphlib/bins.py
@@ -29,6 +29,7 @@ import errno
import stat
import shutil
import tarfile
+import zlib
import morphlib
@@ -50,11 +51,34 @@ def safe_makefile(self, tarinfo, targetpath):
tarfile.TarFile.makefile = safe_makefile
+class ChecksummingOutputStream(object):
+ '''Wrap a stream object and checksum all data that is written.
+
+ The checksum used is Adler32. It is very fast. It's not suited for data
+ under 1KB and does not guard against intentional modifications much,
+ but for detecting corruption in the stored artifacts it is useful.
+
+ '''
+ def __init__(self, f):
+ self.f = f
+ self.checksum = 0
+
+ def read(self, *args, **kwargs):
+ raise NotImplementedError(
+ 'Attempted to read from a write-only stream.')
+
+ def write(self, data, *args, **kwargs):
+ self.f.write(data, *args, **kwargs)
+ self.checksum = (self.checksum + zlib.adler32(data)) & 0xFFFFFFFF
+
+
def create_chunk(rootdir, f, include, dump_memory_profile=None):
'''Create a chunk from the contents of a directory.
``f`` is an open file handle, to which the tar file is written.
+ This function returns a checksum of the resulting file.
+
'''
dump_memory_profile = dump_memory_profile or (lambda msg: None)
@@ -69,7 +93,8 @@ def create_chunk(rootdir, f, include, dump_memory_profile=None):
path_pairs = [(relname, os.path.join(rootdir, relname))
for relname in include]
- with tarfile.open(fileobj=f, mode='w') as tar:
+ stream = ChecksummingOutputStream(f)
+ with tarfile.open(fileobj=stream, mode='w|') as tar:
for relname, filename in path_pairs:
# Normalize mtime for everything.
tarinfo = tar.gettarinfo(filename,
@@ -89,6 +114,8 @@ def create_chunk(rootdir, f, include, dump_memory_profile=None):
os.remove(filename)
dump_memory_profile('after removing in create_chunks')
+ return stream.checksum
+
def create_system(rootdir, f, name):
'''Create a system artifact from the contents of a directory.
@@ -103,9 +130,12 @@ def create_system(rootdir, f, name):
info.linkname = os.path.relpath(info.linkname, unslashy_root)
return info
- with tarfile.open(fileobj=f, mode="w", name=name) as tar:
+ stream = ChecksummingOutputStream(f)
+ with tarfile.open(fileobj=stream, mode="w|", name=name) as tar:
tar.add(rootdir, recursive=True, filter=uproot_info)
+ return stream.checksum
+
def unpack_binary_from_file(f, dirname): # pragma: no cover
'''Unpack a binary into a directory.