From: Andrew Tridgell Date: Thu, 4 Jun 2026 04:17:12 +0000 (+1000) Subject: testsuite: regression for short-checksum --append-verify s2length X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3691b719fac47c27eff02b82fc5b03f033a1c35d;p=thirdparty%2Frsync.git testsuite: regression for short-checksum --append-verify s2length Forces --checksum-choice=xxh64 (an 8-byte transfer checksum) with a corrupted-prefix --append-verify so the full-checksum redo path runs. Before the generator capped s2length at MIN(SUM_LENGTH, xfer_sum_len) this died with "Invalid checksum length 16 [sender]"; the test is RED on the prior generator and GREEN with the cap. Reproduces on any build that has xxhash, so it guards the fix without an old-libxxhash host; skips when xxh64 is absent (a build without xxhash). --- diff --git a/testsuite/append-shortsum_test.py b/testsuite/append-shortsum_test.py new file mode 100644 index 00000000..6fa3bddc --- /dev/null +++ b/testsuite/append-shortsum_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +"""Regression: a short transfer checksum must not over-state the block s2length. + +A full-checksum (--append-verify redo) pass computes the strong block sum length +(s2length). The generator used to cap it at SUM_LENGTH (16), the legacy MD4/MD5 +digest size, regardless of the negotiated algorithm. Since the sum2 array holds +xfer_sum_len-byte elements and the sender rejects an s2length larger than +xfer_sum_len, a sub-16-byte transfer checksum -- xxh64 (8 bytes), which is what +rsync negotiates when the build's libxxhash lacks xxh128/xxh3 (e.g. Ubuntu +20.04) -- made the sender die with "Invalid checksum length 16 [sender]" +(protocol incompatibility, code 2). + +Forcing --checksum-choice=xxh64 reproduces it on any build that has xxhash, so +this guards the fix without needing an old-libxxhash host. Skipped where xxh64 +is unavailable (a build without xxhash). +""" + +import json + +from rsyncfns import ( + FROMDIR, TODIR, assert_same, make_data_file, rmtree, run_rsync, + test_skipped, +) + +vv = json.loads(run_rsync('-VV', check=True, capture_output=True).stdout) +if 'xxh64' not in vv.get('checksum_list', []): + test_skipped("xxh64 not in this build's checksum list (no xxhash)") + +src, dst = FROMDIR, TODIR +rmtree(src) +rmtree(dst) +src.mkdir(parents=True) +dst.mkdir(parents=True) + +# Source longer than the destination so --append has bytes to add; the dest is a +# *corrupted* prefix so --append-verify's whole-file check fails and the file is +# redone with a full checksum -- the csum_length == SUM_LENGTH path that emitted +# the over-long s2length. +make_data_file(src / 'f', 40000) +full = (src / 'f').read_bytes() +prefix = bytearray(full[:20000]) +prefix[0:64] = b'\x00' * 64 +(dst / 'f').write_bytes(bytes(prefix)) + +# --no-whole-file forces the delta/checksum path regardless of local-vs-remote. +# run_rsync(check=True) fails the test on the non-zero exit the bug produced. +run_rsync('-a', '--append-verify', '--checksum-choice=xxh64', '--no-whole-file', + f'{src}/', f'{dst}/') +assert_same(dst / 'f', src / 'f', label='append-verify xxh64 redo') + +print("append-shortsum: --append-verify with an 8-byte (xxh64) checksum no " + "longer overflows the block s2length")