]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/copy.c
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>
25 #include "btrfs-util.h"
29 #include "string-util.h"
33 #define COPY_BUFFER_SIZE (16*1024)
35 int copy_bytes(int fdf
, int fdt
, uint64_t max_bytes
, bool try_reflink
) {
36 bool try_sendfile
= true, try_splice
= true;
42 /* Try btrfs reflinks first. */
44 max_bytes
== (uint64_t) -1 &&
45 lseek(fdf
, 0, SEEK_CUR
) == 0 &&
46 lseek(fdt
, 0, SEEK_CUR
) == 0) {
48 r
= btrfs_reflink(fdf
, fdt
);
50 return 0; /* we copied the whole thing, hence hit EOF, return 0 */
54 size_t m
= COPY_BUFFER_SIZE
;
57 if (max_bytes
!= (uint64_t) -1) {
60 return 1; /* return > 0 if we hit the max_bytes limit */
62 if ((uint64_t) m
> max_bytes
)
63 m
= (size_t) max_bytes
;
66 /* First try sendfile(), unless we already tried */
69 n
= sendfile(fdt
, fdf
, NULL
, m
);
71 if (errno
!= EINVAL
&& errno
!= ENOSYS
)
75 /* use fallback below */
76 } else if (n
== 0) /* EOF */
83 /* The try splice, unless we already tried */
85 n
= splice(fdf
, NULL
, fdt
, NULL
, m
, 0);
87 if (errno
!= EINVAL
&& errno
!= ENOSYS
)
91 /* use fallback below */
92 } else if (n
== 0) /* EOF */
99 /* As a fallback just copy bits by hand */
103 n
= read(fdf
, buf
, m
);
106 if (n
== 0) /* EOF */
109 r
= loop_write(fdt
, buf
, (size_t) n
, false);
115 if (max_bytes
!= (uint64_t) -1) {
116 assert(max_bytes
>= (uint64_t) n
);
121 return 0; /* return 0 if we hit EOF earlier than the size limit */
124 static int fd_copy_symlink(int df
, const char *from
, const struct stat
*st
, int dt
, const char *to
) {
125 _cleanup_free_
char *target
= NULL
;
132 r
= readlinkat_malloc(df
, from
, &target
);
136 if (symlinkat(target
, dt
, to
) < 0)
139 if (fchownat(dt
, to
, st
->st_uid
, st
->st_gid
, AT_SYMLINK_NOFOLLOW
) < 0)
145 static int fd_copy_regular(int df
, const char *from
, const struct stat
*st
, int dt
, const char *to
) {
146 _cleanup_close_
int fdf
= -1, fdt
= -1;
147 struct timespec ts
[2];
154 fdf
= openat(df
, from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
158 fdt
= openat(dt
, to
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, st
->st_mode
& 07777);
162 r
= copy_bytes(fdf
, fdt
, (uint64_t) -1, true);
168 if (fchown(fdt
, st
->st_uid
, st
->st_gid
) < 0)
171 if (fchmod(fdt
, st
->st_mode
& 07777) < 0)
176 (void) futimens(fdt
, ts
);
178 (void) copy_xattr(fdf
, fdt
);
191 static int fd_copy_fifo(int df
, const char *from
, const struct stat
*st
, int dt
, const char *to
) {
198 r
= mkfifoat(dt
, to
, st
->st_mode
& 07777);
202 if (fchownat(dt
, to
, st
->st_uid
, st
->st_gid
, AT_SYMLINK_NOFOLLOW
) < 0)
205 if (fchmodat(dt
, to
, st
->st_mode
& 07777, 0) < 0)
211 static int fd_copy_node(int df
, const char *from
, const struct stat
*st
, int dt
, const char *to
) {
218 r
= mknodat(dt
, to
, st
->st_mode
, st
->st_rdev
);
222 if (fchownat(dt
, to
, st
->st_uid
, st
->st_gid
, AT_SYMLINK_NOFOLLOW
) < 0)
225 if (fchmodat(dt
, to
, st
->st_mode
& 07777, 0) < 0)
231 static int fd_copy_directory(
234 const struct stat
*st
,
237 dev_t original_device
,
240 _cleanup_close_
int fdf
= -1, fdt
= -1;
241 _cleanup_closedir_
DIR *d
= NULL
;
250 fdf
= openat(df
, from
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
252 fdf
= fcntl(df
, F_DUPFD_CLOEXEC
, 3);
259 r
= mkdirat(dt
, to
, st
->st_mode
& 07777);
262 else if (errno
== EEXIST
&& merge
)
267 fdt
= openat(dt
, to
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
274 struct timespec ut
[2] = {
279 if (fchown(fdt
, st
->st_uid
, st
->st_gid
) < 0)
282 if (fchmod(fdt
, st
->st_mode
& 07777) < 0)
285 (void) futimens(fdt
, ut
);
286 (void) copy_xattr(dirfd(d
), fdt
);
289 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
293 if (STR_IN_SET(de
->d_name
, ".", ".."))
296 if (fstatat(dirfd(d
), de
->d_name
, &buf
, AT_SYMLINK_NOFOLLOW
) < 0) {
301 if (buf
.st_dev
!= original_device
)
304 if (S_ISREG(buf
.st_mode
))
305 q
= fd_copy_regular(dirfd(d
), de
->d_name
, &buf
, fdt
, de
->d_name
);
306 else if (S_ISDIR(buf
.st_mode
))
307 q
= fd_copy_directory(dirfd(d
), de
->d_name
, &buf
, fdt
, de
->d_name
, original_device
, merge
);
308 else if (S_ISLNK(buf
.st_mode
))
309 q
= fd_copy_symlink(dirfd(d
), de
->d_name
, &buf
, fdt
, de
->d_name
);
310 else if (S_ISFIFO(buf
.st_mode
))
311 q
= fd_copy_fifo(dirfd(d
), de
->d_name
, &buf
, fdt
, de
->d_name
);
312 else if (S_ISBLK(buf
.st_mode
) || S_ISCHR(buf
.st_mode
))
313 q
= fd_copy_node(dirfd(d
), de
->d_name
, &buf
, fdt
, de
->d_name
);
317 if (q
== -EEXIST
&& merge
)
327 int copy_tree_at(int fdf
, const char *from
, int fdt
, const char *to
, bool merge
) {
333 if (fstatat(fdf
, from
, &st
, AT_SYMLINK_NOFOLLOW
) < 0)
336 if (S_ISREG(st
.st_mode
))
337 return fd_copy_regular(fdf
, from
, &st
, fdt
, to
);
338 else if (S_ISDIR(st
.st_mode
))
339 return fd_copy_directory(fdf
, from
, &st
, fdt
, to
, st
.st_dev
, merge
);
340 else if (S_ISLNK(st
.st_mode
))
341 return fd_copy_symlink(fdf
, from
, &st
, fdt
, to
);
342 else if (S_ISFIFO(st
.st_mode
))
343 return fd_copy_fifo(fdf
, from
, &st
, fdt
, to
);
344 else if (S_ISBLK(st
.st_mode
) || S_ISCHR(st
.st_mode
))
345 return fd_copy_node(fdf
, from
, &st
, fdt
, to
);
350 int copy_tree(const char *from
, const char *to
, bool merge
) {
351 return copy_tree_at(AT_FDCWD
, from
, AT_FDCWD
, to
, merge
);
354 int copy_directory_fd(int dirfd
, const char *to
, bool merge
) {
361 if (fstat(dirfd
, &st
) < 0)
364 if (!S_ISDIR(st
.st_mode
))
367 return fd_copy_directory(dirfd
, NULL
, &st
, AT_FDCWD
, to
, st
.st_dev
, merge
);
370 int copy_file_fd(const char *from
, int fdt
, bool try_reflink
) {
371 _cleanup_close_
int fdf
= -1;
377 fdf
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
381 r
= copy_bytes(fdf
, fdt
, (uint64_t) -1, try_reflink
);
383 (void) copy_times(fdf
, fdt
);
384 (void) copy_xattr(fdf
, fdt
);
389 int copy_file(const char *from
, const char *to
, int flags
, mode_t mode
, unsigned chattr_flags
) {
395 RUN_WITH_UMASK(0000) {
396 fdt
= open(to
, flags
|O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
, mode
);
401 if (chattr_flags
!= 0)
402 (void) chattr_fd(fdt
, chattr_flags
, (unsigned) -1);
404 r
= copy_file_fd(from
, fdt
, true);
411 if (close(fdt
) < 0) {
419 int copy_file_atomic(const char *from
, const char *to
, mode_t mode
, bool replace
, unsigned chattr_flags
) {
420 _cleanup_free_
char *t
= NULL
;
426 r
= tempfn_random(to
, NULL
, &t
);
430 r
= copy_file(from
, t
, O_NOFOLLOW
|O_EXCL
, mode
, chattr_flags
);
435 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
439 r
= rename_noreplace(AT_FDCWD
, t
, AT_FDCWD
, to
);
441 (void) unlink_noerrno(t
);
448 int copy_times(int fdf
, int fdt
) {
449 struct timespec ut
[2];
456 if (fstat(fdf
, &st
) < 0)
462 if (futimens(fdt
, ut
) < 0)
465 if (fd_getcrtime(fdf
, &crtime
) >= 0)
466 (void) fd_setcrtime(fdt
, crtime
);
471 int copy_xattr(int fdf
, int fdt
) {
472 _cleanup_free_
char *bufa
= NULL
, *bufb
= NULL
;
473 size_t sza
= 100, szb
= 100;
483 n
= flistxattr(fdf
, bufa
, sza
);
501 assert(l
< (size_t) n
);
503 if (startswith(p
, "user.")) {
512 m
= fgetxattr(fdf
, p
, bufb
, szb
);
514 if (errno
== ERANGE
) {
523 if (fsetxattr(fdt
, p
, bufb
, m
, 0) < 0)