diff --git a/NEWS b/NEWS index b6b2ab8..fcf4986 100644 --- a/NEWS +++ b/NEWS @@ -4,9 +4,7 @@ GNU diffutils NEWS -*- outline -*- ** Bug fixes - cmp -i N no longer fails merely if N exceeds the maximum off_t value, - and no longer mishandles Linux tmpfs files when N is slightly less - than the maximum off_t value. + cmp -i N and -n N no longer fail merely because N is enormous. [bug present since "the beginning"] cmp -s no longer mishandles /proc files, for which the Linux kernel diff --git a/TODO b/TODO index 25fc22b..fa08112 100644 --- a/TODO +++ b/TODO @@ -6,8 +6,10 @@ GNU patch already parses this format. Add --include option (opposite of --exclude). +Add SEEK_DATA/SEEK_HOLE sparse file optimization to cmp, diff -q, etc. + Look into sdiff improvement here: -http://www.pkix.net/~chuck/sdiff2.diff +https://web.archive.org/web/20090106164131/http://www.pkix.net/~chuck/sdiff2.diff Propagate stderr from subprocess so that diff3 does a better job of explaining _why_: diff --git a/src/cmp.c b/src/cmp.c index 6e73dfa..e3c1c1e 100644 --- a/src/cmp.c +++ b/src/cmp.c @@ -81,8 +81,12 @@ static idx_t buf_size; requested to ignore more than TYPE_MAXIMUM (intmax_t) bytes. */ static intmax_t ignore_initial[2]; -/* Number of bytes to compare, or negative if there is no limit. */ -static intmax_t bytes = -1; +/* Number of bytes to compare. INTMAX_MAX is effectively infinity, + since there's no practical way on current computers to compare so + many bytes. Even if cmp added SEEK_HOLE and SEEK_DATA optimization, + regular files can't have more than TYPE_MAXIMUM (off_t) bytes + and special files are unlikely to support this optimization. */ +static intmax_t bytes = INTMAX_MAX; /* Output format. */ static enum comparison_type @@ -240,11 +244,10 @@ main (int argc, char **argv) case 'n': { intmax_t n; - if (xstrtoimax (optarg, nullptr, 0, &n, valid_suffixes) != LONGINT_OK - || n < 0) + strtol_error e = xstrtoimax (optarg, nullptr, 0, &n, valid_suffixes); + if ((e & ~LONGINT_OVERFLOW) != LONGINT_OK || n < 0) try_help ("invalid --bytes value '%s'", optarg); - if (! (0 <= bytes && bytes < n)) - bytes = n; + bytes = MIN (bytes, n); } break; @@ -365,7 +368,7 @@ main (int argc, char **argv) s0 = 0; if (s1 < 0) s1 = 0; - if (s0 != s1 && (bytes < 0 || MIN (s0, s1) < bytes)) + if (s0 != s1 && MIN (s0, s1) < bytes) exit (EXIT_FAILURE); } } @@ -412,19 +415,14 @@ cmp (void) if (comparison_type == type_all_diffs) { - off_t byte_number_max = (0 <= bytes && bytes <= TYPE_MAXIMUM (off_t) - ? bytes : TYPE_MAXIMUM (off_t)); + intmax_t byte_number_max = bytes; for (int f = 0; f < 2; f++) if (0 < stat_buf[f].st_size && S_ISREG (stat_buf[f].st_mode)) { off_t pos = file_position (f); - if (0 <= pos) - { - off_t file_bytes = MAX (0, stat_buf[f].st_size - pos); - if (file_bytes < byte_number_max) - byte_number_max = file_bytes; - } + off_t after_pos = stat_buf[f].st_size - MAX (0, pos); + byte_number_max = MIN (byte_number_max, after_pos); } for (offset_width = 1; (byte_number_max /= 10) != 0; offset_width++) @@ -484,14 +482,8 @@ cmp (void) while (true) { - idx_t bytes_to_read = buf_size; - - if (0 <= remaining) - { - if (remaining < bytes_to_read) - bytes_to_read = remaining; - remaining -= bytes_to_read; - } + idx_t bytes_to_read = MIN (buf_size, remaining); + remaining -= bytes_to_read; ptrdiff_t read0 = (eof[0] ? 0 : block_read (file_desc[0], buf0, bytes_to_read)); diff --git a/tests/cmp b/tests/cmp index 079c2ff..ef99d96 100755 --- a/tests/cmp +++ b/tests/cmp @@ -228,6 +228,8 @@ cmp -bl j1 j2 > out2 test $? -eq 1 || fail=1 compare exp2 out2 || fail=1 -cmp -i 99999999999999999999999999999999999999999999999999 j1 j2 || fail=1 +big=99999999999999999999999999999999999999999999999999999999999 +cmp -i $big j1 j2 || fail=1 +cmp -i 1000 -n $big j1 j2 || fail=1 Exit $fail