I discovered a long-standing bug in fts.c yesterday: 2006-01-11 Jim Meyering <[EMAIL PROTECTED]>
* 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 <[EMAIL PROTECTED]> * 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 _______________________________________________ bug-gnulib mailing list bug-gnulib@gnu.org http://lists.gnu.org/mailman/listinfo/bug-gnulib