Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dd_rescue for openSUSE:Factory checked in at 2026-11-03 17:51:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dd_rescue (Old) and /work/SRC/openSUSE:Factory/.dd_rescue.new.1257 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dd_rescue" Tue Nov 3 17:51:24 2026 rev:70 rq:1394337 version:1.99.25 Changes: -------- --- /work/SRC/openSUSE:Factory/dd_rescue/dd_rescue.changes 2026-10-20 12:36:17.970447372 +0200 +++ /work/SRC/openSUSE:Factory/.dd_rescue.new.1257/dd_rescue.changes 2026-11-03 17:51:27.041001006 +0100 @@ -1,0 +2,18 @@ +Tue Oct 27 09:48:06 CET 2026 - [email protected] + +- Update to dd_rescue-1.99.25: + * Another edge testcase (unaligned with hardbs = softbs). + * Fix for this edge case. + * Improve buffer allocation to ensure alignment to cache line or + page size (for direct IO) even when plugins want space in front + of buffer (slack_pre). + * Increase frequency of status updates when using larger default + softbs with direct IO. + * More conservative (better) initial duration estimates. + * Add test case from Thomas Deutschmann, where odd offsets would + result on not getting progress updates. + * Fix by reducing granularity of offset checks. +- Drop dd_rescue-ssp-strong.patch, as we no longer have a special + make rule that would override the flags. + +------------------------------------------------------------------- Old: ---- dd_rescue-1.99.24.tar.bz2 dd_rescue-1.99.24.tar.bz2.asc dd_rescue-ssp-strong.patch New: ---- dd_rescue-1.99.25.tar.bz2 dd_rescue-1.99.25.tar.bz2.asc ----------(Old B)---------- Old: * Fix by reducing granularity of offset checks. - Drop dd_rescue-ssp-strong.patch, as we no longer have a special make rule that would override the flags. ----------(Old E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dd_rescue.spec ++++++ --- /var/tmp/diff_new_pack.QnUe1z/_old 2026-11-03 17:51:28.039042723 +0100 +++ /var/tmp/diff_new_pack.QnUe1z/_new 2026-11-03 17:51:28.041042807 +0100 @@ -21,7 +21,7 @@ %define _lto_cflags %{nil} %endif Name: dd_rescue -Version: 1.99.24 +Version: 1.99.25 Release: 0 Summary: Data copying in the presence of I/O Errors License: GPL-2.0-only OR GPL-3.0-only @@ -30,10 +30,6 @@ Source1: https://garloff.de/kurt/linux/ddrescue/%{name}-%{version}.tar.bz2.asc Source2: %{name}.keyring Source99: %{name}.changes -# PATCH-FIX-OPENSUSE dd_rescue-ssp-strong.patch -- the libddr_lzo.po rule -# appends basic -fstack-protector which downgrades the distro -# -fstack-protector-strong from %%optflags; use strong instead -Patch0: dd_rescue-ssp-strong.patch BuildRequires: lzop BuildRequires: pkgconfig BuildRequires: python3-base ++++++ dd_rescue-1.99.24.tar.bz2 -> dd_rescue-1.99.25.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/Makefile new/dd_rescue-1.99.25/Makefile --- old/dd_rescue-1.99.24/Makefile 2026-10-09 14:15:02.000000000 +0200 +++ new/dd_rescue-1.99.25/Makefile 2026-10-18 08:13:36.546884414 +0200 @@ -1,7 +1,7 @@ # (c) [email protected], 99/10/09, GNU GPL # (c) [email protected], 2010 -- 2021, GNU GPL v2 or v3 -VERSION = 1.99.24 +VERSION = 1.99.25 DESTDIR = THISMKFILE := $(lastword $(MAKEFILE_LIST)) @@ -9,7 +9,7 @@ CC = gcc SHELL := bash -RPM_OPT_FLAGS ?= -Os -Wall -g -D_FORTIFY_SOURCE=3 +RPM_OPT_FLAGS ?= -Os -Wall -g -D_FORTIFY_SOURCE=3 -fstack-protector CFLAGS = $(RPM_OPT_FLAGS) $(EXTRA_CFLAGS) -DHAVE_CONFIG_H -I . CFLAGS_OPT = $(CFLAGS) -O3 INSTALL ?= install @@ -337,10 +337,6 @@ %.s: $(SRCDIR)/%.c config.h $(CC) $(CFLAGS) $(DEFINES) $(PIE) -S $< -# Use stack protector for libddr_lzo ... -libddr_lzo.po: $(SRCDIR)/libddr_lzo.c config.h - $(CC) $(CFLAGS) $(PIC) -fstack-protector -o $@ -c $< - # The plugins libddr_hash.so: libddr_hash.po md5.po sha256.po $(SHAPOBJ) sha512.po sha1.po pbkdf2.po checksum_file.po $(CC) -shared -o $@ $^ $(EXTRA_LDFLAGS) @@ -579,6 +575,10 @@ $(INSTALL) $(INSTASROOT) -m 644 $(SRCDIR)/dd_rescue.1 $(SRCDIR)/ddr_lzo.1 $(SRCDIR)/ddr_crypt.1 $(SRCDIR)/ddr_lzma.1 $(MANDIR)/man1/ gzip -9f $(MANDIR)/man1/dd_rescue.1 $(MANDIR)/man1/ddr_lzo.1 $(MANDIR)/man1/ddr_crypt.1 $(MANDIR)/man1/ddr_lzma.1 +.PHONY: check_progress +check_progress: dd_rescue + bash $(SRCDIR)/test_progress.sh ./dd_rescue + check: $(TARGETS) find_nonzero md5 sha1 sha256 sha512 fmt_no @echo "make check ... Pass VG=\"valgrind --options\" to use with valgrind" $(VG) ./dd_rescue --version @@ -625,6 +625,7 @@ @echo "***** dd_rescue ratecontrol test *****" # Test system must be fast enough to achieve ~20MB/s ... OLDDT=`date +%s`; $(VG) ./dd_rescue -m 64M -C 20M /dev/zero /dev/null; DT=`date +%s`; ARCH=$$(uname -m); test $$(($$DT-$$OLDDT)) = 3 -o $$(($$DT-$$OLDDT)) = 4 || test $$(($$DT-$$OLDDT)) -ge 5 -a $${ARCH:0:3} = ppc + $(MAKE) check_progress @echo "***** dd_rescue MD5 plugin tests *****" $(VG) ./md5 /dev/null $(VG) ./md5 /dev/null | md5sum -c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/README.dd_rescue new/dd_rescue-1.99.25/README.dd_rescue --- old/dd_rescue-1.99.24/README.dd_rescue 2026-10-09 12:43:34.000000000 +0200 +++ new/dd_rescue-1.99.25/README.dd_rescue 2026-10-18 00:02:10.911059737 +0200 @@ -243,6 +243,8 @@ reflected in the exit code. It also fixes the positioning when overlapping copies are detected and the copy direction is changed. * 1.99.24 brings docu improvement and fine-tuning on remaining time estimates. +* 1.99.25 fixes missing progress reports when starting with off offsets. + Thanks to Thomas Deutschmann for the report, testcase and fix inspiration. Building diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/REL-ID new/dd_rescue-1.99.25/REL-ID --- old/dd_rescue-1.99.24/REL-ID 2026-10-09 14:46:34.000000000 +0200 +++ new/dd_rescue-1.99.25/REL-ID 2026-10-18 23:13:17.950495138 +0200 @@ -1 +1 @@ -DD_RESCUE_1_99_24 +DD_RESCUE_1_99_25 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/dd_rescue.1 new/dd_rescue-1.99.25/dd_rescue.1 --- old/dd_rescue-1.99.24/dd_rescue.1 2026-10-09 11:31:52.000000000 +0200 +++ new/dd_rescue-1.99.25/dd_rescue.1 2026-10-17 23:59:16.835772574 +0200 @@ -1065,6 +1065,8 @@ 1.99.23-24 fixed a corner case where an error from a plugin got lost and where the overlap detection for same-file copies did not treat positions according to user expectations. +1.99.25 fixed an issue where progress reports would not be generated +if starting with odd offsets. .PP Some additional information can be found on .br diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/dd_rescue.c new/dd_rescue-1.99.25/dd_rescue.c --- old/dd_rescue-1.99.24/dd_rescue.c 2026-10-09 13:48:33.000000000 +0200 +++ new/dd_rescue-1.99.25/dd_rescue.c 2026-10-18 21:06:17.692183474 +0200 @@ -254,12 +254,13 @@ /* Globals, shadowing opts/fstate info */ -char nocol; -static unsigned int pagesize; +int pagesize; +short cachelinesize; +char nocol; +char in_report; /* Rate limit for status updates */ const float printint = 0.1; -char in_report; FILE *logfd; int ddr_loglevel = 2; @@ -492,6 +493,13 @@ } assert(slk_pre == plug_max_slack_pre ); assert(slk_post == plug_max_slack_post); + /* Align real start */ + if (op->o_dir_in || op->o_dir_out) + plug_max_slack_pre = ((plug_max_slack_pre+pagesize-1)/pagesize)*pagesize; + else + plug_max_slack_pre = ((plug_max_slack_pre+cachelinesize-1)/cachelinesize)*cachelinesize; + if (plug_max_slack_pre) + fplog(stderr, DEBUG, "Plugins: Reserve %i bytes before buffer\n", plug_max_slack_pre); } int call_plugins_close(opt_t *op, fstate_t *fst) @@ -1123,7 +1131,7 @@ { static unsigned int ctr = 0; /* 1+ is there to avoid div by zero, difftimevtv also never returns zero */ - float avgrate = (float)(1+prg->xfer)/t1; + float avgrate = (float)(1+prg->xfer)/(t1+0.1); float currate = (float)(1+prg->xfer-prg->lxfer)/t2; const char *bold = BOLD, *norm = NORM; /* We have two different moving averages @@ -2397,6 +2405,7 @@ return errs; } #ifdef HAVE___BUILTIN_PREFETCH + /* Note: This assumes 64B cachelines */ if (rd >= 512 && !eno) { __builtin_prefetch(fst->buf, 0, 2); __builtin_prefetch(fst->buf+64, 0, 2); @@ -2485,14 +2494,16 @@ } errno = 0; + const int upds = (updstat >= 2 && op->hardbs < op->softbs)? updstat/2: updstat; + const int syfr = (op->syncfreq >= 2 && op->hardbs < op->softbs)? op->syncfreq/2: op->syncfreq; /* If we sync regularly, let's print a status update on each sync */ - if (op->syncfreq && !(fst->ipos % (op->syncfreq*op->softbs/2))) + if (op->syncfreq && !(fst->ipos/op->softbs % syfr)) printstatus((op->quiet? 0: stderr), 0, op->hardbs, 1, op, fst, prg, dop); /* else print regularly acc. to updstat if not quiet */ - else if (!op->quiet && !(prg->xfer % (updstat*op->softbs/2))) + else if (!op->quiet && !(prg->xfer/op->softbs % upds)) printstatus(stderr, 0, op->hardbs, 0, op, fst, prg, dop); /* even if quiet, we need to call the printstatus if we do rate limiting */ - else if (op->quiet && op->maxkbs && !(prg->xfer % (updstat*op->softbs/2))) + else if (op->quiet && op->maxkbs && !(prg->xfer/op->softbs % upds)) printstatus(0, 0, op->hardbs, 0, op, fst, prg, dop); } /* remain */ return errs; @@ -2548,6 +2559,7 @@ return errs; } #ifdef HAVE___BUILTIN_PREFETCH + /* Note: This assumes 64B cachelines */ if (rd >= 512 && !eno) { __builtin_prefetch(fst->buf, 0, 2); __builtin_prefetch(fst->buf+64, 0, 2); @@ -2630,13 +2642,13 @@ errno = 0; /* If we sync regularly, let's print a status update on each sync */ - if (op->syncfreq && !(fst->ipos % (op->syncfreq*op->softbs))) + if (op->syncfreq && !(fst->ipos/op->softbs % op->syncfreq)) printstatus((op->quiet? 0: stderr), 0, op->softbs, 1, op, fst, prg, dop); /* else print regularly acc. to updstat if not quiet */ - else if (!op->quiet && !(prg->xfer % (updstat*op->softbs))) + else if (!op->quiet && !(prg->xfer/op->softbs % updstat)) printstatus(stderr, 0, op->softbs, 0, op, fst, prg, dop); /* even if quiet, we need to call the printstatus if we do rate limiting */ - else if (op->quiet && op->maxkbs && !(prg->xfer % (updstat*op->softbs))) + else if (op->quiet && op->maxkbs && !(prg->xfer/op->softbs % updstat)) printstatus(0, 0, op->softbs, 0, op, fst, prg, dop); } /* remain */ return errs; @@ -2712,11 +2724,11 @@ fst->ipos = new_ipos; fst->opos = new_opos; } advancepos(0, 0, 0, op, fst, prg); - if (op->syncfreq && !(prg->xfer % (op->syncfreq*op->softbs))) + if (op->syncfreq && !(prg->xfer/op->softbs % op->syncfreq)) printstatus((op->quiet? 0: stderr), 0, op->softbs, 1, op, fst, prg, dop); - else if (!op->quiet && !(prg->xfer % (updstat*op->softbs))) + else if (!op->quiet && !(prg->xfer/op->softbs % updstat)) printstatus(stderr, 0, op->softbs, 0, op, fst, prg, dop); - else if (op->quiet && op->maxkbs && !(prg->xfer % (updstat*op->softbs))) + else if (op->quiet && op->maxkbs && !(prg->xfer/op->softbs % updstat)) printstatus(0, 0, op->softbs, 0, op, fst, prg, dop); } close(fd_pipe[0]); close(fd_pipe[1]); @@ -3048,6 +3060,8 @@ YESNO(op->preserve), YESNO(op->dosplice), YESNO(op->avoidwrite)); fplog(file, DEBUG, "fallocate: %s, Repeat: %s, O_DIRECT: %s/%s\n", YESNO(op->falloc), YESNO(op->i_repeat), YESNO(op->o_dir_in), YESNO(op->o_dir_out)); + fplog(file, DEBUG, "pagesize: %i, cachelinesize: %i\n", + pagesize, cachelinesize); /* fplog(file, DEBUG, "verbose: %s, quiet: %s\n", YESNO(op->verbose), YESNO(op->quiet)); @@ -3076,9 +3090,12 @@ sig, strsignal(sig)); } -unsigned char* zalloc_aligned_buf(unsigned int bs, unsigned char**obuf) +unsigned char* zalloc_aligned_buf(size_t bs, unsigned char**obuf) { unsigned char *ptr = 0; + if (bs < 512) + bs = 512; + const size_t to_alloc = bs + plug_max_slack_pre + plug_max_slack_post; /* fplog(stderr, DEBUG, "allocate zeroed aligned buffer with %i+%i+%i bytes\n", bs, plug_max_slack_pre, plug_max_slack_post); @@ -3088,23 +3105,24 @@ #ifndef HAVE_VALLOC_DECL void* valloc(size_t sz); #endif - ptr = plug_max_slack_pre%pagesize? 0: (unsigned char*)valloc(bs + plug_max_slack_pre + plug_max_slack_post); + ptr = plug_max_slack_pre%pagesize? 0: (unsigned char*)valloc(to_alloc); #elif defined(HAVE_POSIX_MEMALIGN) void *mp; - if (plug_max_slack_pre%pagesize || posix_memalign(&mp, pagesize, bs + plug_max_slack_pre + plug_max_slack_post)) + if (plug_max_slack_pre%pagesize || posix_memalign(&mp, pagesize, to_alloc)) ptr = 0; else ptr = (unsigned char*)mp; -#endif /* NetBSD */ +#endif /* VALLOC (NetBSD) */ if (obuf) *obuf = ptr; if (!ptr) { if (0 == plug_max_slack_pre%pagesize) - fplog(stderr, WARN, "allocation of aligned buffer failed -- use malloc\n"); - ptr = (unsigned char*)malloc(bs + pagesize + plug_max_slack_pre + plug_max_slack_post); + fplog(stderr, WARN, "allocation of aligned buffer of size %zi failed -- use malloc\n", + to_alloc); + ptr = (unsigned char*)malloc(to_alloc + pagesize); if (!ptr) { - fplog(stderr, FATAL, "allocation of buffer of size %li failed!\n", - bs+pagesize+plug_max_slack_pre+plug_max_slack_post); + fplog(stderr, FATAL, "allocation of buffer of size %zi failed!\n", + to_alloc+pagesize); cleanup(1); exit(18); } if (obuf) @@ -3113,7 +3131,7 @@ ptr -= (unsigned long)ptr % pagesize; } else ptr += plug_max_slack_pre; - memset(ptr-plug_max_slack_pre, 0, bs+plug_max_slack_pre+plug_max_slack_post); + memset(ptr-plug_max_slack_pre, 0, to_alloc); return ptr; } @@ -3250,13 +3268,26 @@ nocol = op->nocol; #ifdef _SC_PAGESIZE - op->pagesize = sysconf(_SC_PAGESIZE); + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize <= 0) { + fplog(stderr, WARN, "Could not determine pagesize, using 4k\n"); + pagesize = 4096; + } #else #warning Cant determine pagesize, setting to 4kiB - op->pagesize = 4096; + pagesize = 4096; +#endif + op->pagesize = pagesize; +#ifdef _SC_LEVEL1_DCACHE_LINESIZE + cachelinesize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (cachelinesize <= 0) { + fplog(stderr, DEBUG, "Could not determine cache line size, using 64\n"); + cachelinesize = 64; + } +#else +#warning Cant determine cachelinesize, setting to 64 + cachelinesize = 64; #endif - pagesize = op->pagesize; - ofiles = NULL; int tmpfd = 0; @@ -3354,9 +3385,10 @@ } /* Defaults for blocksizes */ if (op->softbs == 0) { - if (op->o_dir_in) + if (op->o_dir_in) { op->softbs = DIO_SOFTBLOCKSIZE; - else + updstat /= 4; + } else op->softbs = BUF_SOFTBLOCKSIZE; } if (op->hardbs == 0) { @@ -3681,7 +3713,6 @@ if (op->falloc && !fst->o_chr) do_fallocate(fst->odes, op->oname, op, fst); #endif - if (op->verbose) printinfo(stderr, op); @@ -3710,6 +3741,8 @@ updstat = upd; } } + if (updstat == 0) + updstat = 1; #if 0 if (op->verbose) fplog(stderr, DEBUG, "Update progress every %i kiB\n", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/secmem.c new/dd_rescue-1.99.25/secmem.c --- old/dd_rescue-1.99.24/secmem.c 2024-08-22 19:41:01.000000000 +0200 +++ new/dd_rescue-1.99.25/secmem.c 2026-10-18 16:19:01.744901655 +0200 @@ -19,15 +19,15 @@ #endif static unsigned char *optr; -static unsigned int pagesize; +static unsigned int _pagesize; sec_fields* secmem_init() { #ifdef _SC_PAGESIZE - pagesize = sysconf(_SC_PAGESIZE); + _pagesize = sysconf(_SC_PAGESIZE); #else #warning Cant determine pagesize, setting to 4kiB - pagesize = 4096; + _pagesize = 4096; #endif unsigned char *ptr = 0; #ifdef HAVE_VALLOC @@ -35,37 +35,37 @@ #ifndef HAVE_VALLOC_DECL void* valloc(size_t sz); #endif - ptr = (unsigned char*)valloc(pagesize); + ptr = (unsigned char*)valloc(_pagesize); #elif defined(HAVE_POSIX_MEMALIGN) void *mp; - if (posix_memalign(&mp, pagesize, pagesize)) + if (posix_memalign(&mp, _pagesize, _pagesize)) ptr = 0; else ptr = (unsigned char*)mp; #endif /* NetBSD */ if (!ptr) { //fplog(stderr, WARN, "allocation of aligned buffer failed -- use malloc\n"); - ptr = (unsigned char*)malloc(2*pagesize); + ptr = (unsigned char*)malloc(2*_pagesize); if (!ptr) { - fprintf(stderr, "Allocation of size %i failed!\n", 2*pagesize); + fprintf(stderr, "Allocation of size %i failed!\n", 2*_pagesize); /* fplog(stderr, FATAL, "allocation of buffer of size %li failed!\n", - bs+pagesize+plug_max_slack_pre+plug_max_slack_post); + bs+_pagesize+plug_max_slack_pre+plug_max_slack_post); cleanup(); exit(18); */ abort(); } - ptr += pagesize-1; - ptr -= (unsigned long)ptr % pagesize; + ptr += _pagesize-1; + ptr -= (unsigned long)ptr % _pagesize; } optr = ptr; - memset(ptr, 0, pagesize); - if (mlock(ptr, pagesize)) { + memset(ptr, 0, _pagesize); + if (mlock(ptr, _pagesize)) { fprintf(stderr, "Can't lock page in memory: %s\n", strerror(errno)); abort(); } #ifdef MADV_DONTDUMP - if (madvise(ptr, pagesize, MADV_DONTDUMP)) { + if (madvise(ptr, _pagesize, MADV_DONTDUMP)) { fprintf(stderr, "Can't set to exclude from core: %s\n", strerror(errno)); abort(); } @@ -98,10 +98,10 @@ memset(sf, 0, offsetof(sec_fields, hashbuf1)); abort(); } - memset(ptr, 0, pagesize); + memset(ptr, 0, _pagesize); LFENCE; - munlock(ptr, pagesize); - if ((unsigned long)ptr - (unsigned long)optr < pagesize) + munlock(ptr, _pagesize); + if ((unsigned long)ptr - (unsigned long)optr < _pagesize) free(optr); else free(ptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dd_rescue-1.99.24/test_progress.sh new/dd_rescue-1.99.25/test_progress.sh --- old/dd_rescue-1.99.24/test_progress.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/dd_rescue-1.99.25/test_progress.sh 2026-10-18 22:43:23.326450093 +0200 @@ -0,0 +1,81 @@ +#!/bin/bash +# Regression tests for progress and rate control after a partial first block. +# Usage: bash test_progress.sh [path/to/dd_rescue] +# Only temporary regular files are written. +set -euo pipefail +export LC_ALL=C + +DDR=${1:-./dd_rescue} +TESTDIR=$(mktemp -d "${TMPDIR:-/tmp}/dd-rescue-progress.XXXXXX") +trap 'rm -rf "$TESTDIR"' EXIT + +MIB=1048576 +# Avoid an exact multiple of the update interval at the final partial block. +LENGTH=$((16*MIB + 12345)) +# Same remainder modulo 1 MiB as the reported 23000277250048-byte offset. +OFFSET=716800 + +run_case() +{ + local name=$1 offset=$2 hard=$3 reverse=$4 quiet=$5 + local length=${6:-$LENGTH} + local output="$TESTDIR/output" expected="$TESTDIR/expected" + local log="$TESTDIR/stderr" progress="$TESTDIR/progress" + local total=$((offset + length + MIB)) + local -a options=(-w -b 1M -m "$length" -y 0 -C 8M) + if test "$hard" = 1; then options+=(-B 1M); fi + if test "$reverse" = 1; then + options+=(-r -S "$((offset + length))") + else + options+=(-S "$offset") + fi + if test "$quiet" = 1; then options+=(-q); fi + + echo "Testing $name" + # Sentinel bytes on both sides detect rounding of the offset or length. + head -c "$total" /dev/zero | tr '\000' '\245' > "$output" + { + head -c "$offset" /dev/zero | tr '\000' '\245' + head -c "$length" /dev/zero + head -c "$MIB" /dev/zero | tr '\000' '\245' + } > "$expected" + SECONDS=0 + if ! $VG "$DDR" "${options[@]}" /dev/zero "$output" 2> "$log"; then + cat "$log" >&2 + return 1 + fi + local elapsed=$SECONDS + # Require progress while copying, not just a status at 100% before the summary. + sed '/Summary for/,$d' "$log" > "$progress" + if test "$quiet" = 1; then + if grep -q 'ipos:' "$progress"; then + echo "FAIL: $name printed progress in quiet mode" >&2 + return 1 + fi + elif ! grep -Eq '[[:space:]][1-9][0-9]?%[[:space:]]+ETA:' "$progress"; then + echo "FAIL: $name did not print intermediate progress" >&2 + cat "$log" >&2 + return 1 + fi + # 16 MiB at 8 MiB/s should take about 2 s; allow generous timing slack. + if test "$elapsed" -lt 1; then + echo "FAIL: $name bypassed rate control" >&2 + return 1 + fi + cmp "$expected" "$output" +} + +# Match the existing test suite's optional valgrind wrapper. +VG=${VG:-} +run_case aligned 0 0 0 0 +run_case unaligned "$OFFSET" 0 0 0 +run_case unaligned-reverse "$OFFSET" 0 1 0 +run_case unaligned-hard-blocks "$OFFSET" 1 0 0 +run_case unaligned-hard-blocks-reverse "$OFFSET" 1 1 0 +run_case unaligned-quiet-rate-control "$OFFSET" 0 0 1 +run_case unaligned-hard-blocks-quiet-rate-control "$OFFSET" 1 0 1 +# The old doubled block count remains odd in these cases and skips every +# update window, including at the final partial transfer. +run_case unaligned-hard-blocks-reverse-17M "$OFFSET" 1 1 0 "$((17*MIB + 12345))" +run_case unaligned-hard-blocks-reverse-17M-quiet "$OFFSET" 1 1 1 "$((17*MIB + 12345))" +echo 'All progress tests passed'
