. "$BST_LIB" # librsync 2.3.4 -- the rsync rolling-checksum library: signature, delta, patch # (meta-oe recipes-support). See librsync_%.bbappend for what the port adds. # # --------------------------------------------------------------------------- # WHERE THE EVIDENCE COMES FROM # # The deliverable is mostly a -dev/-staticdev pair -- /usr/lib/librsync.a and # two headers -- plus one small binary, /usr/bin/rdiff. `rdiff` alone is not # coverage of the library: it drives only the whole-file path (rs_sig_file, # rs_loadsig_file, rs_delta_file, rs_patch_file) and always through librsync's # own rs_file_copy_cb, so the streaming job API and every caller-supplied copy # callback would ship completely unexercised. # # So data/librsync-probe (src/librsync_probe.c) is cross-linked against THE VERY # ARCHIVE THAT SHIPS and drives the library directly: the MD4 and BLAKE2 sum # primitives, base64, the error-string table, the wire magics, rs_sig_args # parameter negotiation, whole-file round trips over eleven basis/new shapes, # delta quality (a one-byte edit must stay small and copy-dominated), the # on-the-wire header bytes, five corruption paths, the streaming rs_job_* # interface with its statistics, and a caller-supplied rs_copy_cb. # # --------------------------------------------------------------------------- # WHY THE ORACLE IS A NATIVE CAPTURE, AND WHAT THAT BUYS # # Unlike mpfr, librsync has no contract that fixes its answers a priori: the # delta format is whatever librsync emits, and it is free to encode any new file # as one literal. So the expected values are a NATIVE x86_64 capture -- # data/librsync-native.txt, generated from the same 2.3.4 source the recipe # builds, checked deterministic across three runs. # # The question this suite exists to answer is therefore precisely "does the # wasm32 build agree, row for row, with the same source built natively" -- which # is the porting question and nothing more. librsync/native-identical is that # assertion, and it is the one that matters; the per-area rows below exist so a # reader sees WHICH area moved without re-running anything. # # --------------------------------------------------------------------------- # THE FOUR ROWS THAT ARE RED IN THE CONTROL TOO -- AN UPSTREAM BUG, NOT A GAP # # b64-f-dec, b64-fo-dec, b64-foob-dec and b64-fooba-dec fail on x86_64 exactly as # they fail here. rs_unbase64() (src/base64.c) ends its final quantum with # `n = byte_offset + 2` whether or not that trailing byte carries any data, so # every PADDED input is over-reported by one byte: "Zg==" decodes to 1 byte and # is reported as 2. The four unpadded vectors (foo, foobar) are correct, which is # why the bug survives upstream -- RFC 4648's own test vectors only fail in the # padded half. # # This is a defect in librsync, not in brintOS and not in this port: it is # arithmetic on a local buffer, with no libc, kernel or wasm32 surface anywhere # near it, and it reproduces identically on the control. It is therefore NOT # attributed to a platform issue and NOT left as an unexplained red. The suite # pins the four to the control's exact byte counts, so this stays green while # librsync behaves as it does today and goes red the moment the behaviour # changes -- which is the only signal a port can honestly offer about someone # else's bug. lib=/usr/lib/librsync.a hdr=/usr/include/librsync.h exphdr=/usr/include/librsync_export.h rdiff=/usr/bin/rdiff shipped=$BST_DATA/librsync-probe control=$BST_DATA/librsync-native.txt tmp=${TMPDIR:-/tmp} probe=$tmp/bst-librsync-probe.$$ work=$tmp/bst-librsync-work.$$ if [ ! -f "$lib" ]; then bst_skip librsync/present "no $lib on this image" exit 0 fi bst_ok librsync/present check librsync/header-present test -f "$hdr" check librsync/export-header-present test -f "$exphdr" check librsync/probe-present test -f "$shipped" check librsync/control-present test -f "$control" sz=$(wc -c < "$lib" 2>/dev/null || echo 0) if [ "$sz" -gt 100000 ]; then bst_ok librsync/archive-nonempty else bst_notok librsync/archive-nonempty "librsync.a is $sz bytes"; fi # The static-link spelling of the API. -DBUILD_SHARED_LIBS=OFF compiles librsync # with LIBRSYNC_STATIC_DEFINE, and librsync_export.h keys LIBRSYNC_EXPORT off it: # with the macro the declaration is a plain extern, without it every entry point # carries __attribute__((visibility("default"))). This asserts the shipped header # still offers that branch at all. It does NOT assert which arm a consumer gets -- # the macro is a cmake usage requirement, never written into the installed header, # so a plain-cc consumer compiles the visibility arm; measured inert on this # static archive. See the export-static block below, which asserts that. if grep -q 'LIBRSYNC_STATIC_DEFINE' "$exphdr" 2>/dev/null; then bst_ok librsync/export-header-static-arm else bst_notok librsync/export-header-static-arm \ "LIBRSYNC_STATIC_DEFINE absent from $exphdr" fi # --------------------------------------------------------------------------- # rdiff -- the CLI half. Its presence is the runtime proof that popt resolved at # configure time: BUILD_RDIFF is a cmake_dependent_option on POPT_FOUND, so a # build that silently lost popt ships an empty rdiff package and goes red here. if [ -x "$rdiff" ]; then bst_ok librsync/rdiff-present out=$("$rdiff" --version 2>&1); rc=$? if [ "$rc" -eq 0 ]; then bst_ok librsync/rdiff-runs elif bst_execfail "$out"; then bst_unrun librsync/rdiff-runs "$out" else bst_notok librsync/rdiff-runs "rc=$rc $(_bst_1line "$out")"; fi case "$out" in *2.3.4*) bst_ok librsync/rdiff-version ;; *) bst_notok librsync/rdiff-version "got $(_bst_1line "$out")" ;; esac else bst_notok librsync/rdiff-present "no $rdiff -- popt lost at configure?" bst_notok librsync/rdiff-runs "no $rdiff" bst_notok librsync/rdiff-version "no $rdiff" fi # rdiff end-to-end, on target files: signature -> delta -> patch must reproduce # the new file byte for byte. This is the whole-file path the library probe # deliberately does not reach through the CLI. if mkdir -p "$work" 2>/dev/null; then bst_ok librsync/work-dir i=0 while [ "$i" -lt 400 ]; do printf 'librsync rdiff round-trip line %d padding padding padding\n' "$i" i=$((i + 1)) done > "$work/basis" 2>/dev/null cp "$work/basis" "$work/new" 2>/dev/null printf 'an edited line that did not exist in the basis\n' >> "$work/new" 2>/dev/null if [ -x "$rdiff" ] && "$rdiff" signature "$work/basis" "$work/sig" >"$work/log" 2>&1 && "$rdiff" delta "$work/sig" "$work/new" "$work/delta" >>"$work/log" 2>&1 && "$rdiff" patch "$work/basis" "$work/delta" "$work/out" >>"$work/log" 2>&1; then bst_ok librsync/rdiff-roundtrip-ran if cmp -s "$work/new" "$work/out"; then bst_ok librsync/rdiff-roundtrip-identical else bst_notok librsync/rdiff-roundtrip-identical "patched output differs from new"; fi # A delta against a basis that already holds ~all the content must be a # small fraction of the file, or the rolling checksum matched nothing. nsz=$(wc -c < "$work/new" 2>/dev/null || echo 0) dsz=$(wc -c < "$work/delta" 2>/dev/null || echo 0) if [ "$nsz" -gt 0 ] && [ "$dsz" -gt 0 ] && [ "$((dsz * 4))" -lt "$nsz" ]; then bst_ok librsync/rdiff-delta-small else bst_notok librsync/rdiff-delta-small "delta $dsz vs new $nsz -- no block matched" fi else log=$(cat "$work/log" 2>/dev/null) if bst_execfail "$log"; then bst_unrun librsync/rdiff-roundtrip-ran "$log" else bst_notok librsync/rdiff-roundtrip-ran "$(_bst_1line "$log")" fi bst_notok librsync/rdiff-roundtrip-identical "round trip did not run" bst_notok librsync/rdiff-delta-small "round trip did not run" fi else bst_notok librsync/work-dir "cannot create $work" bst_notok librsync/rdiff-roundtrip-ran "no work dir" bst_notok librsync/rdiff-roundtrip-identical "no work dir" bst_notok librsync/rdiff-delta-small "no work dir" fi # --------------------------------------------------------------------------- # The library probe. data/ installs mode 0644 and the rootfs is read-only at # browser runtime, so stage it somewhere writable and set the bit there. if cp "$shipped" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then bst_ok librsync/probe-stage out=$(LR_WORKDIR="$work" "$probe" 2>/dev/null); rc=$? else bst_notok librsync/probe-stage "cannot stage $shipped" out=''; rc=127 fi rm -f "$probe" # The probe exits non-zero whenever any of its own rows failed, and four rows # fail in the control too, so a clean exit is NOT the expectation here -- the # control comparison below is. Report the code rather than asserting it. if bst_execfail "$out"; then bst_unrun librsync/probe-ran "$out" elif [ -n "$out" ]; then bst_ok librsync/probe-ran else bst_notok librsync/probe-ran "probe printed nothing (rc=$rc)" fi got=$(printf '%s\n' "$out" | grep '^LR-') want=$(grep '^LR-' "$control" 2>/dev/null) ngot=$(printf '%s\n' "$got" | grep -c '^LR-') nwant=$(printf '%s\n' "$want" | grep -c '^LR-') check_eq librsync/row-count "$nwant" "$ngot" # export-static is excluded from the byte-identity comparison and asserted on its # own terms below: it is the one row whose answer is a property of HOW THE PROBE # WAS COMPILED rather than of the library, so demanding it match the control # would be asserting the control's build flags, not this arm's behaviour. # LR-SUMMARY goes with it: it is the probe's own tally, so it counts the excluded # row and would report that one known divergence a second time, as a whole-suite # mismatch. It is asserted on its own below by probe-total + probe-pass-count. got=$(printf '%s\n' "$got" | grep -vE '^LR-(export-static |SUMMARY )') want=$(printf '%s\n' "$want" | grep -vE '^LR-(export-static |SUMMARY )') if [ -n "$want" ] && [ "$got" = "$want" ]; then bst_ok librsync/native-identical else first=$(printf '%s\n' "$want" | while IFS= read -r w; do n=${w%% *} g=$(printf '%s\n' "$got" | grep "^$n " || echo "") [ "$g" = "$w" ] || { printf '%s: want [%s] got [%s]' "$n" "${w#* }" "${g#* }"; break; } done) bst_notok librsync/native-identical "$(_bst_1line "${first:-row counts differ}")" fi # lr -> that row's verdict word (OK / FAIL), from the target run lr() { printf '%s\n' "$got" | while IFS= read -r l; do case "$l" in "LR-$1 "*) printf '%s\n' "${l#LR-$1 }"; break ;; esac done } # Named rows, so a reviewer reading the report sees which AREA of the library # answered rather than only a single aggregate. Each must be OK on this arm. for case_name in \ version-2.3.4 \ md4-empty md4-abc md4-message-digest md4-streaming-split hexify \ magic-delta magic-md4-sig magic-blake2-sig \ sum-length-md4 sum-length-blake2 \ sigargs-64k sigargs-1m sigargs-bad-magic sigargs-strong-too-long \ rt-identical rt-one-byte-edit rt-append rt-truncate rt-prepend \ rt-empty-basis rt-empty-new rt-both-empty rt-unrelated rt-binary \ rt-magic-blake2-rk rt-magic-blake2-rollsum rt-magic-md4-rk rt-magic-md4-rollsum \ delta-small-for-one-byte delta-has-copies delta-copies-most-bytes \ delta-tiny-when-identical delta-large-when-unrelated \ wire-sig-magic-default wire-sig-header-block wire-sig-header-size \ wire-delta-magic wire-delta-end \ err-loadsig-corrupt err-loadsig-bad-magic err-loadsig-truncated \ err-patch-bad-magic err-patch-truncated err-sig-bad-magic \ stream-sig-done stream-loadsig-done stream-hashtable \ stream-delta-stats-op stream-delta-stats-copies stream-delta-done \ cb-patch-done cb-patch-content cb-called cb-pos-in-range \ cb-len-bounded cb-patch-digest cb-error-propagates \ file-size supports-trace-off do v=$(lr "$case_name") case "$v" in OK) bst_ok "librsync/$case_name" ;; '') bst_notok "librsync/$case_name" "row absent from probe output" ;; *) bst_notok "librsync/$case_name" "$(_bst_1line "$v")" ;; esac done # The four upstream-buggy rows, pinned to the control's exact text rather than # to OK. Green here means "this arm reproduces librsync's own base64 padding bug # byte for byte", which is the only true statement available; a change in either # direction is worth a look and turns these red. for case_name in b64-f-dec b64-fo-dec b64-foob-dec b64-fooba-dec; do w=$(printf '%s\n' "$want" | grep "^LR-$case_name " | head -1) g=$(printf '%s\n' "$got" | grep "^LR-$case_name " | head -1) if [ -n "$w" ] && [ "$g" = "$w" ]; then bst_ok "librsync/$case_name-matches-control" else bst_notok "librsync/$case_name-matches-control" \ "want [${w#LR-$case_name }] got [${g:-}]" fi done # The encode half is correct upstream and must be correct here. for case_name in b64-f-enc b64-fo-enc b64-foo-enc b64-foob-enc b64-fooba-enc b64-foobar-enc \ b64-foo-dec b64-foobar-dec do v=$(lr "$case_name") case "$v" in OK) bst_ok "librsync/$case_name" ;; '') bst_notok "librsync/$case_name" "row absent from probe output" ;; *) bst_notok "librsync/$case_name" "$(_bst_1line "$v")" ;; esac done # --------------------------------------------------------------------------- # export-static, asserted on its own terms. # # The probe asks `#ifdef LIBRSYNC_STATIC_DEFINE` at ITS OWN compile time. librsync # sets that macro with target_compile_options(rsync PUBLIC ...), which is a cmake # USAGE REQUIREMENT: it reaches consumers that find librsync through cmake, and it # is never written into the installed header -- /usr/include/librsync_export.h # carries only the `#ifdef` branch. The shipped probe is deliberately built as a # plain-cc consumer, without the macro, so this row reports FAIL here and OK in # the control (whose native build was driven by cmake). That is a true statement # about the -dev package and not a regression, so it is asserted as the observed # answer rather than as OK, and excluded from native-identical above. # # What is asserted alongside it is the thing that actually matters and that the # bbappend's argument rests on: the visibility arm is INERT here. The probe linked # clean without the macro and every functional row above passed, which is the # evidence that a consumer taking the shared spelling is not broken on this arm. v=$(printf '%s\n' "$out" | while IFS= read -r l; do case "$l" in "LR-export-static "*) printf '%s\n' "${l#LR-export-static }"; break ;; esac done) case "$v" in FAIL*not\ defined*) bst_ok librsync/export-static-not-propagated-to-plain-cc ;; OK) bst_notok librsync/export-static-not-propagated-to-plain-cc \ "the header now defines LIBRSYNC_STATIC_DEFINE on its own -- upstream changed, re-read the bbappend's export note" ;; '') bst_notok librsync/export-static-not-propagated-to-plain-cc "row absent from probe output" ;; *) bst_notok librsync/export-static-not-propagated-to-plain-cc "unexpected: $(_bst_1line "$v")" ;; esac # The probe's own tally. The target is expected to differ from the control by # exactly the one row above, so the expectation is derived from the control # rather than pinned to a literal that would go stale the day a case is added. wsummary=$(grep '^LR-SUMMARY' "$control" 2>/dev/null | head -1) gsummary=$(printf '%s\n' "$out" | grep '^LR-SUMMARY' | head -1) wp=${wsummary#LR-SUMMARY }; wtot=${wp#*/}; wp=${wp%%/*} gp=${gsummary#LR-SUMMARY }; gtot=${gp#*/}; gp=${gp%%/*} check_eq librsync/probe-total "$wtot" "$gtot" if [ -n "$gp" ] && [ -n "$wp" ] && [ "$gp" -eq "$((wp - 1))" ]; then bst_ok librsync/probe-pass-count else bst_notok librsync/probe-pass-count \ "expected $((wp - 1)) (control $wp less export-static) got ${gp:-}" fi rm -rf "$work"