[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
a real fts.c bug + fix
From: |
Jim Meyering |
Subject: |
a real fts.c bug + fix |
Date: |
Thu, 12 Jan 2006 11:12:00 +0100 |
I discovered a long-standing bug in fts.c yesterday:
2006-01-11 Jim Meyering <address@hidden>
* fts.c (fts_stat): When following a symlink-to-directory,
don't necessarily interpret stat-fails+lstat-succeeds as indicating
a dangling symlink. That can also happen at least for ELOOP.
The fix: return FTS_SLNONE only when the stat errno is ENOENT.
FYI, this bug predates the inclusion of fts.c in coreutils.
I've included the test case, below.
If any of you know of a system with file name resolution code that
doesn't fail for a chain of 400 symlinks, or for which you get a
different diagnostic than `Too many levels of symbolic links' (ELOOP),
please provide details.
2006-01-11 Jim Meyering <address@hidden>
* tests/du/long-sloop: New file. Test for today's fts.c bug fix.
That bug could make du -L, chgrp -L, or chown -L fail to diagnose
a very long sequence of symbolic links (not necessarily a loop).
* tests/du/Makefile.am (TESTS): Add long-sloop.
Index: lib/fts.c
===================================================================
RCS file: /fetish/cu/lib/fts.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -p -u -r1.42 -r1.43
--- lib/fts.c 11 Jan 2006 16:29:35 -0000 1.42
+++ lib/fts.c 11 Jan 2006 21:00:36 -0000 1.43
@@ -1069,7 +1069,8 @@ fts_stat(FTS *sp, register FTSENT *p, bo
if (ISSET(FTS_LOGICAL) || follow) {
if (stat(p->fts_accpath, sbp)) {
saved_errno = errno;
- if (!lstat(p->fts_accpath, sbp)) {
+ if (errno == ENOENT
+ && lstat(p->fts_accpath, sbp) == 0) {
__set_errno (0);
return (FTS_SLNONE);
}
Index: tests/du/long-sloop
===================================================================
RCS file: tests/du/long-sloop
diff -N tests/du/long-sloop
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/du/long-sloop 12 Jan 2006 09:25:33 -0000 1.3
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Use du to exercise a corner of fts's FTS_LOGICAL code.
+# Show that du fails with ELOOP (Too many levels of symbolic links)
+# when it encounters that condition.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ du --version
+fi
+
+. $srcdir/../lang-default
+
+pwd=`pwd`
+t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
+trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
+trap '(exit $?); exit $?' 1 2 13 15
+
+framework_failure=0
+mkdir -p $tmp || framework_failure=1
+cd $tmp || framework_failure=1
+
+# Create lots of directories, each containing a single symlink
+# pointing at the next directory in the list.
+
+# This number should be larger than the number of symlinks allowed in
+# file name resolution, but not too large as a number of entries
+# in a single directory.
+n=400
+
+dir_list=`seq $n`
+mkdir $dir_list || framework_failure=1
+for i in $dir_list; do
+ ip1=`expr $i + 1`
+ ln -s ../$ip1 $i/s || framework_failure=1
+done
+
+if test $framework_failure = 1; then
+ echo "$0: failure in testing framework" 1>&2
+ (exit 1); exit 1
+fi
+
+# If a system can handle this many symlinks in a file name,
+# just skip this test.
+file=1`printf %${n}s ' '|sed 's, ,/s,g'`
+cat $file > /dev/null 2>&1 && \
+ {
+ cat <<EOF >&2
+$0: Your systems appears to be able to handle more than $n symlinks
+in file name resolution, so skipping this test.
+EOF
+ (exit 77); exit 77
+ }
+
+fail=0
+
+# With coreutils-5.93 there was no failure.
+# With coreutils-5.94 we get a diagnostic like this:
+# du: cannot access `1/s/s/s/.../s': Too many levels of symbolic links
+du -L 1 > /dev/null 2> out1 && fail=1
+sed "s,1/s/s/s/[/s]*','," out1 > out || fail=1
+cat <<\EOF > exp || fail=1
+du: cannot access `': Too many levels of symbolic links
+EOF
+
+cmp out exp || fail=1
+test $fail = 1 && diff out exp 2> /dev/null
+
+(exit $fail); exit $fail
- a real fts.c bug + fix,
Jim Meyering <=