From 427c934fdb634cde4d4426a13e7fc91d99f7db64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2021 15:57:18 +0200 Subject: [PATCH 1/4] fs-util: make sure fsync_directory_of_file() does something useful on O_PATH fds When handling O_PATH fds it's safe to use the parent of /proc/self/fd/ for any kind of inode. Hence do so. --- src/basic/fs-util.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 8f0834fe46..127f709cd9 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1378,18 +1378,39 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { } int fsync_directory_of_file(int fd) { - _cleanup_free_ char *path = NULL; _cleanup_close_ int dfd = -1; struct stat st; int r; assert(fd >= 0); - /* We only reasonably can do this for regular files and directories, hence check for that */ + /* We only reasonably can do this for regular files and directories, or for O_PATH fds, hence check + * for the inode type first */ if (fstat(fd, &st) < 0) return -errno; - if (S_ISREG(st.st_mode)) { + if (S_ISDIR(st.st_mode)) { + dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0); + if (dfd < 0) + return -errno; + + } else if (!S_ISREG(st.st_mode)) { /* Regular files are OK regardless if O_PATH or not, for all other + * types check O_PATH flag */ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; + + if (!FLAGS_SET(flags, O_PATH)) /* If O_PATH this refers to the inode in the fs, in which case + * we can sensibly do what is requested. Otherwise this refers + * to a socket, fifo or device node, where the concept of a + * containing directory doesn't make too much sense. */ + return -ENOTTY; + } + + if (dfd < 0) { + _cleanup_free_ char *path = NULL; r = fd_get_path(fd, &path); if (r < 0) { @@ -1412,13 +1433,7 @@ int fsync_directory_of_file(int fd) { dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0); if (dfd < 0) return dfd; - - } else if (S_ISDIR(st.st_mode)) { - dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0); - if (dfd < 0) - return -errno; - } else - return -ENOTTY; + } if (fsync(dfd) < 0) return -errno; From 814a7e034516b8a917c7313d9800b45c9f5193df Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Feb 2021 17:12:12 +0100 Subject: [PATCH 2/4] fs-util: add API for fsync()ing parent dir of path --- src/basic/fs-util.c | 24 ++++++++++++++++++++++++ src/basic/fs-util.h | 1 + 2 files changed, 25 insertions(+) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 127f709cd9..62c7954c84 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1484,6 +1484,30 @@ int fsync_path_at(int at_fd, const char *path) { return 0; } +int fsync_parent_at(int at_fd, const char *path) { + _cleanup_close_ int opened_fd = -1; + + if (isempty(path)) { + if (at_fd != AT_FDCWD) + return fsync_directory_of_file(at_fd); + + opened_fd = open("..", O_RDONLY|O_DIRECTORY|O_CLOEXEC); + if (opened_fd < 0) + return -errno; + + if (fsync(opened_fd) < 0) + return -errno; + + return 0; + } + + opened_fd = openat(at_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW); + if (opened_fd < 0) + return -errno; + + return fsync_directory_of_file(opened_fd); +} + int syncfs_path(int atfd, const char *path) { _cleanup_close_ int fd = -1; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 7f15b558ca..c4ab98dbb4 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -140,6 +140,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags); int fsync_directory_of_file(int fd); int fsync_full(int fd); int fsync_path_at(int at_fd, const char *path); +int fsync_parent_at(int at_fd, const char *path); int syncfs_path(int atfd, const char *path); From 32a3041656a6efefc4880f78cca3b4bd4b135f66 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 3 Feb 2021 20:53:32 +0100 Subject: [PATCH 3/4] fs-util: add fsync_path_and_parent_at() --- src/basic/fs-util.c | 16 ++++++++++++++++ src/basic/fs-util.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 62c7954c84..7d7beb13dc 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1508,6 +1508,22 @@ int fsync_parent_at(int at_fd, const char *path) { return fsync_directory_of_file(opened_fd); } +int fsync_path_and_parent_at(int at_fd, const char *path) { + _cleanup_close_ int opened_fd = -1; + + if (isempty(path)) { + if (at_fd != AT_FDCWD) + return fsync_full(at_fd); + + opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC); + } else + opened_fd = openat(at_fd, path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); + if (opened_fd < 0) + return -errno; + + return fsync_full(opened_fd); +} + int syncfs_path(int atfd, const char *path) { _cleanup_close_ int fd = -1; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index c4ab98dbb4..d612cbe404 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -141,6 +141,7 @@ int fsync_directory_of_file(int fd); int fsync_full(int fd); int fsync_path_at(int at_fd, const char *path); int fsync_parent_at(int at_fd, const char *path); +int fsync_path_and_parent_at(int at_fd, const char *path); int syncfs_path(int atfd, const char *path); From 4050625e5bf22f1a34c499c85645bf764160cde7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 3 Feb 2021 21:06:09 +0100 Subject: [PATCH 4/4] fs-util: teach syncfs_path() handle with empty path argument --- src/basic/fs-util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 7d7beb13dc..28c7247e05 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1527,9 +1527,13 @@ int fsync_path_and_parent_at(int at_fd, const char *path) { int syncfs_path(int atfd, const char *path) { _cleanup_close_ int fd = -1; - assert(path); + if (isempty(path)) { + if (atfd != AT_FDCWD) + return syncfs(atfd) < 0 ? -errno : 0; - fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK); + fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC); + } else + fd = openat(atfd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) return -errno;