Merge pull request #16928 from poettering/statx-fallback
stat-util: provide single statx() fallback on top of fstatat()
This commit is contained in:
@@ -49,6 +49,16 @@ struct statx STATX_DEFINITION;
|
||||
* defines an older definition */
|
||||
struct new_statx STATX_DEFINITION;
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_SYNC_AS_STAT
|
||||
#define AT_STATX_SYNC_AS_STAT 0x0000
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_FORCE_SYNC
|
||||
#define AT_STATX_FORCE_SYNC 0x2000
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_DONT_SYNC
|
||||
#define AT_STATX_DONT_SYNC 0x4000
|
||||
@@ -64,11 +74,21 @@ struct new_statx STATX_DEFINITION;
|
||||
#define STATX_MODE 0x00000002U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_NLINK
|
||||
#define STATX_NLINK 0x00000004U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_UID
|
||||
#define STATX_UID 0x00000008U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_GID
|
||||
#define STATX_GID 0x00000010U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_ATIME
|
||||
#define STATX_ATIME 0x00000020U
|
||||
@@ -89,6 +109,16 @@ struct new_statx STATX_DEFINITION;
|
||||
#define STATX_INO 0x00000100U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_SIZE
|
||||
#define STATX_SIZE 0x00000200U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_BLOCKS
|
||||
#define STATX_BLOCKS 0x00000400U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_BTIME
|
||||
#define STATX_BTIME 0x00000800U
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@@ -135,13 +136,8 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
|
||||
_cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
|
||||
int mount_id = -1, mount_id_parent = -1;
|
||||
bool nosupp = false, check_st_dev = true;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
struct stat a, b;
|
||||
struct statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
@@ -298,15 +294,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
|
||||
}
|
||||
|
||||
int path_get_mnt_id(const char *path, int *ret) {
|
||||
union {
|
||||
struct statx sx;
|
||||
struct new_statx nsx;
|
||||
} buf
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
STRUCT_NEW_STATX_DEFINE(buf);
|
||||
int r;
|
||||
|
||||
if (statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_MNT_ID, &buf.sx) < 0) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "macro.h"
|
||||
#include "missing_fs.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
@@ -413,3 +414,59 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
|
||||
a->st_ino == b->st_ino &&
|
||||
(!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
|
||||
}
|
||||
|
||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
|
||||
static bool avoid_statx = false;
|
||||
struct stat st;
|
||||
|
||||
if (!avoid_statx) {
|
||||
if (statx(dfd, path, flags, mask, sx) < 0) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM)
|
||||
return -errno;
|
||||
|
||||
/* If statx() is not supported or if we see EPERM (which might indicate seccomp
|
||||
* filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
|
||||
* since that is likely an indication of fs access issues, which we should
|
||||
* propagate */
|
||||
} else
|
||||
return 0;
|
||||
|
||||
avoid_statx = true;
|
||||
}
|
||||
|
||||
/* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
|
||||
* OK to ignore */
|
||||
if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW|
|
||||
AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
return -errno;
|
||||
|
||||
*sx = (struct statx) {
|
||||
.stx_mask = STATX_TYPE|STATX_MODE|
|
||||
STATX_NLINK|STATX_UID|STATX_GID|
|
||||
STATX_ATIME|STATX_MTIME|STATX_CTIME|
|
||||
STATX_INO|STATX_SIZE|STATX_BLOCKS,
|
||||
.stx_blksize = st.st_blksize,
|
||||
.stx_nlink = st.st_nlink,
|
||||
.stx_uid = st.st_uid,
|
||||
.stx_gid = st.st_gid,
|
||||
.stx_mode = st.st_mode,
|
||||
.stx_ino = st.st_ino,
|
||||
.stx_size = st.st_size,
|
||||
.stx_blocks = st.st_blocks,
|
||||
.stx_rdev_major = major(st.st_rdev),
|
||||
.stx_rdev_minor = minor(st.st_rdev),
|
||||
.stx_dev_major = major(st.st_dev),
|
||||
.stx_dev_minor = minor(st.st_dev),
|
||||
.stx_atime.tv_sec = st.st_atim.tv_sec,
|
||||
.stx_atime.tv_nsec = st.st_atim.tv_nsec,
|
||||
.stx_mtime.tv_sec = st.st_mtim.tv_sec,
|
||||
.stx_mtime.tv_nsec = st.st_mtim.tv_nsec,
|
||||
.stx_ctime.tv_sec = st.st_ctim.tv_sec,
|
||||
.stx_ctime.tv_nsec = st.st_ctim.tv_nsec,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing_stat.h"
|
||||
|
||||
int is_symlink(const char *path);
|
||||
int is_dir(const char *path, bool follow);
|
||||
@@ -91,3 +92,24 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
|
||||
int proc_mounted(void);
|
||||
|
||||
bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
|
||||
|
||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
|
||||
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
# define STRUCT_STATX_DEFINE(var) \
|
||||
struct statx var = {}
|
||||
# define STRUCT_NEW_STATX_DEFINE(var) \
|
||||
union { \
|
||||
struct statx sx; \
|
||||
struct new_statx nsx; \
|
||||
} var = {}
|
||||
#else
|
||||
# define STRUCT_STATX_DEFINE(var) \
|
||||
struct statx var
|
||||
# define STRUCT_NEW_STATX_DEFINE(var) \
|
||||
union { \
|
||||
struct statx sx; \
|
||||
struct new_statx nsx; \
|
||||
} var
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
@@ -154,12 +155,7 @@ static int parse_crtime(le64_t le, usec_t *usec) {
|
||||
}
|
||||
|
||||
int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
|
||||
struct_statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
usec_t a, b;
|
||||
le64_t le;
|
||||
size_t n;
|
||||
|
||||
Reference in New Issue
Block a user