]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/fs-util.c
fs-util: add fsync_full() helper
[thirdparty/systemd.git] / src / basic / fs-util.c
index 7dfc1b309d9717aefb44996732db47d0b6006c49..f929db9c23006e27212bc657eb474bd020b94bf1 100644 (file)
@@ -226,7 +226,6 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
 }
 
 int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
-        char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
         bool do_chown, do_chmod;
         struct stat st;
 
@@ -236,11 +235,9 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
          * unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does
          * on chown().
          *
-         * This call is happy with O_PATH fds, since we always go via /proc/self/fd/ to change
-         * ownership/access mode. */
+         * This call is happy with O_PATH fds. */
 
-        xsprintf(fd_path, "/proc/self/fd/%i", fd);
-        if (stat(fd_path, &st) < 0)
+        if (fstat(fd, &st) < 0)
                 return -errno;
 
         do_chown =
@@ -262,16 +259,16 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
                 mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
 
                 if (((minimal ^ st.st_mode) & 07777) != 0)
-                        if (chmod(fd_path, minimal & 07777) < 0)
+                        if (fchmod_opath(fd, minimal & 07777) < 0)
                                 return -errno;
         }
 
         if (do_chown)
-                if (chown(fd_path, uid, gid) < 0)
+                if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
                         return -errno;
 
         if (do_chmod)
-                if (chmod(fd_path, mode & 07777) < 0)
+                if (fchmod_opath(fd, mode & 07777) < 0)
                         return -errno;
 
         return do_chown || do_chmod;
@@ -983,9 +980,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
 
                                 /* Prefix what's left to do with what we just read, and start the loop again, but
                                  * remain in the current directory. */
-                                joined = strjoin(destination, todo);
+                                joined = path_join(destination, todo);
                         } else
-                                joined = strjoin("/", destination, todo);
+                                joined = path_join("/", destination, todo);
                         if (!joined)
                                 return -ENOMEM;
 
@@ -1301,6 +1298,17 @@ int fsync_directory_of_file(int fd) {
         return 0;
 }
 
+int fsync_full(int fd) {
+        int r, q;
+
+        /* Sync both the file and the directory */
+
+        r = fsync(fd) < 0 ? -errno : 0;
+        q = fsync_directory_of_file(fd);
+
+        return r < 0 ? r : q;
+}
+
 int fsync_path_at(int at_fd, const char *path) {
         _cleanup_close_ int opened_fd = -1;
         int fd;