copy.c revision 14bcf25c8b94b5c3556ba3983028a2b35ed0572f
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering/***
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering This file is part of systemd.
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering Copyright 2014 Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering systemd is free software; you can redistribute it and/or modify it
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering under the terms of the GNU Lesser General Public License as published by
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (at your option) any later version.
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering systemd is distributed in the hope that it will be useful, but
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering Lesser General Public License for more details.
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering You should have received a copy of the GNU Lesser General Public License
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering***/
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#include <sys/sendfile.h>
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#include <sys/xattr.h>
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#include "util.h"
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#include "btrfs-util.h"
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#include "copy.h"
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#define COPY_BUFFER_SIZE (16*1024)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering bool try_sendfile = true;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(fdf >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(fdt >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering /* Try btrfs reflinks first. */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (try_reflink && max_bytes == (off_t) -1) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = btrfs_reflink(fdf, fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r >= 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering for (;;) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering size_t m = COPY_BUFFER_SIZE;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ssize_t n;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (max_bytes != (off_t) -1) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (max_bytes <= 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -EFBIG;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if ((off_t) m > max_bytes)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering m = (size_t) max_bytes;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering /* First try sendfile(), unless we already tried */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (try_sendfile) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering n = sendfile(fdt, fdf, NULL, m);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (n < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (errno != EINVAL && errno != ENOSYS)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering try_sendfile = false;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering /* use fallback below */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering } else if (n == 0) /* EOF */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering break;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (n > 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering /* Succcess! */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering goto next;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering /* As a fallback just copy bits by hand */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering char buf[m];
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering n = read(fdf, buf, m);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (n < 0)
ec76e139d8ce0a1183ae7639ae31a28e7e90791bThomas Hindoe Paaboel Andersen return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (n == 0) /* EOF */
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering break;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = loop_write(fdt, buf, (size_t) n, false);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering next:
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (max_bytes != (off_t) -1) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(max_bytes >= n);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering max_bytes -= n;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringstatic int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_free_ char *target = NULL;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(st);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = readlinkat_malloc(df, from, &target);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (symlinkat(target, dt, to) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringstatic int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_close_ int fdf = -1, fdt = -1;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct timespec ts[2];
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r, q;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(st);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fdf < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fdt < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = copy_bytes(fdf, fdt, (off_t) -1, true);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering unlinkat(dt, to, 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchown(fdt, st->st_uid, st->st_gid) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchmod(fdt, st->st_mode & 07777) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ts[0] = st->st_atim;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ts[1] = st->st_mtim;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) futimens(fdt, ts);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) copy_xattr(fdf, fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = close(fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdt = -1;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (q < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering unlinkat(dt, to, 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringstatic int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(st);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = mkfifoat(dt, to, st->st_mode & 07777);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringstatic int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(st);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = mknodat(dt, to, st->st_mode, st->st_rdev);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringstatic int fd_copy_directory(
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int df,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering const char *from,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering const struct stat *st,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int dt,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering const char *to,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering dev_t original_device,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering bool merge) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_close_ int fdf = -1, fdt = -1;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_closedir_ DIR *d = NULL;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct dirent *de;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering bool created;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(st);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (from)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering d = fdopendir(fdf);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (!d)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdf = -1;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = mkdirat(dt, to, st->st_mode & 07777);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r >= 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering created = true;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (errno == EEXIST && merge)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering created = false;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fdt < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (created) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct timespec ut[2] = {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering st->st_atim,
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering st->st_mtim
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering };
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchown(fdt, st->st_uid, st->st_gid) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fchmod(fdt, st->st_mode & 07777) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) futimens(fdt, ut);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) copy_xattr(dirfd(d), fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering FOREACH_DIRENT(de, d, return -errno) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct stat buf;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int q;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering continue;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (buf.st_dev != original_device)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering continue;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (S_ISREG(buf.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISDIR(buf.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISLNK(buf.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISFIFO(buf.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = -EOPNOTSUPP;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (q == -EEXIST && merge)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering q = 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (q < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = q;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct stat st;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (S_ISREG(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_regular(fdf, from, &st, fdt, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISDIR(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISLNK(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_symlink(fdf, from, &st, fdt, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISFIFO(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_fifo(fdf, from, &st, fdt, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_node(fdf, from, &st, fdt, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering else
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -EOPNOTSUPP;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_tree(const char *from, const char *to, bool merge) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_directory_fd(int dirfd, const char *to, bool merge) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct stat st;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(dirfd >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fstat(dirfd, &st) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (!S_ISDIR(st.st_mode))
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -ENOTDIR;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_file_fd(const char *from, int fdt, bool try_reflink) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_close_ int fdf = -1;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(fdt >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fdf < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) copy_times(fdf, fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) copy_xattr(fdf, fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int fdt = -1, r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering RUN_WITH_UMASK(0000) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fdt < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (chattr_flags != 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = copy_file_fd(from, fdt, true);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering close(fdt);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering unlink(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (close(fdt) < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering unlink_noerrno(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_free_ char *t = NULL;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering int r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(from);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = tempfn_random(to, NULL, &t);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (replace) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = renameat(AT_FDCWD, t, AT_FDCWD, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering } else
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (r < 0) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) unlink_noerrno(t);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return r;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering }
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_times(int fdf, int fdt) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct timespec ut[2];
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering struct stat st;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering usec_t crtime = 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(fdf >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering assert(fdt >= 0);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fstat(fdf, &st) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ut[0] = st.st_atim;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ut[1] = st.st_mtim;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (futimens(fdt, ut) < 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return -errno;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering if (fd_getcrtime(fdf, &crtime) >= 0)
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering (void) fd_setcrtime(fdt, crtime);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering return 0;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering}
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poetteringint copy_xattr(int fdf, int fdt) {
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering _cleanup_free_ char *bufa = NULL, *bufb = NULL;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering size_t sza = 100, szb = 100;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering ssize_t n;
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering 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;
}