diff --git a/avbroot/ota.py b/avbroot/ota.py index 824d4ea..37bf965 100644 --- a/avbroot/ota.py +++ b/avbroot/ota.py @@ -659,7 +659,11 @@ class _TeeFileDescriptor: self.capture.write(data) else: for stream in self.streams: - stream.write(data) + # Naive hole punching to create sparse files + if stream is self.backing and util.is_zero(data): + stream.seek(len(data), os.SEEK_CUR) + else: + stream.write(data) return len(data) diff --git a/avbroot/util.py b/avbroot/util.py index e52a70f..19cd5c7 100644 --- a/avbroot/util.py +++ b/avbroot/util.py @@ -3,6 +3,9 @@ import os import tempfile +_ZERO_BLOCK = memoryview(b'\0' * 16384) + + @contextlib.contextmanager def open_output_file(path): ''' @@ -145,3 +148,21 @@ def read_exact(f, size: int) -> bytes: return bytes(data) else: return data + + +def is_zero(data): + ''' + Check if all bytes in the bytes-like object are null bytes. + ''' + + view = memoryview(data) + + while view: + n = min(len(view), len(_ZERO_BLOCK)) + + if view[:n] != _ZERO_BLOCK[:n]: + return False + + view = view[n:] + + return True