aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGanael LAPLANCHE <martymac@FreeBSD.org>2022-03-28 14:54:02 +0000
committerMark Johnston <markj@FreeBSD.org>2022-03-28 15:23:46 +0000
commit0cff70ca66547ca5b04030ef07e6a0b9759a0184 (patch)
tree09e87119b8af735f1c3f5640c908dd40ee020989 /lib
parent6e13794fbe6e82c21365d0fd66769bf8b19c0197 (diff)
downloadsrc-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.c31
-rw-r--r--lib/libc/gen/fts-compat11.c32
-rw-r--r--lib/libc/gen/fts.c33
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);
}