This is a follow-up for
945a8210c770801c8492eda03b6e9af3ec5d03a3 and
makes the st_dev check generic, so that we can reuse it some other
places. It also incorporates the non-NULL check now, to be a
comprehensive one-stop solution.
The helper is static inline so that compilers can optimize the redundant
checks away in case it is combined with other checks.
/* Returns if the specified stat structure references the same (though possibly modified) inode. Does
* a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
- return a && b &&
- a->st_dev != 0 && /* is the structure ever initialized? */
+ return stat_is_set(a) && stat_is_set(b) &&
((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
a->st_dev == b->st_dev &&
a->st_ino == b->st_ino;
/* Same as stat_inode_same() but for struct statx */
- return a && b &&
+ return statx_is_set(a) && statx_is_set(b) &&
FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) &&
((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 &&
a->stx_dev_major == b->stx_dev_major &&
}
bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) {
- if (!a || !b)
+ if (!new_statx_is_set(a) || !new_statx_is_set(b))
return false;
/* if we have the mount ID, that's all we need */
#include <sys/types.h>
#include <sys/vfs.h>
+#include "fs-util.h"
#include "macro.h"
#include "missing_stat.h"
#include "siphash24.h"
const char* inode_type_to_string(mode_t m);
mode_t inode_type_from_string(const char *s);
+
+/* Macros that check whether the stat/statx structures have been initialized already. For "struct stat" we
+ * use a check for .st_dev being non-zero, since the kernel unconditionally fills that in, mapping the file
+ * to its originating superblock, regardless if the fs is block based or virtual (we also check for .st_mode
+ * being MODE_INVALID, since we use that as an invalid marker for separate mode_t fields). For "struct statx"
+ * we use the .stx_mask field, which must be non-zero if any of the fields have already been initialized. */
+static inline bool stat_is_set(const struct stat *st) {
+ return st && st->st_dev != 0 && st->st_mode != MODE_INVALID;
+}
+static inline bool statx_is_set(const struct statx *sx) {
+ return sx && sx->stx_mask != 0;
+}
+static inline bool new_statx_is_set(const struct new_statx *sx) {
+ return sx && sx->stx_mask != 0;
+}
m->etc_hosts_last = ts;
- if (m->etc_hosts_stat.st_mode != 0) {
+ if (stat_is_set(&m->etc_hosts_stat)) {
if (stat("/etc/hosts", &st) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to stat /etc/hosts: %m");