During parallel file system tests fts(3) may return a wrong value in fts_info. # FAULT # -rw------- 1 root wheel - 4 13 jan 09:25 ./lockf.0.3676 # fts_path: ./lockf.0.3676 # fts_info: 13 FTS_SLNONE # fts_errno: 0 No error: 0 Test scenario @ http://people.freebsd.org/~pho/fts2.sh
When following symlinks, fts returns FTS_SLNONE when stat() fails, but a subsequent lstat() succeeds (in recent versions fstatat() without and with AT_SYMLINK_NOFOLLOW). This incorrectly triggers if a filename exists to be read from the directory, is deleted before the stat and created again after the stat. Clearly, the code should only return FTS_SLNONE if S_ISLNK(sbp->st_mode). What it should do otherwise is less clear. We could go back to stat() and try some number of times for stat() and lstat() to become consistent, or we could return FTS_NS immediately.
Created attachment 155166 [details] don't return FTS_SLNONE if it's not a symlink (if race)
The patch looks good. Tested on r281013. Thank you for looking at this!
A commit references this bug: Author: jilles Date: Sat Apr 4 20:22:13 UTC 2015 New revision: 281082 URL: https://svnweb.freebsd.org/changeset/base/281082 Log: fts: Don't return FTS_SLNONE if it's not a symlink (if race). When following symlinks, fts returned FTS_SLNONE when fstatat(flag=0) failed, but a subsequent fstatat(flag=AT_SYMLINK_NOFOLLOW) succeeded. This incorrectly triggered if a filename existed to be read from the directory, was deleted before the fstatat(flag=0) and created again after the fstatat(flag=0). Fix this by only returning FTS_SLNONE if the result from fstatat(flag=AT_SYMLINK_NOFOLLOW) is actually a symlink. If it is not a symlink, treat it as if fstatat(flag=0) succeeded. PR: 196724 Reported and tested by: pho MFC after: 1 week Changes: head/lib/libc/gen/fts.c
A commit references this bug: Author: jilles Date: Sun Apr 19 13:28:32 UTC 2015 New revision: 281741 URL: https://svnweb.freebsd.org/changeset/base/281741 Log: MFC r281082: fts: Don't return FTS_SLNONE if it's not a symlink (if race). When following symlinks, fts returned FTS_SLNONE when fstatat(flag=0) failed, but a subsequent fstatat(flag=AT_SYMLINK_NOFOLLOW) succeeded. This incorrectly triggered if a filename existed to be read from the directory, was deleted before the fstatat(flag=0) and created again after the fstatat(flag=0). Fix this by only returning FTS_SLNONE if the result from fstatat(flag=AT_SYMLINK_NOFOLLOW) is actually a symlink. If it is not a symlink, treat it as if fstatat(flag=0) succeeded. PR: 196724 Changes: _U stable/10/ stable/10/lib/libc/gen/fts.c