On 22/06/16 15:54, Pádraig Brady wrote:
> Cool, I'll add that test in your name to coreutils.

Attached.

thanks,
Pádraig

>From ef9650170f795be41223c8887258a1c596ecc162 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Sun, 26 Jun 2016 20:58:41 +0100
Subject: [PATCH 1/2] all: update gnulib submodule and tests/init.sh to latest

* gnulib: Update to latest.
* NEWS: Specifically mention the fts readdir() fix
and reindent to standard indentation.
* tests/init.sh: Update from gnulib.
---
 NEWS          | 60 ++++++++++++++++++++++++++++++++---------------------------
 gnulib        |  2 +-
 tests/init.sh | 31 ++++++++++++++++--------------
 3 files changed, 51 insertions(+), 42 deletions(-)

diff --git a/NEWS b/NEWS
index b6c5c06..bfaf239 100644
--- a/NEWS
+++ b/NEWS
@@ -4,46 +4,52 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
-   cp, mv, and install no longer run into undefined behavior when
-   handling ACLs on Cygwin and Solaris platforms. [bug introduced in
-   coreutils-8.24]
+  cp, mv, and install no longer run into undefined behavior when
+  handling ACLs on Cygwin and Solaris platforms. [bug introduced in
+  coreutils-8.24]
 
-   date, du, ls, and pr no longer mishandle time zone abbreviations on
-   System V style platforms where this information is available only
-   in the global variable 'tzname'. [bug introduced in coreutils-8.24]
+  chcon, chgrp, chmod, chown, du, and rm, or specifically utilities
+  using the FTS interface, now diagnose failures returned by readdir().
+  [this bug was inherent in the use of fts: thus, for rm the bug was
+  introduced in coreutils-8.0.  du, chmod, chgrp and chown started using
+  fts in 6.0.  chcon was added in coreutils-6.9.91 with fts support.  ]
 
-   nl now resets numbering for each page section rather than just for each page.
-   [This bug was present in "the beginning".]
+  date, du, ls, and pr no longer mishandle time zone abbreviations on
+  System V style platforms where this information is available only
+  in the global variable 'tzname'. [bug introduced in coreutils-8.24]
 
-   stty --help no longer outputs extraneous gettext header lines
-   for translated languages. [bug introduced in coreutils-8.24]
+  nl now resets numbering for each page section rather than just for each page.
+  [This bug was present in "the beginning".]
 
-   seq now immediately exits upon write errors.
-   [This bug was present in "the beginning".]
+  stty --help no longer outputs extraneous gettext header lines
+  for translated languages. [bug introduced in coreutils-8.24]
 
-   yes now handles short writes, rather than assuming all writes complete.
-   [bug introduced in coreutils-8.24]
+  seq now immediately exits upon write errors.
+  [This bug was present in "the beginning".]
+
+  yes now handles short writes, rather than assuming all writes complete.
+  [bug introduced in coreutils-8.24]
 
 ** Changes in behavior
 
-   seq no longer accepts 0 value as increment, and now also rejects NaN
-   values for any argument.
+  seq no longer accepts 0 value as increment, and now also rejects NaN
+  values for any argument.
 
-   stat now outputs nanosecond information for time stamps even if
-   they are out of localtime range.
+  stat now outputs nanosecond information for time stamps even if
+  they are out of localtime range.
 
-   sort, tail, and uniq now support traditional usage like 'sort +2'
-   and 'tail +10' on systems conforming to POSIX 1003.1-2008 and later.
-   The 2008 edition of POSIX dropped the requirement that arguments
-   like '+2' must be treated as file names.
+  sort, tail, and uniq now support traditional usage like 'sort +2'
+  and 'tail +10' on systems conforming to POSIX 1003.1-2008 and later.
+  The 2008 edition of POSIX dropped the requirement that arguments
+  like '+2' must be treated as file names.
 
 ** Improvements
 
-   stat and tail now know about "prl_fs" (a parallels file system),
-   "m1fs" (a Plexistor file system), "wslfs" (Windows Subsystem for Linux),
-   and "smb2".  stat -f --format=%T now reports the file system type, and
-   tail -f uses polling for "prl_fs" and "smb2", inotify for "m1fs",
-   and attempts inotify for "wslfs".
+  stat and tail now know about "prl_fs" (a parallels file system),
+  "m1fs" (a Plexistor file system), "wslfs" (Windows Subsystem for Linux),
+  and "smb2".  stat -f --format=%T now reports the file system type, and
+  tail -f uses polling for "prl_fs" and "smb2", inotify for "m1fs",
+  and attempts inotify for "wslfs".
 
 
 * Noteworthy changes in release 8.25 (2016-01-20) [stable]
diff --git a/gnulib b/gnulib
index 841c4fa..6835fc4 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 841c4fa800b4c5c930c3350e5a9a164b204a79c8
+Subproject commit 6835fc458f30b94f15d69c35a79cbc2dfabe2d06
diff --git a/tests/init.sh b/tests/init.sh
index ee08022..97e4e4b 100755
--- a/tests/init.sh
+++ b/tests/init.sh
@@ -308,13 +308,19 @@ if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \
       fi
     }
   fi
-elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then
+elif
+  for diff_opt_ in -U3 -c '' no; do
+    test "$diff_opt_" = no && break
+    diff_out_=`exec 2>/dev/null; diff $diff_opt_ "$0" "$0" </dev/null` && break
+  done
+  test "$diff_opt_" != no
+then
   if test -z "$diff_out_"; then
-    compare_ () { diff -c "$@"; }
+    compare_ () { diff $diff_opt_ "$@"; }
   else
     compare_ ()
     {
-      if diff -c "$@" > diff.out; then
+      if diff $diff_opt_ "$@" > diff.out; then
         # No differences were found, but AIX and HP-UX 'diff' produce output
         # "No differences encountered" or "There are no differences between the
         # files.". Hide this output.
@@ -466,7 +472,6 @@ setup_ ()
   fi
 
   initial_cwd_=$PWD
-  fail=0
 
   pfx_=`testdir_prefix_`
   test_dir_=`mktempd_ "$initial_cwd_" "$pfx_-$ME_.XXXX"` \
@@ -550,8 +555,9 @@ mktempd_ ()
   # Disallow any trailing slash on specified destdir:
   # it would subvert the post-mktemp "case"-based destdir test.
   case $destdir_ in
-  /) ;;
+  / | //) destdir_slash_=$destdir;;
   */) fail_ "invalid destination dir: remove trailing slash(es)";;
+  *) destdir_slash_=$destdir_/;;
   esac
 
   case $template_ in
@@ -561,20 +567,17 @@ mktempd_ ()
   esac
 
   # First, try to use mktemp.
-  d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` \
-    || fail=1
+  d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` &&
 
   # The resulting name must be in the specified directory.
-  case $d in "$destdir_"*);; *) fail=1;; esac
+  case $d in "$destdir_slash_"*) :;; *) false;; esac &&
 
   # It must have created the directory.
-  test -d "$d" || fail=1
+  test -d "$d" &&
 
   # It must have 0700 permissions.  Handle sticky "S" bits.
-  perms=`ls -dgo "$d" 2>/dev/null|tr S -` || fail=1
-  case $perms in drwx------*) ;; *) fail=1;; esac
-
-  test $fail = 0 && {
+  perms=`ls -dgo "$d" 2>/dev/null` &&
+  case $perms in drwx--[-S]---*) :;; *) false;; esac && {
     echo "$d"
     return
   }
@@ -593,7 +596,7 @@ mktempd_ ()
   i_=1
   while :; do
     X_=`rand_bytes_ $nx_`
-    candidate_dir_="$destdir_/$base_template_$X_"
+    candidate_dir_="$destdir_slash_$base_template_$X_"
     err_=`mkdir -m 0700 "$candidate_dir_" 2>&1` \
       && { echo "$candidate_dir_"; return; }
     test $MAX_TRIES_ -le $i_ && break;
-- 
2.5.5


>From e84298a2589918ffe74a71d91fcf5271eacb3708 Mon Sep 17 00:00:00 2001
From: Peter Benie <[email protected]>
Date: Sun, 26 Jun 2016 19:07:45 +0100
Subject: [PATCH 2/2] tests: verify that fts diagnoses readdir() failures

* tests/rm/rm-readdir-fail.sh: A new test to simulate readdir()
failing immediately or after returning a few entries, and verifying
that rm does the appropriate thing.
This was initially reported at:
http://bugzilla.opensuse.org/show_bug.cgi?id=984910
where it was mentioned that readdir() may fail
when an NFS server has a poor readdir cookie implementation.
---
 tests/local.mk              |   1 +
 tests/rm/rm-readdir-fail.sh | 108 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)
 create mode 100755 tests/rm/rm-readdir-fail.sh

diff --git a/tests/local.mk b/tests/local.mk
index d3afb6e..3032bda 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -223,6 +223,7 @@ all_tests =					\
   tests/rm/unreadable.pl			\
   tests/rm/v-slash.sh				\
   tests/rm/many-dir-entries-vs-OOM.sh		\
+  tests/rm/rm-readdir-fail.sh			\
   tests/chgrp/default-no-deref.sh		\
   tests/chgrp/deref.sh				\
   tests/chgrp/no-x.sh				\
diff --git a/tests/rm/rm-readdir-fail.sh b/tests/rm/rm-readdir-fail.sh
new file mode 100755
index 0000000..20ea50e
--- /dev/null
+++ b/tests/rm/rm-readdir-fail.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+# Test rm's behaviour when the directory cannot be read.
+# This test is skipped on systems that lack LD_PRELOAD support.
+
+# Copyright (C) 2016 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=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_gcc_shared_
+
+mkdir -p dir/notempty || framework_failure_
+
+# Simulate "readdir" failure.
+cat > k.c <<\EOF || framework_failure_
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+struct dirent *readdir (DIR *dirp)
+{
+  struct dirent *(*real_readdir)(DIR *dirp) = dlsym (RTLD_NEXT, "readdir");
+  if (! real_readdir)
+    {
+      fprintf (stderr, "Failed to find readdir()\n");
+      errno = ESRCH;
+      return NULL;
+    }
+  struct dirent* d = real_readdir (dirp);
+  if (! d)
+    {
+      fprintf (stderr, "Failed to get dirent\n");
+      errno = ENOENT;
+      return NULL;
+    }
+
+  /* Flag that LD_PRELOAD and above functions work.  */
+  static int done = 0;
+  if (! done)
+    {
+      fclose (fopen ("preloaded", "w"));
+      done++;
+    }
+
+  /* Return some entries to trigger partial read failure,
+     ensuring we don't return ignored '.' or '..'  */
+  char const *readdir_partial = getenv ("READDIR_PARTIAL");
+  if (readdir_partial && *readdir_partial && done <= 3)
+    {
+      done++;
+      d->d_name[0]='0'+done; d->d_name[1]='\0';
+#ifdef _DIRENT_HAVE_D_NAMLEN
+      _D_EXACT_NAMELEN(d)=2;
+#endif
+      errno = 0;
+      return d;
+    };
+
+  /* Fail.  */
+  errno = ENOENT;
+  return NULL;
+}
+
+struct dirent64 *readdir64 (DIR *dirp)
+{
+  return (struct dirent64 *) readdir (dirp);
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+  || framework_failure_ 'failed to build shared library'
+
+# Test if LD_PRELOAD works:
+export READDIR_PARTIAL
+for READDIR_PARTIAL in '' '1'; do
+  (LD_PRELOAD=$LD_PRELOAD:./k.so returns_ 1 rm -Rf dir 2>>err) || fail=1
+done
+test -f preloaded ||
+  skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+
+# First case is failure to read any items from dir, then assume empty.
+# Generally that will be diagnosed when rm tries to rmdir().
+# Second case is more general error where we fail immediately
+# (with ENOENT in this case but it could be anything).
+cat <<EOF > exp
+rm: cannot remove 'dir': Directory not empty
+rm: traversal failed: dir: No such file or directory
+EOF
+
+compare exp err || fail=1
+
+Exit $fail
-- 
2.5.5

Reply via email to