From 1209d61ac0c940bdd2dd11448cc9e1b3e9b59a29 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 28 Nov 2015 18:02:05 -0800 Subject: [PATCH] diff --brief no longer mistakenly reports diff. with 0-sized /proc/ files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/analyze.c (diff_2_files): Don't declare difference when any st_size is 0. * src/diff.c (compare_files): Likewise. * tests/brief-vs-proc-stat-zero: New test. * tests/Makefile.am: Add it. * NEWS (Bug fixes): Describe it. Reported by Stephan Müller in http://debbugs.gnu.org/21942 --- NEWS | 8 ++++++++ src/analyze.c | 2 ++ src/diff.c | 4 +++- tests/Makefile.am | 1 + tests/brief-vs-stat-zero-kernel-lies | 30 ++++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 tests/brief-vs-stat-zero-kernel-lies diff --git a/NEWS b/NEWS index 088f13b..1724c74 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,14 @@ GNU diffutils NEWS -*- outline -*- diff -B no longer generates incorrect output if the two inputs each end with a one-byte incomplete line. + diff --brief no longer reports a difference for unusual identical files. + For example, when comparing a file like /proc/cmdline (for which the linux + kernel reports st_size of 0 even though it is not an empty file) to a + copy of that file's contents residing on a "normal" file system: + $ f=/proc/cmdline; cp $f k; diff --brief $f k + Files /proc/cmdline and k differ + + ** Performance changes diff's default algorithm has been adjusted to output higher-quality diff --git a/src/analyze.c b/src/analyze.c index 893d07c..2622810 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -477,6 +477,8 @@ diff_2_files (struct comparison *cmp) { /* Files with different lengths must be different. */ if (cmp->file[0].stat.st_size != cmp->file[1].stat.st_size + && 0 < cmp->file[0].stat.st_size + && 0 < cmp->file[1].stat.st_size && (cmp->file[0].desc < 0 || S_ISREG (cmp->file[0].stat.st_mode)) && (cmp->file[1].desc < 0 || S_ISREG (cmp->file[1].stat.st_mode))) changes = 1; diff --git a/src/diff.c b/src/diff.c index 46ac99d..cff23f0 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1377,7 +1377,9 @@ compare_files (struct comparison const *parent, else if (files_can_be_treated_as_binary && S_ISREG (cmp.file[0].stat.st_mode) && S_ISREG (cmp.file[1].stat.st_mode) - && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size) + && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size + && 0 < cmp.file[0].stat.st_size + && 0 < cmp.file[1].stat.st_size) { message ("Files %s and %s differ\n", file_label[0] ? file_label[0] : cmp.file[0].name, diff --git a/tests/Makefile.am b/tests/Makefile.am index 805ccc2..b070a76 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,6 +4,7 @@ TESTS = \ basic \ bignum \ binary \ + brief-vs-stat-zero-kernel-lies \ colliding-file-names \ excess-slash \ help-version \ diff --git a/tests/brief-vs-stat-zero-kernel-lies b/tests/brief-vs-stat-zero-kernel-lies new file mode 100755 index 0000000..9b272c6 --- /dev/null +++ b/tests/brief-vs-stat-zero-kernel-lies @@ -0,0 +1,30 @@ +#!/bin/sh +# Before diff-3.4, diff --brief could mistakenly declare a difference. +# For example, when comparing a file like /proc/cmdline (for which the linux +# kernel reports a st_size of 0 even though it is not an empty file) to a +# copy of that file's contents residing on a "normal" file system. + +. "${srcdir=.}/init.sh"; path_prepend_ ../src + +fail=0 + +# Skip the test unless we have an appropriate file. +boot=/proc/cmdline +test -f $boot || skip_ no $boot file +sz=$(stat --format %s $boot) || skip_ stat --format %s does not work +test $sz = 0 || skip_ $boot has nonzero size + +# There are two code paths to test: one for non-binary and one for binary files. +# $boot is non-binary. +cat $boot > ref || framework_failure_ +diff --brief $boot ref > out 2>&1 || fail=1 +compare /dev/null out || fail=1 + +# /proc/self/cmdline is a NUL-terminated list of argv values, +# so construct the expected output here: +printf 'diff\0--brief\0/proc/self/cmdline\0bin\0' > bin || framework_failure_ +# And run the command that is embedded in that output: +diff --brief /proc/self/cmdline bin > out 2>&1 || fail=1 +compare /dev/null out || fail=1 + +Exit $fail -- 2.6.2