summaryrefslogtreecommitdiffstats
path: root/src/basic/dirent-util.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
commit55944e5e40b1be2afc4855d8d2baf4b73d1876b5 (patch)
tree33f869f55a1b149e9b7c2b7e201867ca5dd52992 /src/basic/dirent-util.h
parentInitial commit. (diff)
downloadsystemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.tar.xz
systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.zip
Adding upstream version 255.4.upstream/255.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/basic/dirent-util.h')
-rw-r--r--src/basic/dirent-util.h64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h
new file mode 100644
index 0000000..0a2fcbf
--- /dev/null
+++ b/src/basic/dirent-util.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "macro.h"
+#include "path-util.h"
+
+bool dirent_is_file(const struct dirent *de) _pure_;
+bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
+int dirent_ensure_type(int dir_fd, struct dirent *de);
+
+struct dirent *readdir_ensure_type(DIR *d);
+struct dirent *readdir_no_dot(DIR *dirp);
+
+#define FOREACH_DIRENT_ALL(de, d, on_error) \
+ for (struct dirent *(de) = readdir_ensure_type(d);; (de) = readdir_ensure_type(d)) \
+ if (!de) { \
+ if (errno > 0) { \
+ on_error; \
+ } \
+ break; \
+ } else
+
+#define FOREACH_DIRENT(de, d, on_error) \
+ FOREACH_DIRENT_ALL(de, d, on_error) \
+ if (hidden_or_backup_file((de)->d_name)) \
+ continue; \
+ else
+
+/* Maximum space one dirent structure might require at most */
+#define DIRENT_SIZE_MAX CONST_MAX(sizeof(struct dirent), offsetof(struct dirent, d_name) + NAME_MAX + 1)
+
+/* Only if 64-bit off_t is enabled struct dirent + struct dirent64 are actually the same. We require this, and
+ * we want them to be interchangeable to make getdents64() work, hence verify that. */
+assert_cc(_FILE_OFFSET_BITS == 64);
+/* These asserts would fail on musl where the LFS extensions don't exist. They should
+ * always be present on glibc however. */
+#if HAVE_STRUCT_DIRENT64
+assert_cc(sizeof(struct dirent) == sizeof(struct dirent64));
+assert_cc(offsetof(struct dirent, d_ino) == offsetof(struct dirent64, d_ino));
+assert_cc(sizeof_field(struct dirent, d_ino) == sizeof_field(struct dirent64, d_ino));
+assert_cc(offsetof(struct dirent, d_off) == offsetof(struct dirent64, d_off));
+assert_cc(sizeof_field(struct dirent, d_off) == sizeof_field(struct dirent64, d_off));
+assert_cc(offsetof(struct dirent, d_reclen) == offsetof(struct dirent64, d_reclen));
+assert_cc(sizeof_field(struct dirent, d_reclen) == sizeof_field(struct dirent64, d_reclen));
+assert_cc(offsetof(struct dirent, d_type) == offsetof(struct dirent64, d_type));
+assert_cc(sizeof_field(struct dirent, d_type) == sizeof_field(struct dirent64, d_type));
+assert_cc(offsetof(struct dirent, d_name) == offsetof(struct dirent64, d_name));
+assert_cc(sizeof_field(struct dirent, d_name) == sizeof_field(struct dirent64, d_name));
+#endif
+
+#define FOREACH_DIRENT_IN_BUFFER(de, buf, sz) \
+ for (void *_end = (uint8_t*) ({ (de) = (buf); }) + (sz); \
+ (uint8_t*) (de) < (uint8_t*) _end; \
+ (de) = (struct dirent*) ((uint8_t*) (de) + (de)->d_reclen))
+
+#define DEFINE_DIRENT_BUFFER(name, sz) \
+ union { \
+ struct dirent de; \
+ uint8_t data[(sz) * DIRENT_SIZE_MAX]; \
+ } name