git: e66bbe6e02b4 - stable/13 - libc: Check for readdir(2) errors in fts(3)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 11 Apr 2022 13:44:04 UTC
The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=e66bbe6e02b48d1fa57c52321a517dcf42d8eb69 commit e66bbe6e02b48d1fa57c52321a517dcf42d8eb69 Author: Ganael LAPLANCHE <martymac@FreeBSD.org> AuthorDate: 2022-03-28 14:54:02 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2022-04-11 13:43:28 +0000 libc: Check for readdir(2) errors in fts(3) Previously, such errors were not distinguished from the end-of-directory condition. With improvements from Mahmoud Abumandour <ma.mandourr@gmail.com>. Reviewed by: markj PR: 262038 (cherry picked from commit 0cff70ca66547ca5b04030ef07e6a0b9759a0184) --- lib/libc/gen/fts-compat.c | 31 ++++++++++++++++++++++++++++--- lib/libc/gen/fts-compat11.c | 32 +++++++++++++++++++++++++++++--- lib/libc/gen/fts.c | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c index ccdd4f15905b..9f295110f1c7 100644 --- a/lib/libc/gen/fts-compat.c +++ b/lib/libc/gen/fts-compat.c @@ -610,6 +610,19 @@ __fts_set_clientptr_44bsd(FTS *sp, void *clientptr) sp->fts_clientptr = clientptr; } +static struct freebsd11_dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct freebsd11_dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = freebsd11_readdir(dirp); + *readdir_errno = errno; + return (ret); +} + /* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children @@ -634,7 +647,7 @@ fts_build(FTS *sp, int type) DIR *dirp; void *oldaddr; int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno, - nostat, doadjust, dnamlen; + nostat, doadjust, dnamlen, readdir_errno; char *cp; /* Set current node pointer. */ @@ -738,8 +751,9 @@ fts_build(FTS *sp, int type) /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; + readdir_errno = 0; for (head = tail = NULL, nitems = 0; - dirp && (dp = freebsd11_readdir(dirp));) { + (dp = fts_safe_readdir(dirp, &readdir_errno));) { dnamlen = dp->d_namlen; if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -839,6 +853,16 @@ mem1: saved_errno = errno; } ++nitems; } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + if (dirp) (void)closedir(dirp); @@ -877,7 +901,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; return (NULL); } diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c index 288351d2008b..a18ce3f00a6a 100644 --- a/lib/libc/gen/fts-compat11.c +++ b/lib/libc/gen/fts-compat11.c @@ -607,6 +607,19 @@ freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr) sp->fts_clientptr = clientptr; } +static struct freebsd11_dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct freebsd11_dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = freebsd11_readdir(dirp); + *readdir_errno = errno; + return (ret); +} + /* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children @@ -630,7 +643,8 @@ fts_build(FTS11 *sp, int type) DIR *dirp; void *oldaddr; char *cp; - int cderrno, descend, oflag, saved_errno, nostat, doadjust; + int cderrno, descend, oflag, saved_errno, nostat, doadjust, + readdir_errno; long level; long nlinks; /* has to be signed because -1 is a magic value */ size_t dnamlen, len, maxlen, nitems; @@ -736,8 +750,9 @@ fts_build(FTS11 *sp, int type) /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; + readdir_errno = 0; for (head = tail = NULL, nitems = 0; - dirp && (dp = freebsd11_readdir(dirp));) { + (dp = fts_safe_readdir(dirp, &readdir_errno));) { dnamlen = dp->d_namlen; if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -823,6 +838,16 @@ mem1: saved_errno = errno; } ++nitems; } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + if (dirp) (void)closedir(dirp); @@ -859,7 +884,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; return (NULL); } diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index d0705e123775..5186ae047a3b 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -604,6 +604,19 @@ fts_set_clientptr(FTS *sp, void *clientptr) sp->fts_clientptr = clientptr; } +static struct dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = readdir(dirp); + *readdir_errno = errno; + return (ret); +} + /* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children @@ -627,7 +640,8 @@ fts_build(FTS *sp, int type) DIR *dirp; void *oldaddr; char *cp; - int cderrno, descend, oflag, saved_errno, nostat, doadjust; + int cderrno, descend, oflag, saved_errno, nostat, doadjust, + readdir_errno; long level; long nlinks; /* has to be signed because -1 is a magic value */ size_t dnamlen, len, maxlen, nitems; @@ -733,7 +747,9 @@ fts_build(FTS *sp, int type) /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; - for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { + readdir_errno = 0; + for (head = tail = NULL, nitems = 0; + (dp = fts_safe_readdir(dirp, &readdir_errno));) { dnamlen = dp->d_namlen; if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -819,6 +835,16 @@ mem1: saved_errno = errno; } ++nitems; } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + if (dirp) (void)closedir(dirp); @@ -855,7 +881,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; return (NULL); }