diff options
author | Ganael LAPLANCHE <martymac@FreeBSD.org> | 2022-03-28 14:54:02 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2022-03-28 15:23:46 +0000 |
commit | 0cff70ca66547ca5b04030ef07e6a0b9759a0184 (patch) | |
tree | 09e87119b8af735f1c3f5640c908dd40ee020989 /lib | |
parent | 6e13794fbe6e82c21365d0fd66769bf8b19c0197 (diff) | |
download | src-0cff70ca66547ca5b04030ef07e6a0b9759a0184.tar.gz src-0cff70ca66547ca5b04030ef07e6a0b9759a0184.zip |
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
MFC after: 2 weeks
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/gen/fts-compat.c | 31 | ||||
-rw-r--r-- | lib/libc/gen/fts-compat11.c | 32 | ||||
-rw-r--r-- | 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); } |