1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/sendfile.h>
23 #include <sys/xattr.h>
26 // #include "btrfs-util.h"
30 #define COPY_BUFFER_SIZE (16*1024)
32 int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
33 bool try_sendfile = true, try_splice = true;
39 /* Try btrfs reflinks first. */
40 if (try_reflink && max_bytes == (off_t) -1) {
41 r = btrfs_reflink(fdf, fdt);
47 size_t m = COPY_BUFFER_SIZE;
50 if (max_bytes != (off_t) -1) {
55 if ((off_t) m > max_bytes)
56 m = (size_t) max_bytes;
59 /* First try sendfile(), unless we already tried */
62 n = sendfile(fdt, fdf, NULL, m);
64 if (errno != EINVAL && errno != ENOSYS)
68 /* use fallback below */
69 } else if (n == 0) /* EOF */
76 /* The try splice, unless we already tried */
78 n = splice(fdf, NULL, fdt, NULL, m, 0);
80 if (errno != EINVAL && errno != ENOSYS)
84 /* use fallback below */
85 } else if (n == 0) /* EOF */
92 /* As a fallback just copy bits by hand */
96 n = read(fdf, buf, m);
102 r = loop_write(fdt, buf, (size_t) n, false);
108 if (max_bytes != (off_t) -1) {
109 assert(max_bytes >= n);
117 // UNNEEDED by elogind
119 static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
120 _cleanup_free_ char *target = NULL;
127 r = readlinkat_malloc(df, from, &target);
131 if (symlinkat(target, dt, to) < 0)
134 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
140 static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
141 _cleanup_close_ int fdf = -1, fdt = -1;
142 struct timespec ts[2];
149 fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
153 fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
157 r = copy_bytes(fdf, fdt, (off_t) -1, true);
163 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
166 if (fchmod(fdt, st->st_mode & 07777) < 0)
171 (void) futimens(fdt, ts);
173 (void) copy_xattr(fdf, fdt);
186 static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
193 r = mkfifoat(dt, to, st->st_mode & 07777);
197 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
200 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
206 static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
213 r = mknodat(dt, to, st->st_mode, st->st_rdev);
217 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
220 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
226 static int fd_copy_directory(
229 const struct stat *st,
232 dev_t original_device,
235 _cleanup_close_ int fdf = -1, fdt = -1;
236 _cleanup_closedir_ DIR *d = NULL;
245 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
247 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
254 r = mkdirat(dt, to, st->st_mode & 07777);
257 else if (errno == EEXIST && merge)
262 fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
269 struct timespec ut[2] = {
274 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
277 if (fchmod(fdt, st->st_mode & 07777) < 0)
280 (void) futimens(fdt, ut);
281 (void) copy_xattr(dirfd(d), fdt);
284 FOREACH_DIRENT_ALL(de, d, return -errno) {
288 if (STR_IN_SET(de->d_name, ".", ".."))
291 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
296 if (buf.st_dev != original_device)
299 if (S_ISREG(buf.st_mode))
300 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
301 else if (S_ISDIR(buf.st_mode))
302 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
303 else if (S_ISLNK(buf.st_mode))
304 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
305 else if (S_ISFIFO(buf.st_mode))
306 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
307 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
308 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
312 if (q == -EEXIST && merge)
322 int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
328 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
331 if (S_ISREG(st.st_mode))
332 return fd_copy_regular(fdf, from, &st, fdt, to);
333 else if (S_ISDIR(st.st_mode))
334 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
335 else if (S_ISLNK(st.st_mode))
336 return fd_copy_symlink(fdf, from, &st, fdt, to);
337 else if (S_ISFIFO(st.st_mode))
338 return fd_copy_fifo(fdf, from, &st, fdt, to);
339 else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
340 return fd_copy_node(fdf, from, &st, fdt, to);
345 int copy_tree(const char *from, const char *to, bool merge) {
346 return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
349 int copy_directory_fd(int dirfd, const char *to, bool merge) {
356 if (fstat(dirfd, &st) < 0)
359 if (!S_ISDIR(st.st_mode))
362 return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
365 int copy_file_fd(const char *from, int fdt, bool try_reflink) {
366 _cleanup_close_ int fdf = -1;
372 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
376 r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
378 (void) copy_times(fdf, fdt);
379 (void) copy_xattr(fdf, fdt);
384 int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
390 RUN_WITH_UMASK(0000) {
391 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
396 if (chattr_flags != 0)
397 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
399 r = copy_file_fd(from, fdt, true);
406 if (close(fdt) < 0) {
414 int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
415 _cleanup_free_ char *t = NULL;
421 r = tempfn_random(to, NULL, &t);
425 r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
430 r = renameat(AT_FDCWD, t, AT_FDCWD, to);
434 r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
436 (void) unlink_noerrno(t);
443 int copy_times(int fdf, int fdt) {
444 struct timespec ut[2];
451 if (fstat(fdf, &st) < 0)
457 if (futimens(fdt, ut) < 0)
460 if (fd_getcrtime(fdf, &crtime) >= 0)
461 (void) fd_setcrtime(fdt, crtime);
466 int copy_xattr(int fdf, int fdt) {
467 _cleanup_free_ char *bufa = NULL, *bufb = NULL;
468 size_t sza = 100, szb = 100;
478 n = flistxattr(fdf, bufa, sza);
496 assert(l < (size_t) n);
498 if (startswith(p, "user.")) {
507 m = fgetxattr(fdf, p, bufb, szb);
509 if (errno == ERANGE) {
518 if (fsetxattr(fdt, p, bufb, m, 0) < 0)