]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dirent-util: tweak readdir_ensure_type() a bit 20962/head
authorLennart Poettering <lennart@poettering.net>
Thu, 7 Oct 2021 20:58:43 +0000 (22:58 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 7 Oct 2021 21:13:40 +0000 (23:13 +0200)
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

index ee2aff0f4d0bae3f06f1087932edc1280121c5e1..d578e6836d60c3d1c0a897c9dce14ef4f012f6dd 100644 (file)
@@ -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;
         }
 }