From: Lennart Poettering Date: Mon, 8 Dec 2025 12:32:42 +0000 (+0100) Subject: stat-util: write up XAT_FDROOT in stat-util.[ch] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95abe4beff08636681069623ffdf16cfa34c7cf8;p=thirdparty%2Fsystemd.git stat-util: write up XAT_FDROOT in stat-util.[ch] --- diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index bb20ba50dee..d1c5d7aa37b 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -31,10 +31,25 @@ static int verify_stat_at( struct stat st; int r; - assert(fd >= 0 || fd == AT_FDCWD); + assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT)); assert(!isempty(path) || !follow); assert(verify_func); + _cleanup_free_ char *p = NULL; + if (fd == XAT_FDROOT) { + fd = AT_FDCWD; + + if (isempty(path)) + path = "/"; + else if (!path_is_absolute(path)) { + p = strjoin("/", path); + if (!p) + return -ENOMEM; + + path = p; + } + } + if (fstatat(fd, strempty(path), &st, (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0) return -errno; @@ -66,8 +81,10 @@ int verify_regular_at(int fd, const char *path, bool follow) { } int fd_verify_regular(int fd) { - assert(fd >= 0); - return verify_regular_at(fd, NULL, false); + if (IN_SET(fd, AT_FDCWD, XAT_FDROOT)) + return -EISDIR; + + return verify_regular_at(fd, /* path= */ NULL, /* follow= */ false); } int stat_verify_directory(const struct stat *st) { @@ -83,7 +100,9 @@ int stat_verify_directory(const struct stat *st) { } int fd_verify_directory(int fd) { - assert(fd >= 0); + if (IN_SET(fd, AT_FDCWD, XAT_FDROOT)) + return 0; + return verify_stat_at(fd, NULL, false, stat_verify_directory, true); } @@ -127,7 +146,10 @@ int stat_verify_linked(const struct stat *st) { } int fd_verify_linked(int fd) { - assert(fd >= 0); + + if (fd == XAT_FDROOT) + return 0; + return verify_stat_at(fd, NULL, false, stat_verify_linked, true); } @@ -223,23 +245,33 @@ int null_or_empty_path_with_root(const char *fn, const char *root) { return null_or_empty(&st); } -int fd_is_read_only_fs(int fd) { - struct statfs st; +static int xfstatfs(int fd, struct statfs *ret) { + assert(ret); + + if (fd == AT_FDCWD) + return RET_NERRNO(statfs(".", ret)); + if (fd == XAT_FDROOT) + return RET_NERRNO(statfs("/", ret)); assert(fd >= 0); + return RET_NERRNO(fstatfs(fd, ret)); +} - if (fstatfs(fd, &st) < 0) - return -errno; +int fd_is_read_only_fs(int fd) { + int r; + + struct statfs st; + r = xfstatfs(fd, &st); + if (r < 0) + return r; if (st.f_flags & ST_RDONLY) return true; - if (is_network_fs(&st)) { + if (is_network_fs(&st)) /* On NFS, fstatfs() might not reflect whether we can actually write to the remote share. * Let's try again with access(W_OK) which is more reliable, at least sometimes. */ - if (access_fd(fd, W_OK) == -EROFS) - return true; - } + return access_fd(fd, W_OK) == -EROFS; return false; } @@ -364,9 +396,9 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { } int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) { - struct statfs s; int r; + struct statfs s; r = xstatfsat(dir_fd, path, &s); if (r < 0) return r; @@ -383,19 +415,23 @@ bool is_network_fs(const struct statfs *s) { } int fd_is_temporary_fs(int fd) { - struct statfs s; + int r; - if (fstatfs(fd, &s) < 0) - return -errno; + struct statfs s; + r = xfstatfs(fd, &s); + if (r < 0) + return r; return is_temporary_fs(&s); } int fd_is_network_fs(int fd) { - struct statfs s; + int r; - if (fstatfs(fd, &s) < 0) - return -errno; + struct statfs s; + r = xfstatfs(fd, &s); + if (r < 0) + return r; return is_network_fs(&s); } @@ -489,7 +525,7 @@ bool statx_mount_same(const struct statx *a, const struct statx *b) { int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { _cleanup_close_ int fd = -EBADF; - assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT)); assert(ret); if (!isempty(path)) { @@ -499,7 +535,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { dir_fd = fd; } - return RET_NERRNO(fstatfs(dir_fd, ret)); + return RET_NERRNO(xfstatfs(dir_fd, ret)); } usec_t statx_timestamp_load(const struct statx_timestamp *ts) {