diff --git a/src/basic/copy.c b/src/basic/copy.c index 6a9c3a396f..aa805bb8e2 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -1047,18 +1047,29 @@ int copy_file_full( copy_progress_bytes_t progress_bytes, void *userdata) { + _cleanup_close_ int fdf = -1; + struct stat st; int fdt = -1, r; assert(from); assert(to); + fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fdf < 0) + return -errno; + + if (mode == (mode_t) -1) + if (fstat(fdf, &st) < 0) + return -errno; + RUN_WITH_UMASK(0000) { if (copy_flags & COPY_MAC_CREATE) { r = mac_selinux_create_file_prepare(to, S_IFREG); if (r < 0) return r; } - fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); + fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, + mode != (mode_t) -1 ? mode : st.st_mode); if (copy_flags & COPY_MAC_CREATE) mac_selinux_create_file_clear(); if (fdt < 0) @@ -1068,13 +1079,16 @@ int copy_file_full( if (chattr_mask != 0) (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL); - r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata); + r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata); if (r < 0) { close(fdt); (void) unlink(to); return r; } + (void) copy_times(fdf, fdt, copy_flags); + (void) copy_xattr(fdf, fdt); + if (chattr_mask != 0) (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);