[Git][reproducible-builds/diffoscope][master] Allow trailing garbage for Gzip files

Chris Lamb (@lamby) gitlab at salsa.debian.org
Mon Jul 6 15:50:47 UTC 2026



Chris Lamb pushed to branch master at Reproducible Builds / diffoscope


Commits:
c8dcbf4a by Paul Spooren at 2026-07-06T08:50:30-07:00
Allow trailing garbage for Gzip files

If a Gzip contains any trailing garbage, (e.g. metadata like it's down
for OpenWrt), it successfully extracts the data but exists with code
`2`. This causes `diffoscope` to exit, misunderstanding the exit code as
an error.

By allowing both exit codes 0 and 2, such metadata gzip archives with
metadata are now supported by `diffoscope`.

Signed-off-by: Paul Spooren <mail at aparcar.org>

- - - - -


2 changed files:

- diffoscope/comparators/gzip.py
- tests/comparators/test_gzip.py


Changes:

=====================================
diffoscope/comparators/gzip.py
=====================================
@@ -48,11 +48,19 @@ class GzipContainer(Archive):
             # Use the short options (-d and -c) instead of the long options
             # (--decompress and --stdout) to support the gzip implementation
             # present in busybox, which doesn't support the long options.
-            subprocess.check_call(
+            returncode = subprocess.call(
                 ["gzip", "-d", "-c", self.source.path],
                 stdout=fp,
                 stderr=None,
             )
+        # gzip exits with 2 (a warning) when decompression succeeds but there
+        # is trailing garbage after the stream, eg. metadata appended to
+        # OpenWrt firmware images. The payload is still fully decompressed, so
+        # only treat a fatal error (exit code 1) as a failure.
+        if returncode not in (0, 2):
+            raise subprocess.CalledProcessError(
+                returncode, ["gzip", "-d", "-c", self.source.path]
+            )
         return dest_path
 
 


=====================================
tests/comparators/test_gzip.py
=====================================
@@ -17,6 +17,7 @@
 # You should have received a copy of the GNU General Public License
 # along with diffoscope.  If not, see <https://www.gnu.org/licenses/>.
 
+import gzip
 import shutil
 import pytest
 
@@ -90,6 +91,28 @@ def test_content_diff(differences):
     assert differences[1].unified_diff == expected_diff
 
 
+def test_trailing_garbage(tmpdir):
+    # OpenWrt firmware images append metadata after the gzip stream, which
+    # makes gzip(1) exit with a warning (code 2) even though the payload
+    # decompressed fine. Ensure we still compare the content.
+    def make(name, content):
+        path = str(tmpdir.join(name))
+        with gzip.open(path, "wb") as fp:
+            fp.write(content)
+        with open(path, "ab") as fp:
+            fp.write(b"OpenWrt appended metadata blob")
+        return specialize(FilesystemFile(path))
+
+    file1 = make("garbage1.gz", b"hello\n")
+    file2 = make("garbage2.gz", b"world\n")
+
+    assert file1.compare(file1) is None
+    difference = file1.compare(file2)
+    assert difference is not None
+    # The decompressed content must have been extracted and compared.
+    assert difference.details[-1].unified_diff
+
+
 def test_compare_non_existing(monkeypatch, gzip1):
     monkeypatch.setattr(Config(), "new_file", True)
     difference = gzip1.compare(MissingFile("/nonexisting", gzip1))



View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/-/commit/c8dcbf4aa828ba9f1a95156df6deb27f07017816

-- 
View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/-/commit/c8dcbf4aa828ba9f1a95156df6deb27f07017816
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.reproducible-builds.org/pipermail/rb-commits/attachments/20260706/a770c6dc/attachment.htm>


More information about the rb-commits mailing list