}
int fds_are_same_mount(int fd1, int fd2) {
- struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
+ struct statx sx1, sx2;
+ int r;
assert(fd1 >= 0 || IN_SET(fd1, AT_FDCWD, XAT_FDROOT));
assert(fd2 >= 0 || IN_SET(fd2, AT_FDCWD, XAT_FDROOT));
- const char *fn1;
- if (fd1 == XAT_FDROOT) {
- fd1 = AT_FDCWD;
- fn1 = "/";
- } else
- fn1 = "";
-
- if (statx(fd1, fn1, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0)
- return -errno;
-
- const char *fn2;
- if (fd2 == XAT_FDROOT) {
- fd2 = AT_FDCWD;
- fn2 = "/";
- } else
- fn2 = "";
+ r = xstatx(fd1, /* path = */ NULL, AT_EMPTY_PATH,
+ STATX_TYPE|STATX_INO|STATX_MNT_ID,
+ &sx1);
+ if (r < 0)
+ return r;
- if (statx(fd2, fn2, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0)
- return -errno;
+ r = xstatx(fd2, /* path = */ NULL, AT_EMPTY_PATH,
+ STATX_TYPE|STATX_INO|STATX_MNT_ID,
+ &sx2);
+ if (r < 0)
+ return r;
return statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2);
}
assert(fd >= 0 || fd == AT_FDCWD);
assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
- if (isempty(path))
- at_flags |= AT_EMPTY_PATH;
-
/* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
* on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
* implemented on various file systems on the lower level since a while, but never was accessible). However, we
* concept is useful for determining how "old" a file really is, and hence using the older of the two makes
* most sense. */
- if (statx(fd, strempty(path),
- at_flags_normalize_nofollow(at_flags)|AT_STATX_DONT_SYNC,
- STATX_BTIME,
- &sx) >= 0 &&
- FLAGS_SET(sx.stx_mask, STATX_BTIME) && sx.stx_btime.tv_sec != 0)
+ r = xstatx_full(fd, path,
+ at_flags_normalize_nofollow(at_flags)|AT_STATX_DONT_SYNC,
+ /* mandatory_mask = */ 0,
+ STATX_BTIME,
+ /* mandatory_attributes = */ 0,
+ &sx);
+ if (r > 0 && sx.stx_btime.tv_sec != 0) /* > 0: all optional masks are supported */
a = statx_timestamp_load(&sx.stx_btime);
else
a = USEC_INFINITY;
if (r < 0 && r != -EADDRNOTAVAIL)
return log_error_errno(r, "Failed to extract filename of \"%s\": %m", path);
- if (statx(dir_fd, strempty(f),
- AT_SYMLINK_NOFOLLOW|(isempty(f) ? AT_EMPTY_PATH : 0),
- STATX_TYPE|STATX_INO, &sx) < 0)
- return log_full_errno((searching && errno == ENOENT) ||
- (unprivileged_mode && ERRNO_IS_PRIVILEGE(errno)) ? LOG_DEBUG : LOG_ERR, errno,
+ r = xstatx_full(dir_fd, f,
+ AT_SYMLINK_NOFOLLOW,
+ STATX_TYPE|STATX_INO,
+ /* optional_mask = */ 0,
+ STATX_ATTR_MOUNT_ROOT,
+ &sx);
+ if (r < 0)
+ return log_full_errno((searching && r == -ENOENT) ||
+ (unprivileged_mode && ERRNO_IS_NEG_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR, r,
"Failed to determine block device node of \"%s\": %m", path);
if (!S_ISDIR(sx.stx_mode))
return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "Path \"%s\" is not a directory", path);
- r = statx_warn_mount_root(&sx, LOG_ERR);
- if (r < 0)
- return r;
-
if (!FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
return 0;
}
- if (statx(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx) < 0)
- return log_error_errno(errno, "statx(%s) failed: %m", path);
-
- r = statx_warn_mount_root(&sx, LOG_ERR);
+ r = xstatx_full(dirfd(d), /* path = */ NULL, AT_EMPTY_PATH,
+ STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME,
+ /* optional_mask = */ 0,
+ STATX_ATTR_MOUNT_ROOT,
+ &sx);
if (r < 0)
- return r;
+ return log_error_errno(r, "statx(%s) failed: %m", path);
*ret_mountpoint = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
*ret = TAKE_PTR(d);
if (dot_or_dot_dot(de->d_name))
continue;
- /* If statx() is supported, use it. It's preferable over fstatat() since it tells us
- * explicitly where we are looking at a mount point, for free as side information. Determining
- * the same information without statx() is hard, see the complexity of path_is_mount_point(),
- * and also much slower as it requires a number of syscalls instead of just one. Hence, when
- * we have modern statx() we use it instead of fstat() and do proper mount point checks,
- * while on older kernels's well do traditional st_dev based detection of mount points.
- *
- * Using statx() for detecting mount points also has the benefit that we handle weird file
- * systems such as overlayfs better where each file is originating from a different
- * st_dev. */
-
struct statx sx;
- if (statx(dirfd(d), de->d_name,
- AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
- STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
- &sx) < 0) {
- if (errno == ENOENT)
- continue;
-
+ r = xstatx_full(dirfd(d), de->d_name,
+ AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
+ STATX_TYPE|STATX_MODE|STATX_UID,
+ STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
+ STATX_ATTR_MOUNT_ROOT,
+ &sx);
+ if (r == -ENOENT)
+ continue;
+ if (r < 0) {
/* FUSE, NFS mounts, SELinux might return EACCES */
- log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
+ log_full_errno(r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
"statx(%s/%s) failed: %m", p, de->d_name);
continue;
}
- r = statx_warn_mount_root(&sx, LOG_ERR);
- if (r < 0)
- return r;
-
if (FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
log_debug("Ignoring \"%s/%s\": different mount points.", p, de->d_name);
continue;