From: Lennart Poettering Date: Thu, 7 Oct 2021 20:58:43 +0000 (+0200) Subject: dirent-util: tweak readdir_ensure_type() a bit X-Git-Tag: v250-rc1~547^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=49a0931f625127a7cdbb02b6a9119119a2f7e1a7;p=thirdparty%2Fsystemd.git dirent-util: tweak readdir_ensure_type() a bit 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. --- diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index ee2aff0f4d0..d578e6836d6 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; + /* Like readdir(), but fills in .d_type if it is DT_UNKNOWN */ + + for (;;) { + 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 *dirp) { - struct dirent *d; +struct dirent *readdir_no_dot(DIR *d) { + assert(d); for (;;) { - d = readdir_ensure_type(dirp); - if (d && dot_or_dot_dot(d->d_name)) - continue; - return d; + struct dirent *de; + + de = readdir_ensure_type(d); + if (!de || !dot_or_dot_dot(de->d_name)) + return de; } }