chiark / gitweb /
Prep v234: Apply missing upstream fixes in src/basic (1/6)
[elogind.git] / src / basic / copy.c
index 4e5f392fe59fdc8b7a74bbdb84ea482a117f916d..37212be228de1e2e9c7e0d6bc2abf89091b4e9ca 100644 (file)
@@ -67,7 +67,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
                 return -errno;
 }
 
-int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
+int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
         bool try_cfr = true, try_sendfile = true, try_splice = true;
         int r;
         size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
@@ -77,7 +77,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
 
 #if 0 /// UNNEEDED by elogind
         /* Try btrfs reflinks first. */
-        if (try_reflink &&
+        if ((copy_flags & COPY_REFLINK) &&
             max_bytes == (uint64_t) -1 &&
             lseek(fdf, 0, SEEK_CUR) == 0 &&
             lseek(fdt, 0, SEEK_CUR) == 0) {
@@ -178,7 +178,16 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
 }
 
 #if 0 /// UNNEEDED by elogind
-static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
+static int fd_copy_symlink(
+                int df,
+                const char *from,
+                const struct stat *st,
+                int dt,
+                const char *to,
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags) {
+
         _cleanup_free_ char *target = NULL;
         int r;
 
@@ -193,13 +202,25 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int
         if (symlinkat(target, dt, to) < 0)
                 return -errno;
 
-        if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
+        if (fchownat(dt, to,
+                     uid_is_valid(override_uid) ? override_uid : st->st_uid,
+                     gid_is_valid(override_gid) ? override_gid : st->st_gid,
+                     AT_SYMLINK_NOFOLLOW) < 0)
                 return -errno;
 
         return 0;
 }
 
-static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
+static int fd_copy_regular(
+                int df,
+                const char *from,
+                const struct stat *st,
+                int dt,
+                const char *to,
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags) {
+
         _cleanup_close_ int fdf = -1, fdt = -1;
         struct timespec ts[2];
         int r, q;
@@ -216,13 +237,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
         if (fdt < 0)
                 return -errno;
 
-        r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
+        r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
         if (r < 0) {
                 unlinkat(dt, to, 0);
                 return r;
         }
 
-        if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+        if (fchown(fdt,
+                   uid_is_valid(override_uid) ? override_uid : st->st_uid,
+                   gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
                 r = -errno;
 
         if (fchmod(fdt, st->st_mode & 07777) < 0)
@@ -231,7 +254,6 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
         ts[0] = st->st_atim;
         ts[1] = st->st_mtim;
         (void) futimens(fdt, ts);
-
         (void) copy_xattr(fdf, fdt);
 
         q = close(fdt);
@@ -245,7 +267,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
         return r;
 }
 
-static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
+static int fd_copy_fifo(
+                int df,
+                const char *from,
+                const struct stat *st,
+                int dt,
+                const char *to,
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags) {
         int r;
 
         assert(from);
@@ -256,7 +286,10 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt,
         if (r < 0)
                 return -errno;
 
-        if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
+        if (fchownat(dt, to,
+                     uid_is_valid(override_uid) ? override_uid : st->st_uid,
+                     gid_is_valid(override_gid) ? override_gid : st->st_gid,
+                     AT_SYMLINK_NOFOLLOW) < 0)
                 r = -errno;
 
         if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
@@ -265,7 +298,15 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt,
         return r;
 }
 
-static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
+static int fd_copy_node(
+                int df,
+                const char *from,
+                const struct stat *st,
+                int dt,
+                const char *to,
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags) {
         int r;
 
         assert(from);
@@ -276,7 +317,10 @@ static int fd_copy_node(int df, const char *from, const struct stat *st, int dt,
         if (r < 0)
                 return -errno;
 
-        if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
+        if (fchownat(dt, to,
+                     uid_is_valid(override_uid) ? override_uid : st->st_uid,
+                     gid_is_valid(override_gid) ? override_gid : st->st_gid,
+                     AT_SYMLINK_NOFOLLOW) < 0)
                 r = -errno;
 
         if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
@@ -292,7 +336,9 @@ static int fd_copy_directory(
                 int dt,
                 const char *to,
                 dev_t original_device,
-                bool merge) {
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags) {
 
         _cleanup_close_ int fdf = -1, fdt = -1;
         _cleanup_closedir_ DIR *d = NULL;
@@ -318,7 +364,7 @@ static int fd_copy_directory(
         r = mkdirat(dt, to, st->st_mode & 07777);
         if (r >= 0)
                 created = true;
-        else if (errno == EEXIST && merge)
+        else if (errno == EEXIST && (copy_flags & COPY_MERGE))
                 created = false;
         else
                 return -errno;
@@ -333,7 +379,7 @@ static int fd_copy_directory(
                 struct stat buf;
                 int q;
 
-                if (STR_IN_SET(de->d_name, ".", ".."))
+                if (dot_or_dot_dot(de->d_name))
                         continue;
 
                 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
@@ -345,19 +391,19 @@ static int fd_copy_directory(
                         continue;
 
                 if (S_ISREG(buf.st_mode))
-                        q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
+                        q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
                 else if (S_ISDIR(buf.st_mode))
-                        q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
+                        q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags);
                 else if (S_ISLNK(buf.st_mode))
-                        q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
+                        q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
                 else if (S_ISFIFO(buf.st_mode))
-                        q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
+                        q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
                 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
-                        q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
+                        q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
                 else
                         q = -EOPNOTSUPP;
 
-                if (q == -EEXIST && merge)
+                if (q == -EEXIST && (copy_flags & COPY_MERGE))
                         q = 0;
 
                 if (q < 0)
@@ -370,7 +416,9 @@ static int fd_copy_directory(
                         st->st_mtim
                 };
 
-                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+                if (fchown(fdt,
+                           uid_is_valid(override_uid) ? override_uid : st->st_uid,
+                           gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
                         r = -errno;
 
                 if (fchmod(fdt, st->st_mode & 07777) < 0)
@@ -383,7 +431,7 @@ static int fd_copy_directory(
         return r;
 }
 
-int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
+int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
         struct stat st;
 
         assert(from);
@@ -393,24 +441,24 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
                 return -errno;
 
         if (S_ISREG(st.st_mode))
-                return fd_copy_regular(fdf, from, &st, fdt, to);
+                return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
         else if (S_ISDIR(st.st_mode))
-                return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
+                return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags);
         else if (S_ISLNK(st.st_mode))
-                return fd_copy_symlink(fdf, from, &st, fdt, to);
+                return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
         else if (S_ISFIFO(st.st_mode))
-                return fd_copy_fifo(fdf, from, &st, fdt, to);
+                return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
         else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
-                return fd_copy_node(fdf, from, &st, fdt, to);
+                return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
         else
                 return -EOPNOTSUPP;
 }
 
-int copy_tree(const char *from, const char *to, bool merge) {
-        return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
+int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
+        return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags);
 }
 
-int copy_directory_fd(int dirfd, const char *to, bool merge) {
+int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
         struct stat st;
 
         assert(dirfd >= 0);
@@ -422,10 +470,10 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
 
-        return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
+        return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
 }
 
-int copy_directory(const char *from, const char *to, bool merge) {
+int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
         struct stat st;
 
         assert(from);
@@ -437,10 +485,10 @@ int copy_directory(const char *from, const char *to, bool merge) {
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
 
-        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
 }
 
-int copy_file_fd(const char *from, int fdt, bool try_reflink) {
+int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
         _cleanup_close_ int fdf = -1;
         int r;
 
@@ -451,7 +499,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         if (fdf < 0)
                 return -errno;
 
-        r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
+        r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
 
         (void) copy_times(fdf, fdt);
         (void) copy_xattr(fdf, fdt);
@@ -459,7 +507,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         return r;
 }
 
-int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
+int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
         int fdt = -1, r;
 
         assert(from);
@@ -474,7 +522,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
         if (chattr_flags != 0)
                 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
 
-        r = copy_file_fd(from, fdt, true);
+        r = copy_file_fd(from, fdt, copy_flags);
         if (r < 0) {
                 close(fdt);
                 unlink(to);
@@ -489,7 +537,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
         return 0;
 }
 
-int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
+int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
         _cleanup_free_ char *t = NULL;
         int r;
 
@@ -500,18 +548,18 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
         if (r < 0)
                 return r;
 
-        r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
+        r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags);
         if (r < 0)
                 return r;
 
-        if (replace) {
+        if (copy_flags & COPY_REPLACE) {
                 r = renameat(AT_FDCWD, t, AT_FDCWD, to);
                 if (r < 0)
                         r = -errno;
         } else
                 r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
         if (r < 0) {
-                (void) unlink_noerrno(t);
+                (void) unlink(t);
                 return r;
         }