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"
29 #define COPY_BUFFER_SIZE (16*1024)
31 int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
32 bool try_sendfile = true;
38 /* Try btrfs reflinks first. */
39 if (try_reflink && max_bytes == (off_t) -1) {
40 r = btrfs_reflink(fdf, fdt);
46 size_t m = COPY_BUFFER_SIZE;
49 if (max_bytes != (off_t) -1) {
54 if ((off_t) m > max_bytes)
55 m = (size_t) max_bytes;
58 /* First try sendfile(), unless we already tried */
61 n = sendfile(fdt, fdf, NULL, m);
63 if (errno != EINVAL && errno != ENOSYS)
67 /* use fallback below */
68 } else if (n == 0) /* EOF */
75 /* As a fallback just copy bits by hand */
79 n = read(fdf, buf, m);
85 r = loop_write(fdt, buf, (size_t) n, false);
91 if (max_bytes != (off_t) -1) {
92 assert(max_bytes >= n);
100 static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
101 _cleanup_free_ char *target = NULL;
108 r = readlinkat_malloc(df, from, &target);
112 if (symlinkat(target, dt, to) < 0)
115 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
121 static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
122 _cleanup_close_ int fdf = -1, fdt = -1;
123 struct timespec ts[2];
130 fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
134 fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
138 r = copy_bytes(fdf, fdt, (off_t) -1, true);
144 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
147 if (fchmod(fdt, st->st_mode & 07777) < 0)
152 (void) futimens(fdt, ts);
154 (void) copy_xattr(fdf, fdt);
167 static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
174 r = mkfifoat(dt, to, st->st_mode & 07777);
178 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
181 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
187 static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
194 r = mknodat(dt, to, st->st_mode, st->st_rdev);
198 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
201 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
207 static int fd_copy_directory(
210 const struct stat *st,
213 dev_t original_device,
216 _cleanup_close_ int fdf = -1, fdt = -1;
217 _cleanup_closedir_ DIR *d = NULL;
226 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
228 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
235 r = mkdirat(dt, to, st->st_mode & 07777);
238 else if (errno == EEXIST && merge)
243 fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
250 struct timespec ut[2] = {
255 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
258 if (fchmod(fdt, st->st_mode & 07777) < 0)
261 (void) futimens(fdt, ut);
262 (void) copy_xattr(dirfd(d), fdt);
265 FOREACH_DIRENT(de, d, return -errno) {
269 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
274 if (buf.st_dev != original_device)
277 if (S_ISREG(buf.st_mode))
278 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
279 else if (S_ISDIR(buf.st_mode))
280 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
281 else if (S_ISLNK(buf.st_mode))
282 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
283 else if (S_ISFIFO(buf.st_mode))
284 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
285 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
286 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
290 if (q == -EEXIST && merge)
300 int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
306 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
309 if (S_ISREG(st.st_mode))
310 return fd_copy_regular(fdf, from, &st, fdt, to);
311 else if (S_ISDIR(st.st_mode))
312 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
313 else if (S_ISLNK(st.st_mode))
314 return fd_copy_symlink(fdf, from, &st, fdt, to);
315 else if (S_ISFIFO(st.st_mode))
316 return fd_copy_fifo(fdf, from, &st, fdt, to);
317 else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
318 return fd_copy_node(fdf, from, &st, fdt, to);
323 int copy_tree(const char *from, const char *to, bool merge) {
324 return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
327 int copy_directory_fd(int dirfd, const char *to, bool merge) {
334 if (fstat(dirfd, &st) < 0)
337 if (!S_ISDIR(st.st_mode))
340 return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
343 int copy_file_fd(const char *from, int fdt, bool try_reflink) {
344 _cleanup_close_ int fdf = -1;
350 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
354 r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
356 (void) copy_times(fdf, fdt);
357 (void) copy_xattr(fdf, fdt);
362 int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
368 RUN_WITH_UMASK(0000) {
369 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
374 if (chattr_flags != 0)
375 (void) chattr_fd(fdt, true, chattr_flags);
377 r = copy_file_fd(from, fdt, true);
384 if (close(fdt) < 0) {
392 int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
393 _cleanup_free_ char *t = NULL;
399 r = tempfn_random(to, &t);
403 r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
408 r = renameat(AT_FDCWD, t, AT_FDCWD, to);
412 r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
414 (void) unlink_noerrno(t);
421 int copy_times(int fdf, int fdt) {
422 struct timespec ut[2];
429 if (fstat(fdf, &st) < 0)
435 if (futimens(fdt, ut) < 0)
438 if (fd_getcrtime(fdf, &crtime) >= 0)
439 (void) fd_setcrtime(fdt, crtime);
444 int copy_xattr(int fdf, int fdt) {
445 _cleanup_free_ char *bufa = NULL, *bufb = NULL;
446 size_t sza = 100, szb = 100;
456 n = flistxattr(fdf, bufa, sza);
475 assert(l < (size_t) n);
477 if (startswith(p, "user.")) {
486 m = fgetxattr(fdf, p, bufb, szb);
488 if (errno == ERANGE) {
498 if (fsetxattr(fdt, p, bufb, m, 0) < 0)