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;