From 49a0931f625127a7cdbb02b6a9119119a2f7e1a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Oct 2021 22:58:43 +0200 Subject: [PATCH] dirent-util: tweak readdir_ensure_type() a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we ignored if readdir_ensure_type() failed, the .d_type would then still possibly report DT_UNKNOWN, possibly confusing the caller. Let's make this safer: if we get an error on readdir_ensure_type() then report it — except if it is ENOENT which indicates the dirent vanished by now, which is not a problem and we should just skip to the next entry. --- src/basic/dirent-util.c | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index ee2aff0f4d..d578e6836d 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -66,24 +66,40 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { } struct dirent *readdir_ensure_type(DIR *d) { - struct dirent *de; + int r; assert(d); - errno = 0; - de = readdir(d); - if (de) - (void) dirent_ensure_type(d, de); - return de; -} - -struct dirent *readdir_no_dot(DIR *dirp) { - struct dirent *d; + /* Like readdir(), but fills in .d_type if it is DT_UNKNOWN */ for (;;) { - d = readdir_ensure_type(dirp); - if (d && dot_or_dot_dot(d->d_name)) - continue; - return d; + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de) + return NULL; + + r = dirent_ensure_type(d, de); + if (r >= 0) + return de; + if (r != -ENOENT) { + errno = -r; /* We want to be compatible with readdir(), hence propagate error via errno here */ + return NULL; + } + + /* Vanished by now? Then skip immedately to next */ + } +} + +struct dirent *readdir_no_dot(DIR *d) { + assert(d); + + for (;;) { + struct dirent *de; + + de = readdir_ensure_type(d); + if (!de || !dot_or_dot_dot(de->d_name)) + return de; } }