summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-10-08 11:14:03 +0200
committerGitHub <noreply@github.com>2021-10-08 11:14:03 +0200
commitc17e8ce9ecc46e3dc9774a131f1bb0afeddb2000 (patch)
treef3a6b65a035378c77aa434c8637562ede2dd44a1
parentdissect: print more useful error messages for two more error cases (diff)
parentdirent-util: tweak readdir_ensure_type() a bit (diff)
downloadsystemd-c17e8ce9ecc46e3dc9774a131f1bb0afeddb2000.tar.xz
systemd-c17e8ce9ecc46e3dc9774a131f1bb0afeddb2000.zip
Merge pull request #20962 from poettering/dttoif
Some tweaks to dirent-util.c
-rw-r--r--src/basic/dirent-util.c69
-rw-r--r--src/basic/dirent-util.h2
-rw-r--r--src/basic/recurse-dir.c2
3 files changed, 42 insertions, 31 deletions
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
index a70871b33d..d578e6836d 100644
--- a/src/basic/dirent-util.c
+++ b/src/basic/dirent-util.c
@@ -5,22 +5,12 @@
#include "dirent-util.h"
#include "path-util.h"
+#include "stat-util.h"
#include "string-util.h"
-int stat_mode_to_dirent_type(mode_t mode) {
- return
- S_ISREG(mode) ? DT_REG :
- S_ISDIR(mode) ? DT_DIR :
- S_ISLNK(mode) ? DT_LNK :
- S_ISFIFO(mode) ? DT_FIFO :
- S_ISSOCK(mode) ? DT_SOCK :
- S_ISCHR(mode) ? DT_CHR :
- S_ISBLK(mode) ? DT_BLK :
- DT_UNKNOWN;
-}
-
static int dirent_ensure_type(DIR *d, struct dirent *de) {
- struct stat st;
+ STRUCT_STATX_DEFINE(sx);
+ int r;
assert(d);
assert(de);
@@ -33,10 +23,17 @@ static int dirent_ensure_type(DIR *d, struct dirent *de) {
return 0;
}
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
- return -errno;
+ /* Let's ask only for the type, nothing else. */
+ r = statx_fallback(dirfd(d), de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx);
+ if (r < 0)
+ return r;
- de->d_type = stat_mode_to_dirent_type(st.st_mode);
+ assert(FLAGS_SET(sx.stx_mask, STATX_TYPE));
+ de->d_type = IFTODT(sx.stx_mode);
+
+ /* If the inode is passed too, update the field, i.e. report most recent data */
+ if (FLAGS_SET(sx.stx_mask, STATX_INO))
+ de->d_ino = sx.stx_ino;
return 0;
}
@@ -69,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;
}
}
diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h
index 5bbd54df5a..c7956e7c1b 100644
--- a/src/basic/dirent-util.h
+++ b/src/basic/dirent-util.h
@@ -8,8 +8,6 @@
#include "macro.h"
#include "path-util.h"
-int stat_mode_to_dirent_type(mode_t mode);
-
bool dirent_is_file(const struct dirent *de) _pure_;
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c
index fe34ffbfd4..2aabbccadb 100644
--- a/src/basic/recurse-dir.c
+++ b/src/basic/recurse-dir.c
@@ -290,7 +290,7 @@ int recurse_dir(
/* Copy over the data we acquired through statx() if we acquired any */
if (sx.stx_mask & STATX_TYPE) {
assert(!!subdir == !!S_ISDIR(sx.stx_mode));
- de[i]->d_type = stat_mode_to_dirent_type(sx.stx_mode);
+ de[i]->d_type = IFTODT(sx.stx_mode);
}
if (sx.stx_mask & STATX_INO)