]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fs-util: allow fsync_directory_of_file() on directories too
authorLennart Poettering <lennart@poettering.net>
Wed, 3 Feb 2021 19:40:40 +0000 (20:40 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 3 Mar 2021 17:31:20 +0000 (18:31 +0100)
(in which case the parent dir is synced)

src/basic/fs-util.c

index 3a3daa9a05d8288c829807b27c039b2d4643b65a..9423b9bf7ac0e7582c647bf3b7919dfb050070d2 100644 (file)
@@ -1413,33 +1413,45 @@ 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;
 
-        r = fd_verify_regular(fd);
-        if (r < 0)
-                return r;
+        assert(fd >= 0);
 
-        r = fd_get_path(fd, &path);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
-                                fd,
-                                r == -ENOSYS ? ", ignoring" : "");
+        /* We only reasonably can do this for regular files and directories, hence check for that */
+        if (fstat(fd, &st) < 0)
+                return -errno;
 
-                if (r == -ENOSYS)
-                        /* If /proc is not available, we're most likely running in some
-                         * chroot environment, and syncing the directory is not very
-                         * important in that case. Let's just silently do nothing. */
-                        return 0;
+        if (S_ISREG(st.st_mode)) {
 
-                return r;
-        }
+                r = fd_get_path(fd, &path);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
+                                        fd,
+                                        r == -ENOSYS ? ", ignoring" : "");
 
-        if (!path_is_absolute(path))
-                return -EINVAL;
+                        if (r == -ENOSYS)
+                                /* If /proc is not available, we're most likely running in some
+                                 * chroot environment, and syncing the directory is not very
+                                 * important in that case. Let's just silently do nothing. */
+                                return 0;
+
+                        return r;
+                }
 
-        dfd = open_parent(path, O_CLOEXEC, 0);
-        if (dfd < 0)
-                return dfd;
+                if (!path_is_absolute(path))
+                        return -EINVAL;
+
+                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;