From: Pádraig Brady Date: Wed, 22 Jun 2016 12:49:53 +0000 (+0100) Subject: fts: handle readdir() errors X-Git-Tag: v1.0~6720 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=6835fc458f30b94f15d69c35a79cbc2dfabe2d06;p=gnulib.git fts: handle readdir() errors * lib/fts.c (fts_build): readdir(3) returns NULL when finished, but also upon error when it will also set errno. Therefore flag the error case from readdir(). We treat the case where no items are read the same as if the dir can't be accessed, i.e. by setting fts_errno to FTS_DNR. The bug was initially reported by Peter Benie 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. --- diff --git a/ChangeLog b/ChangeLog index bb343daa41..34b651f242 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-06-26 Pádraig Brady + + fts: handle readdir() errors + * lib/fts.c (fts_build): readdir(3) returns NULL when finished, + but also upon error when it will also set errno. Therefore + flag the error case from readdir(). We treat the case where + no items are read the same as if the dir can't be accessed, + i.e. by setting fts_errno to FTS_DNR. + 2016-06-24 Paul Eggert intprops: port better to GCC 7 diff --git a/lib/fts.c b/lib/fts.c index bcdcff9bb7..331d23bf88 100644 --- a/lib/fts.c +++ b/lib/fts.c @@ -1461,9 +1461,18 @@ fts_build (register FTS *sp, int type) while (cur->fts_dirp) { bool is_dir; size_t d_namelen; + __set_errno (0); struct dirent *dp = readdir(cur->fts_dirp); - if (dp == NULL) + if (dp == NULL) { + if (errno) { + cur->fts_errno = errno; + /* If we've not read any items yet, treat + the error as if we can't access the dir. */ + cur->fts_info = (continue_readdir || nitems) + ? FTS_ERR : FTS_DNR; + } break; + } if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -1622,7 +1631,8 @@ mem1: saved_errno = errno; /* If didn't find anything, return NULL. */ if (!nitems) { - if (type == BREAD) + if (type == BREAD + && cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) cur->fts_info = FTS_DP; fts_lfree(head); return (NULL);