copy: Add a COPY_MERGE_EMPTY flag to merge only if the target is empty
authorRyan Gonzalez <rymg19@gmail.com>
Mon, 7 Jan 2019 00:01:59 +0000 (18:01 -0600)
committerRyan Gonzalez <rymg19@gmail.com>
Tue, 8 Jan 2019 20:30:09 +0000 (14:30 -0600)
src/basic/copy.c
src/basic/copy.h

index 34e01ea..46e02a3 100644 (file)
@@ -24,6 +24,7 @@
 #include "macro.h"
 #include "missing.h"
 #include "mountpoint-util.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
@@ -501,7 +502,7 @@ static int fd_copy_directory(
         _cleanup_close_ int fdf = -1, fdt = -1;
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
-        bool created;
+        bool exists, created;
         int r;
 
         assert(st);
@@ -522,13 +523,26 @@ static int fd_copy_directory(
                 return -errno;
         fdf = -1;
 
-        r = mkdirat(dt, to, st->st_mode & 07777);
-        if (r >= 0)
-                created = true;
-        else if (errno == EEXIST && (copy_flags & COPY_MERGE))
+        exists = false;
+        if (copy_flags & COPY_MERGE_EMPTY) {
+                r = dir_is_empty_at(dt, to);
+                if (r < 0 && r != -ENOENT)
+                        return r;
+                else if (r == 1)
+                        exists = true;
+        }
+
+        if (exists)
                 created = false;
-        else
-                return -errno;
+        else {
+                r = mkdirat(dt, to, st->st_mode & 07777);
+                if (r >= 0)
+                        created = true;
+                else if (errno == EEXIST && (copy_flags & COPY_MERGE))
+                        created = false;
+                else
+                        return -errno;
+        }
 
         fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
         if (fdt < 0)
index a41b44c..f677021 100644 (file)
@@ -9,10 +9,11 @@
 #include <sys/types.h>
 
 typedef enum CopyFlags {
-        COPY_REFLINK    = 1 << 0, /* Try to reflink */
-        COPY_MERGE      = 1 << 1, /* Merge existing trees with our new one to copy */
-        COPY_REPLACE    = 1 << 2, /* Replace an existing file if there's one */
-        COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
+        COPY_REFLINK     = 1 << 0, /* Try to reflink */
+        COPY_MERGE       = 1 << 1, /* Merge existing trees with our new one to copy */
+        COPY_REPLACE     = 1 << 2, /* Replace an existing file if there's one */
+        COPY_SAME_MOUNT  = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
+        COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
 } CopyFlags;
 
 typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);