du: don't infloop for --files0-from=DIR
authorJim Meyering <meyering@redhat.com>
Wed, 2 Mar 2011 18:16:46 +0000 (19:16 +0100)
committerJim Meyering <meyering@redhat.com>
Thu, 3 Mar 2011 08:05:44 +0000 (09:05 +0100)
* src/du.c (main): Fail on AI_ERR_READ error, rather than merely
diagnosing and continuing.  Based on a patch by Stefan Vargyas.
Also move the handling of AI_ERR_EOF into the case stmt.
Do not report ferror/fclose(stdin) failure when we've
already diagnosed e.g., failure to read the DIR, above.
Bug introduced by 2008-11-24 commit 031e2fb5, "du: read and
process --files0-from= input a name at a time,".
* src/wc.c: Handle read failure as with du: do not exit
immediately, but rather go on to print any total and to clean-up.
As above, move the handling of AI_ERR_EOF into the case stmt.
* tests/du/files0-from-dir: New file, to test both du and wc.
* tests/Makefile.am (TESTS): Add it.
* NEWS (Bug fixes): Mention it.

NEWS
THANKS.in
src/du.c
src/wc.c
tests/Makefile.am
tests/du/files0-from-dir [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 9993469..658a89a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
+  du would infloop when given --files0-from=DIR
+  [bug introduced in coreutils-7.1]
+
   cut could segfault when invoked with a user-specified output
   delimiter and an unbounded range like "-f1234567890-".
   [bug introduced in coreutils-5.3.0]
index b475eef..fe53c44 100644 (file)
--- a/THANKS.in
+++ b/THANKS.in
@@ -524,6 +524,7 @@ Soeren Sonnenburg                   sonnenburg@informatik.hu-berlin.de
 Solar Designer                      solar@owl.openwall.com
 Stanislav Ievlev                    inger@altlinux.ru
 Stavros Passas                      stabat@ics.forth.gr
+Stefan Vargyas                      stvar@yahoo.com
 Stéphane Chazelas                   Stephane_CHAZELAS@yahoo.fr
 Stephen Depooter                    sbdep@myrealbox.com
 Stephen Eglen                       eglen@pcg.wustl.edu
index 671cac7..67841a3 100644 (file)
--- a/src/du.c
+++ b/src/du.c
@@ -926,19 +926,19 @@ main (int argc, char **argv)
       bool skip_file = false;
       enum argv_iter_err ai_err;
       char *file_name = argv_iter (ai, &ai_err);
-      if (ai_err == AI_ERR_EOF)
-        break;
       if (!file_name)
         {
           switch (ai_err)
             {
+            case AI_ERR_EOF:
+              goto argv_iter_done;
             case AI_ERR_READ:
-              error (0, errno, _("%s: read error"), quote (files_from));
-              continue;
-
+              error (0, errno, _("%s: read error"),
+                     quotearg_colon (files_from));
+              ok = false;
+              goto argv_iter_done;
             case AI_ERR_MEM:
               xalloc_die ();
-
             default:
               assert (!"unexpected error code from argv_iter");
             }
@@ -985,11 +985,12 @@ main (int argc, char **argv)
           ok &= du_files (temp_argv, bit_flags);
         }
     }
+ argv_iter_done:
 
   argv_iter_free (ai);
   di_set_free (di_set);
 
-  if (files_from && (ferror (stdin) || fclose (stdin) != 0))
+  if (files_from && (ferror (stdin) || fclose (stdin) != 0) && ok)
     error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));
 
   if (print_grand_total)
index ccf4ccf..0399214 100644 (file)
--- a/src/wc.c
+++ b/src/wc.c
@@ -722,16 +722,17 @@ main (int argc, char **argv)
       bool skip_file = false;
       enum argv_iter_err ai_err;
       char *file_name = argv_iter (ai, &ai_err);
-      if (ai_err == AI_ERR_EOF)
-        break;
       if (!file_name)
         {
           switch (ai_err)
             {
+            case AI_ERR_EOF:
+              goto argv_iter_done;
             case AI_ERR_READ:
-              error (EXIT_FAILURE, errno, _("%s: read error"),
-                     quote (files_from));
-              continue;
+              error (0, errno, _("%s: read error"),
+                     quotearg_colon (files_from));
+              ok = false;
+              goto argv_iter_done;
             case AI_ERR_MEM:
               xalloc_die ();
             default:
@@ -773,6 +774,7 @@ main (int argc, char **argv)
       else
         ok &= wc_file (file_name, &fstatus[nfiles ? i : 0]);
     }
+ argv_iter_done:
 
   /* No arguments on the command line is fine.  That means read from stdin.
      However, no arguments on the --files0-from input stream is an error
index 9603441..28eafe8 100644 (file)
@@ -370,6 +370,7 @@ TESTS =                                             \
   du/exclude                                   \
   du/fd-leak                                   \
   du/files0-from                               \
+  du/files0-from-dir                           \
   du/hard-link                                 \
   du/inacc-dest                                        \
   du/inacc-dir                                 \
diff --git a/tests/du/files0-from-dir b/tests/du/files0-from-dir
new file mode 100755 (executable)
index 0000000..fc1e184
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+# ensure that du and wc handle --files0-from=DIR
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ du wc
+
+mkdir dir
+
+# Skip this test if reading from a directory succeeds.
+# In that case, using --files0-from=dir would yield garbage,
+# interpreting the directory entry as a sequence of
+# NUL-separated file names.
+cat dir > /dev/null && skip_ "cat dir/ succeeds"
+
+for prog in du wc; do
+  $prog --files0-from=dir > /dev/null 2>err && fail=1
+  printf "$prog: dir:\n" > exp || fail=1
+  # The diagnostic string is usually "Is a directory" (ENOTDIR),
+  # but accept a different string or errno value.
+  sed 's/dir:.*/dir:/' err > k; mv k err
+  compare err exp || fail=1
+done
+
+Exit $fail