Diffutils patch regarding special files

Jason Todd <[email protected]> Tue, 11 Nov 2008 18:15:01 -0500 (EST)
Newsgroups gmane.comp.gnu.utils
Message-ID <[email protected]>
Hi,

I have put together the attached simple patch for diff.c of the Diffutils 
package (specifically version 2.8.1).  This patch suppresses the messages 
(and failure exit status) when non-regular files are encountered during 
recursive comparisons, if the "-Q" or "--ignore_special" command line 
arguments are given.  Examples of the suppressed messages are:

File original/dev/char1-3 is a character special file while file 
test1/dev/char1-3 is a character special file
File original/misc/a-fifo is a fifo while file test1/misc/a-fifo is a fifo
File original/misc/a-socket is a socket while file test1/misc/a-socket is 
a fifo

Instead, the patch looks a little further, and if the files are of the 
same type and are not device files, it considers them a match.  In the 
case of device files, if they are of the same type (block or character) 
and refer to the same device (via stat.st_rdev), then it considers them a 
match.

When comparing two complete filesystems, or large portions of them (which 
I do a lot), these messages tend to get in the way.  Broken symlinks, 
which are common in almost every distribution, are still reported, but 
those messages I am willing to filter outside of diff.

I can submit a larger patch that includes the relevant changes to the 
documentation supplied with Diffutils, if you would like.  Further, I can 
update and re-package everything as diffutils-2.8.2 if you would like (but 
I don't want to intrude too much).  Just let me know.

Thanks,
Jason Todd
diff-ignore_special.patch (text/plain, 3.3 KB)
diff -Naur diffutils-2.8.1/src/diff.c new.diffutils-2.8.1/src/diff.c
--- diffutils-2.8.1/src/diff.c	2002-03-24 02:35:28.000000000 -0500
+++ new.diffutils-2.8.1/src/diff.c	2008-11-11 16:49:21.000000000 -0500
@@ -70,6 +70,10 @@
    recursively.  */
 static bool recursive;
 
+/* If two non-regular files are of the same type, suppress the POSIX-specified
+   message and prevent a failure exit status in this case.  */
+static bool ignore_special;
+
 /* In context diffs, show previous lines that match these regexps.  */
 static struct regexp_list function_regexp_list;
 
@@ -139,7 +143,7 @@
 }
 
 static char const shortopts[] =
-"0123456789abBcC:dD:eEfF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y";
+"0123456789abBcC:dD:eEfF:hHiI:lL:nNpPqQrsS:tTuU:vwW:x:X:y";
 
 /* Values for long options that do not have single-letter equivalents.  */
 enum
@@ -207,6 +211,7 @@
   {"ignore-file-name-case", 0, 0, IGNORE_FILE_NAME_CASE_OPTION},
   {"ignore-matching-lines", 1, 0, 'I'},
   {"ignore-space-change", 0, 0, 'b'},
+  {"ignore-special", 0, 0, 'Q'},
   {"ignore-tab-expansion", 0, 0, 'E'},
   {"inhibit-hunk-merge", 0, 0, INHIBIT_HUNK_MERGE_OPTION},
   {"initial-tab", 0, 0, 'T'},
@@ -441,6 +446,10 @@
 	  brief = 1;
 	  break;
 
+	case 'Q':
+	  ignore_special = 1;
+	  break;
+
 	case 'r':
 	  recursive = 1;
 	  break;
@@ -851,6 +860,7 @@
   -p  --show-c-function  Show which C function each change is in.\n\
   -F RE  --show-function-line=RE  Show the most recent line matching RE."),
   N_("-q  --brief  Output only whether files differ."),
+  N_("-Q  --ignore-special  Ignore non-regular files with matching types."),
   N_("-e  --ed  Output an ed script."),
   N_("--normal  Output a normal diff."),
   N_("-n  --rcs  Output an RCS format diff."),
@@ -1258,10 +1268,13 @@
 	      status = EXIT_FAILURE;
 	    }
 	}
-      else
+      else if ((filetype(&cmp.file[0].stat) != filetype(&cmp.file[1].stat)) ||
+	       !ignore_special)
 	{
 	  /* We have two files that are not to be compared.  */
 
+	  /* This is suppressed if "-Q" has been specified.  */
+
 	  /* See POSIX 1003.1-2001 for this format.  */
 	  message5 ("File %s is a %s while file %s is a %s\n",
 		    file_label[0] ? file_label[0] : cmp.file[0].name,
@@ -1272,6 +1285,30 @@
 	  /* This is a difference.  */
 	  status = EXIT_FAILURE;
 	}
+#if HAVE_STRUCT_STAT_ST_RDEV && (defined S_ISCHR) && (defined S_ISBLK)
+      else
+	{
+	  /* We have two non-regular files, and "-Q" has been specified.  */
+
+	  /* The file types (and names, if recursive) match, and that is all
+	     that is necessary to know that they represent the same thing in
+	     the case of FIFOs and sockets.  For device nodes, check the major
+	     and minor numbers.  */
+
+	  /* Note, st_rdev is an extension to POSIX/SUSv3.  */
+
+	  if ((S_ISCHR(cmp.file[0].stat.st_mode) ||
+	       S_ISBLK(cmp.file[0].stat.st_mode)) &&
+	      (cmp.file[0].stat.st_rdev != cmp.file[1].stat.st_rdev))
+	    {
+	      message ("Device nodes %s and %s represent different devices\n",
+		       file_label[0] ? file_label[0] : cmp.file[0].name,
+		       file_label[1] ? file_label[1] : cmp.file[1].name);
+
+	      status = EXIT_FAILURE;
+	    }
+	}
+#endif
     }
   else if (files_can_be_treated_as_binary
 	   && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size