chiark / gitweb /
copy: try top copy atime/time/xattrs when copying files
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Dec 2014 16:00:39 +0000 (17:00 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 26 Dec 2014 18:21:58 +0000 (19:21 +0100)
src/shared/copy.c
src/shared/copy.h

index 0c2cdc8d9490793d94730904621eae0ad412736f..92f6e1e114329738b852ba7abde0cfb28681a529 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <sys/sendfile.h>
+#include <sys/xattr.h>
 
 #include "util.h"
 #include "btrfs-util.h"
@@ -145,6 +146,9 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
         if (fchmod(fdt, st->st_mode & 07777) < 0)
                 r = -errno;
 
+        (void) copy_times(fdf, fdt);
+        (void) copy_xattr(fdf, fdt);
+
         q = close(fdt);
         fdt = -1;
 
@@ -244,6 +248,9 @@ static int fd_copy_directory(
 
                 if (fchmod(fdt, st->st_mode & 07777) < 0)
                         r = -errno;
+
+                (void) copy_times(fdf, fdt);
+                (void) copy_xattr(fdf, fdt);
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -326,6 +333,7 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
 
 int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         _cleanup_close_ int fdf = -1;
+        int r;
 
         assert(from);
         assert(fdt >= 0);
@@ -334,7 +342,12 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         if (fdf < 0)
                 return -errno;
 
-        return copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+        r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+
+        (void) copy_times(fdf, fdt);
+        (void) copy_xattr(fdf, fdt);
+
+        return r;
 }
 
 int copy_file(const char *from, const char *to, int flags, mode_t mode) {
@@ -361,3 +374,91 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) {
 
         return 0;
 }
+
+int copy_times(int fdf, int fdt) {
+        struct timespec ut[2];
+        struct stat st;
+        usec_t crtime;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        if (fstat(fdf, &st) < 0)
+                return -errno;
+
+        ut[0] = st.st_atim;
+        ut[1] = st.st_mtim;
+
+        if (futimens(fdt, ut) < 0)
+                return -errno;
+
+        if (fd_getcrtime(fdf, &crtime) >= 0)
+                (void) fd_setcrtime(fdt, crtime);
+
+        return 0;
+}
+
+int copy_xattr(int fdf, int fdt) {
+        _cleanup_free_ char *bufa = NULL, *bufb = NULL;
+        size_t sza = 100, szb = 100;
+        ssize_t n;
+        int ret = 0;
+        const char *p;
+
+        for (;;) {
+                bufa = malloc(sza);
+                if (!bufa)
+                        return -ENOMEM;
+
+                n = flistxattr(fdf, bufa, sza);
+                if (n == 0)
+                        return 0;
+                if (n > 0)
+                        break;
+                if (errno != ERANGE)
+                        return -errno;
+
+                sza *= 2;
+
+                free(bufa);
+                bufa = NULL;
+        }
+
+        p = bufa;
+        while (n > 0) {
+                size_t l;
+
+                l = strlen(p);
+                assert(l < (size_t) n);
+
+                if (startswith(p, "user.")) {
+                        ssize_t m;
+
+                        if (!bufb) {
+                                bufb = malloc(szb);
+                                if (!bufb)
+                                        return -ENOMEM;
+                        }
+
+                        m = fgetxattr(fdf, p, bufb, szb);
+                        if (m < 0) {
+                                if (errno == ERANGE) {
+                                        szb *= 2;
+                                        free(bufb);
+                                        bufb = NULL;
+                                        continue;
+                                }
+
+                                return -errno;
+                        }
+
+                        if (fsetxattr(fdt, p, bufb, m, 0) < 0)
+                                ret = -errno;
+                }
+
+                p += l + 1;
+                n -= l + 1;
+        }
+
+        return ret;
+}
index 714addf4cbb134bfd0da5034173c7a2c46f698d6..6d725ef26df1297a0ed73870c09ac136cad92328 100644 (file)
@@ -30,3 +30,5 @@ int copy_tree(const char *from, const char *to, bool merge);
 int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
 int copy_directory_fd(int dirfd, const char *to, bool merge);
 int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink);
+int copy_times(int fdf, int fdt);
+int copy_xattr(int fdf, int fdt);