From 609d34736fc69ce3bf261eddd1948fe34025923a Mon Sep 17 00:00:00 2001 From: Ryan Gonzalez Date: Sun, 6 Jan 2019 18:01:59 -0600 Subject: [PATCH] copy: Add a COPY_MERGE_EMPTY flag to merge only if the target is empty --- src/basic/copy.c | 28 +++++++++++++++++++++------- src/basic/copy.h | 9 +++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/basic/copy.c b/src/basic/copy.c index 34e01ea1cf4..46e02a37593 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -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) diff --git a/src/basic/copy.h b/src/basic/copy.h index a41b44c70ab..f6770218819 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -9,10 +9,11 @@ #include 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);