Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <dirent.h>
4 : : #include <errno.h>
5 : : #include <fcntl.h>
6 : : #include <stddef.h>
7 : : #include <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : : #include <sys/sendfile.h>
11 : : #include <sys/stat.h>
12 : : #include <sys/xattr.h>
13 : : #include <time.h>
14 : : #include <unistd.h>
15 : :
16 : : #include "alloc-util.h"
17 : : #include "btrfs-util.h"
18 : : #include "chattr-util.h"
19 : : #include "copy.h"
20 : : #include "dirent-util.h"
21 : : #include "fd-util.h"
22 : : #include "fs-util.h"
23 : : #include "io-util.h"
24 : : #include "macro.h"
25 : : #include "missing.h"
26 : : #include "mountpoint-util.h"
27 : : #include "stat-util.h"
28 : : #include "string-util.h"
29 : : #include "strv.h"
30 : : #include "time-util.h"
31 : : #include "tmpfile-util.h"
32 : : #include "umask-util.h"
33 : : #include "user-util.h"
34 : : #include "xattr-util.h"
35 : :
36 : : #define COPY_BUFFER_SIZE (16U*1024U)
37 : :
38 : : /* A safety net for descending recursively into file system trees to copy. On Linux PATH_MAX is 4096, which means the
39 : : * deepest valid path one can build is around 2048, which we hence use as a safety net here, to not spin endlessly in
40 : : * case of bind mount cycles and suchlike. */
41 : : #define COPY_DEPTH_MAX 2048U
42 : :
43 : 164 : static ssize_t try_copy_file_range(
44 : : int fd_in, loff_t *off_in,
45 : : int fd_out, loff_t *off_out,
46 : : size_t len,
47 : : unsigned flags) {
48 : :
49 : : static int have = -1;
50 : : ssize_t r;
51 : :
52 [ - + ]: 164 : if (have == 0)
53 : 0 : return -ENOSYS;
54 : :
55 : 164 : r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
56 [ + + ]: 164 : if (have < 0)
57 [ + + + - ]: 8 : have = r >= 0 || errno != ENOSYS;
58 [ + + ]: 164 : if (r < 0)
59 : 76 : return -errno;
60 : :
61 : 88 : return r;
62 : : }
63 : :
64 : : enum {
65 : : FD_IS_NO_PIPE,
66 : : FD_IS_BLOCKING_PIPE,
67 : : FD_IS_NONBLOCKING_PIPE,
68 : : };
69 : :
70 : 24 : static int fd_is_nonblock_pipe(int fd) {
71 : : struct stat st;
72 : : int flags;
73 : :
74 : : /* Checks whether the specified file descriptor refers to a pipe, and if so if O_NONBLOCK is set. */
75 : :
76 [ - + ]: 24 : if (fstat(fd, &st) < 0)
77 : 0 : return -errno;
78 : :
79 [ + - ]: 24 : if (!S_ISFIFO(st.st_mode))
80 : 24 : return FD_IS_NO_PIPE;
81 : :
82 : 0 : flags = fcntl(fd, F_GETFL);
83 [ # # ]: 0 : if (flags < 0)
84 : 0 : return -errno;
85 : :
86 [ # # ]: 0 : return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
87 : : }
88 : :
89 : 0 : static int sigint_pending(void) {
90 : : sigset_t ss;
91 : :
92 [ # # ]: 0 : assert_se(sigemptyset(&ss) >= 0);
93 [ # # ]: 0 : assert_se(sigaddset(&ss, SIGINT) >= 0);
94 : :
95 [ # # ]: 0 : if (sigtimedwait(&ss, NULL, &(struct timespec) { 0, 0 }) < 0) {
96 [ # # ]: 0 : if (errno == EAGAIN)
97 : 0 : return false;
98 : :
99 : 0 : return -errno;
100 : : }
101 : :
102 : 0 : return true;
103 : : }
104 : :
105 : 128 : int copy_bytes_full(
106 : : int fdf, int fdt,
107 : : uint64_t max_bytes,
108 : : CopyFlags copy_flags,
109 : : void **ret_remains,
110 : : size_t *ret_remains_size,
111 : : copy_progress_bytes_t progress,
112 : : void *userdata) {
113 : :
114 : 128 : bool try_cfr = true, try_sendfile = true, try_splice = true;
115 : 128 : int r, nonblock_pipe = -1;
116 : 128 : size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
117 : :
118 [ - + ]: 128 : assert(fdf >= 0);
119 [ - + ]: 128 : assert(fdt >= 0);
120 : :
121 : : /* Tries to copy bytes from the file descriptor 'fdf' to 'fdt' in the smartest possible way. Copies a maximum
122 : : * of 'max_bytes', which may be specified as UINT64_MAX, in which no maximum is applied. Returns negative on
123 : : * error, zero if EOF is hit before the bytes limit is hit and positive otherwise. If the copy fails for some
124 : : * reason but we read but didn't yet write some data an ret_remains/ret_remains_size is not NULL, then it will
125 : : * be initialized with an allocated buffer containing this "remaining" data. Note that these two parameters are
126 : : * initialized with a valid buffer only on failure and only if there's actually data already read. Otherwise
127 : : * these parameters if non-NULL are set to NULL. */
128 : :
129 [ - + ]: 128 : if (ret_remains)
130 : 0 : *ret_remains = NULL;
131 [ - + ]: 128 : if (ret_remains_size)
132 : 0 : *ret_remains_size = 0;
133 : :
134 : : /* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of
135 : : * source and destination first. */
136 [ + + ]: 128 : if ((copy_flags & COPY_REFLINK)) {
137 : : off_t foffset;
138 : :
139 : 68 : foffset = lseek(fdf, 0, SEEK_CUR);
140 [ + + ]: 68 : if (foffset >= 0) {
141 : : off_t toffset;
142 : :
143 : 60 : toffset = lseek(fdt, 0, SEEK_CUR);
144 [ + - ]: 60 : if (toffset >= 0) {
145 : :
146 [ + - + - : 60 : if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX)
+ + ]
147 : 44 : r = btrfs_reflink(fdf, fdt); /* full file reflink */
148 : : else
149 [ + - ]: 16 : r = btrfs_clone_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */
150 [ - + ]: 60 : if (r >= 0) {
151 : : off_t t;
152 : :
153 : : /* This worked, yay! Now — to be fully correct — let's adjust the file pointers */
154 [ # # ]: 0 : if (max_bytes == UINT64_MAX) {
155 : :
156 : : /* We cloned to the end of the source file, let's position the read
157 : : * pointer there, and query it at the same time. */
158 : 0 : t = lseek(fdf, 0, SEEK_END);
159 [ # # ]: 0 : if (t < 0)
160 : 0 : return -errno;
161 [ # # ]: 0 : if (t < foffset)
162 : 0 : return -ESPIPE;
163 : :
164 : : /* Let's adjust the destination file write pointer by the same number
165 : : * of bytes. */
166 : 0 : t = lseek(fdt, toffset + (t - foffset), SEEK_SET);
167 [ # # ]: 0 : if (t < 0)
168 : 0 : return -errno;
169 : :
170 : 0 : return 0; /* we copied the whole thing, hence hit EOF, return 0 */
171 : : } else {
172 : 0 : t = lseek(fdf, foffset + max_bytes, SEEK_SET);
173 [ # # ]: 0 : if (t < 0)
174 : 0 : return -errno;
175 : :
176 : 0 : t = lseek(fdt, toffset + max_bytes, SEEK_SET);
177 [ # # ]: 0 : if (t < 0)
178 : 0 : return -errno;
179 : :
180 : 0 : return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */
181 : : }
182 : : }
183 : : }
184 : : }
185 : : }
186 : :
187 : 358555 : for (;;) {
188 : : ssize_t n;
189 : :
190 [ + + ]: 358683 : if (max_bytes <= 0)
191 : 40 : return 1; /* return > 0 if we hit the max_bytes limit */
192 : :
193 [ - + ]: 358643 : if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
194 : 0 : r = sigint_pending();
195 [ # # ]: 0 : if (r < 0)
196 : 0 : return r;
197 [ # # ]: 0 : if (r > 0)
198 : 0 : return -EINTR;
199 : : }
200 : :
201 [ + + + + ]: 358643 : if (max_bytes != UINT64_MAX && m > max_bytes)
202 : 60 : m = max_bytes;
203 : :
204 : : /* First try copy_file_range(), unless we already tried */
205 [ + + ]: 358643 : if (try_cfr) {
206 : 164 : n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u);
207 [ + + ]: 164 : if (n < 0) {
208 [ + - - + ]: 76 : if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF))
209 : 0 : return n;
210 : :
211 : 76 : try_cfr = false;
212 : : /* use fallback below */
213 [ + + ]: 88 : } else if (n == 0) /* EOF */
214 : 36 : break;
215 : : else
216 : : /* Success! */
217 : 52 : goto next;
218 : : }
219 : :
220 : : /* First try sendfile(), unless we already tried */
221 [ + + ]: 358555 : if (try_sendfile) {
222 : 112 : n = sendfile(fdt, fdf, NULL, m);
223 [ + + ]: 112 : if (n < 0) {
224 [ + + + + ]: 24 : if (!IN_SET(errno, EINVAL, ENOSYS))
225 : 12 : return -errno;
226 : :
227 : 12 : try_sendfile = false;
228 : : /* use fallback below */
229 [ + + ]: 88 : } else if (n == 0) /* EOF */
230 : 36 : break;
231 : : else
232 : : /* Success! */
233 : 52 : goto next;
234 : : }
235 : :
236 : : /* Then try splice, unless we already tried. */
237 [ + + ]: 358455 : if (try_splice) {
238 : :
239 : : /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file
240 : : * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the
241 : : * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and
242 : : * check if either of the specified fds are a pipe, and if so, let's pass the flag
243 : : * automatically, depending on O_NONBLOCK being set.
244 : : *
245 : : * Here's a twist though: when we use it to move data between two pipes of which one has
246 : : * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK
247 : : * behaviour. Hence in that case we can't use splice() and still guarantee systematic
248 : : * O_NONBLOCK behaviour, hence don't. */
249 : :
250 [ + - ]: 12 : if (nonblock_pipe < 0) {
251 : : int a, b;
252 : :
253 : : /* Check if either of these fds is a pipe, and if so non-blocking or not */
254 : 12 : a = fd_is_nonblock_pipe(fdf);
255 [ - + ]: 12 : if (a < 0)
256 : 0 : return a;
257 : :
258 : 12 : b = fd_is_nonblock_pipe(fdt);
259 [ - + ]: 12 : if (b < 0)
260 : 0 : return b;
261 : :
262 [ + - - + : 12 : if ((a == FD_IS_NO_PIPE && b == FD_IS_NO_PIPE) ||
# # ]
263 [ # # # # ]: 0 : (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) ||
264 [ # # ]: 0 : (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE))
265 : :
266 : : /* splice() only works if one of the fds is a pipe. If neither is, let's skip
267 : : * this step right-away. As mentioned above, if one of the two fds refers to a
268 : : * blocking pipe and the other to a non-blocking pipe, we can't use splice()
269 : : * either, hence don't try either. This hence means we can only use splice() if
270 : : * either only one of the two fds is a pipe, or if both are pipes with the same
271 : : * nonblocking flag setting. */
272 : :
273 : 12 : try_splice = false;
274 : : else
275 [ # # # # ]: 0 : nonblock_pipe = a == FD_IS_NONBLOCKING_PIPE || b == FD_IS_NONBLOCKING_PIPE;
276 : : }
277 : : }
278 : :
279 [ - + ]: 358455 : if (try_splice) {
280 [ # # ]: 0 : n = splice(fdf, NULL, fdt, NULL, m, nonblock_pipe ? SPLICE_F_NONBLOCK : 0);
281 [ # # ]: 0 : if (n < 0) {
282 [ # # # # ]: 0 : if (!IN_SET(errno, EINVAL, ENOSYS))
283 : 0 : return -errno;
284 : :
285 : 0 : try_splice = false;
286 : : /* use fallback below */
287 [ # # ]: 0 : } else if (n == 0) /* EOF */
288 : 0 : break;
289 : : else
290 : : /* Success! */
291 : 0 : goto next;
292 : : }
293 : :
294 : : /* As a fallback just copy bits by hand */
295 : 358455 : {
296 : 358455 : uint8_t buf[MIN(m, COPY_BUFFER_SIZE)], *p = buf;
297 : : ssize_t z;
298 : :
299 : 358455 : n = read(fdf, buf, sizeof buf);
300 [ - + ]: 358455 : if (n < 0)
301 : 0 : return -errno;
302 [ + + ]: 358455 : if (n == 0) /* EOF */
303 : 4 : break;
304 : :
305 : 358451 : z = (size_t) n;
306 : : do {
307 : : ssize_t k;
308 : :
309 : 358451 : k = write(fdt, p, z);
310 [ - + ]: 358451 : if (k < 0) {
311 : 0 : r = -errno;
312 : :
313 [ # # ]: 0 : if (ret_remains) {
314 : : void *copy;
315 : :
316 : 0 : copy = memdup(p, z);
317 [ # # ]: 0 : if (!copy)
318 : 0 : return -ENOMEM;
319 : :
320 : 0 : *ret_remains = copy;
321 : : }
322 : :
323 [ # # ]: 0 : if (ret_remains_size)
324 : 0 : *ret_remains_size = z;
325 : :
326 : 0 : return r;
327 : : }
328 : :
329 [ - + ]: 358451 : assert(k <= z);
330 : 358451 : z -= k;
331 : 358451 : p += k;
332 [ - + ]: 358451 : } while (z > 0);
333 : : }
334 : :
335 : 358555 : next:
336 [ - + ]: 358555 : if (progress) {
337 : 0 : r = progress(n, userdata);
338 [ # # ]: 0 : if (r < 0)
339 : 0 : return r;
340 : : }
341 : :
342 [ + + ]: 358555 : if (max_bytes != (uint64_t) -1) {
343 [ - + ]: 259480 : assert(max_bytes >= (uint64_t) n);
344 : 259480 : max_bytes -= n;
345 : : }
346 : :
347 : : /* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
348 : : * so reduce our maximum by the amount we already copied,
349 : : * but don't go below our copy buffer size, unless we are
350 : : * close the limit of bytes we are allowed to copy. */
351 : 358555 : m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
352 : : }
353 : :
354 : 76 : return 0; /* return 0 if we hit EOF earlier than the size limit */
355 : : }
356 : :
357 : 8 : static int fd_copy_symlink(
358 : : int df,
359 : : const char *from,
360 : : const struct stat *st,
361 : : int dt,
362 : : const char *to,
363 : : uid_t override_uid,
364 : : gid_t override_gid,
365 : : CopyFlags copy_flags) {
366 : :
367 : 8 : _cleanup_free_ char *target = NULL;
368 : : int r;
369 : :
370 [ - + ]: 8 : assert(from);
371 [ - + ]: 8 : assert(st);
372 [ - + ]: 8 : assert(to);
373 : :
374 : 8 : r = readlinkat_malloc(df, from, &target);
375 [ - + ]: 8 : if (r < 0)
376 : 0 : return r;
377 : :
378 [ - + ]: 8 : if (symlinkat(target, dt, to) < 0)
379 : 0 : return -errno;
380 : :
381 [ + - + - : 16 : if (fchownat(dt, to,
- + ]
382 : 8 : uid_is_valid(override_uid) ? override_uid : st->st_uid,
383 : 8 : gid_is_valid(override_gid) ? override_gid : st->st_gid,
384 : : AT_SYMLINK_NOFOLLOW) < 0)
385 : 0 : return -errno;
386 : :
387 : 8 : return 0;
388 : : }
389 : :
390 : 16 : static int fd_copy_regular(
391 : : int df,
392 : : const char *from,
393 : : const struct stat *st,
394 : : int dt,
395 : : const char *to,
396 : : uid_t override_uid,
397 : : gid_t override_gid,
398 : : CopyFlags copy_flags,
399 : : copy_progress_bytes_t progress,
400 : : void *userdata) {
401 : :
402 : 16 : _cleanup_close_ int fdf = -1, fdt = -1;
403 : : struct timespec ts[2];
404 : : int r, q;
405 : :
406 [ - + ]: 16 : assert(from);
407 [ - + ]: 16 : assert(st);
408 [ - + ]: 16 : assert(to);
409 : :
410 : 16 : fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
411 [ - + ]: 16 : if (fdf < 0)
412 : 0 : return -errno;
413 : :
414 : 16 : fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
415 [ - + ]: 16 : if (fdt < 0)
416 : 0 : return -errno;
417 : :
418 : 16 : r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress, userdata);
419 [ - + ]: 16 : if (r < 0) {
420 : 0 : (void) unlinkat(dt, to, 0);
421 : 0 : return r;
422 : : }
423 : :
424 [ + - + - : 32 : if (fchown(fdt,
- + ]
425 : 16 : uid_is_valid(override_uid) ? override_uid : st->st_uid,
426 : 16 : gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
427 : 0 : r = -errno;
428 : :
429 [ - + ]: 16 : if (fchmod(fdt, st->st_mode & 07777) < 0)
430 : 0 : r = -errno;
431 : :
432 : 16 : ts[0] = st->st_atim;
433 : 16 : ts[1] = st->st_mtim;
434 : 16 : (void) futimens(fdt, ts);
435 : 16 : (void) copy_xattr(fdf, fdt);
436 : :
437 : 16 : q = close(fdt);
438 : 16 : fdt = -1;
439 : :
440 [ - + ]: 16 : if (q < 0) {
441 : 0 : r = -errno;
442 : 0 : (void) unlinkat(dt, to, 0);
443 : : }
444 : :
445 : 16 : return r;
446 : : }
447 : :
448 : 0 : static int fd_copy_fifo(
449 : : int df,
450 : : const char *from,
451 : : const struct stat *st,
452 : : int dt,
453 : : const char *to,
454 : : uid_t override_uid,
455 : : gid_t override_gid,
456 : : CopyFlags copy_flags) {
457 : : int r;
458 : :
459 [ # # ]: 0 : assert(from);
460 [ # # ]: 0 : assert(st);
461 [ # # ]: 0 : assert(to);
462 : :
463 : 0 : r = mkfifoat(dt, to, st->st_mode & 07777);
464 [ # # ]: 0 : if (r < 0)
465 : 0 : return -errno;
466 : :
467 [ # # # # : 0 : if (fchownat(dt, to,
# # ]
468 : 0 : uid_is_valid(override_uid) ? override_uid : st->st_uid,
469 : 0 : gid_is_valid(override_gid) ? override_gid : st->st_gid,
470 : : AT_SYMLINK_NOFOLLOW) < 0)
471 : 0 : r = -errno;
472 : :
473 [ # # ]: 0 : if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
474 : 0 : r = -errno;
475 : :
476 : 0 : return r;
477 : : }
478 : :
479 : 4 : static int fd_copy_node(
480 : : int df,
481 : : const char *from,
482 : : const struct stat *st,
483 : : int dt,
484 : : const char *to,
485 : : uid_t override_uid,
486 : : gid_t override_gid,
487 : : CopyFlags copy_flags) {
488 : : int r;
489 : :
490 [ - + ]: 4 : assert(from);
491 [ - + ]: 4 : assert(st);
492 [ - + ]: 4 : assert(to);
493 : :
494 : 4 : r = mknodat(dt, to, st->st_mode, st->st_rdev);
495 [ - + ]: 4 : if (r < 0)
496 : 0 : return -errno;
497 : :
498 [ + - + - : 8 : if (fchownat(dt, to,
- + ]
499 : 4 : uid_is_valid(override_uid) ? override_uid : st->st_uid,
500 : 4 : gid_is_valid(override_gid) ? override_gid : st->st_gid,
501 : : AT_SYMLINK_NOFOLLOW) < 0)
502 : 0 : r = -errno;
503 : :
504 [ - + ]: 4 : if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
505 : 0 : r = -errno;
506 : :
507 : 4 : return r;
508 : : }
509 : :
510 : 28 : static int fd_copy_directory(
511 : : int df,
512 : : const char *from,
513 : : const struct stat *st,
514 : : int dt,
515 : : const char *to,
516 : : dev_t original_device,
517 : : unsigned depth_left,
518 : : uid_t override_uid,
519 : : gid_t override_gid,
520 : : CopyFlags copy_flags,
521 : : const char *display_path,
522 : : copy_progress_path_t progress_path,
523 : : copy_progress_bytes_t progress_bytes,
524 : : void *userdata) {
525 : :
526 : 28 : _cleanup_close_ int fdf = -1, fdt = -1;
527 : 28 : _cleanup_closedir_ DIR *d = NULL;
528 : : struct dirent *de;
529 : : bool exists, created;
530 : : int r;
531 : :
532 [ - + ]: 28 : assert(st);
533 [ - + ]: 28 : assert(to);
534 : :
535 [ - + ]: 28 : if (depth_left == 0)
536 : 0 : return -ENAMETOOLONG;
537 : :
538 [ + - ]: 28 : if (from)
539 : 28 : fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
540 : : else
541 : 0 : fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
542 [ - + ]: 28 : if (fdf < 0)
543 : 0 : return -errno;
544 : :
545 : 28 : d = fdopendir(fdf);
546 [ - + ]: 28 : if (!d)
547 : 0 : return -errno;
548 : 28 : fdf = -1;
549 : :
550 : 28 : exists = false;
551 [ - + ]: 28 : if (copy_flags & COPY_MERGE_EMPTY) {
552 : 0 : r = dir_is_empty_at(dt, to);
553 [ # # # # ]: 0 : if (r < 0 && r != -ENOENT)
554 : 0 : return r;
555 [ # # ]: 0 : else if (r == 1)
556 : 0 : exists = true;
557 : : }
558 : :
559 [ - + ]: 28 : if (exists)
560 : 0 : created = false;
561 : : else {
562 : 28 : r = mkdirat(dt, to, st->st_mode & 07777);
563 [ + + ]: 28 : if (r >= 0)
564 : 24 : created = true;
565 [ + - - + ]: 4 : else if (errno == EEXIST && (copy_flags & COPY_MERGE))
566 : 0 : created = false;
567 : : else
568 : 4 : return -errno;
569 : : }
570 : :
571 : 24 : fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
572 [ - + ]: 24 : if (fdt < 0)
573 : 0 : return -errno;
574 : :
575 : 24 : r = 0;
576 : :
577 [ + + - + ]: 120 : FOREACH_DIRENT_ALL(de, d, return -errno) {
578 : 96 : const char *child_display_path = NULL;
579 [ + + - ]: 96 : _cleanup_free_ char *dp = NULL;
580 : : struct stat buf;
581 : : int q;
582 : :
583 [ + + ]: 96 : if (dot_or_dot_dot(de->d_name))
584 : 48 : continue;
585 : :
586 [ - + ]: 48 : if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
587 : 0 : r = sigint_pending();
588 [ # # ]: 0 : if (r < 0)
589 : 0 : return r;
590 [ # # ]: 0 : if (r > 0)
591 : 0 : return -EINTR;
592 : : }
593 : :
594 [ - + ]: 48 : if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
595 : 0 : r = -errno;
596 : 0 : continue;
597 : : }
598 : :
599 [ - + ]: 48 : if (progress_path) {
600 [ # # ]: 0 : if (display_path)
601 : 0 : child_display_path = dp = path_join(display_path, de->d_name);
602 : : else
603 : 0 : child_display_path = de->d_name;
604 : :
605 : 0 : r = progress_path(child_display_path, &buf, userdata);
606 [ # # ]: 0 : if (r < 0)
607 : 0 : return r;
608 : : }
609 : :
610 [ + + ]: 48 : if (S_ISDIR(buf.st_mode)) {
611 : : /*
612 : : * Don't descend into directories on other file systems, if this is requested. We do a simple
613 : : * .st_dev check here, which basically comes for free. Note that we do this check only on
614 : : * directories, not other kind of file system objects, for two reason:
615 : : *
616 : : * • The kernel's overlayfs pseudo file system that overlays multiple real file systems
617 : : * propagates the .st_dev field of the file system a file originates from all the way up
618 : : * through the stack to stat(). It doesn't do that for directories however. This means that
619 : : * comparing .st_dev on non-directories suggests that they all are mount points. To avoid
620 : : * confusion we hence avoid relying on this check for regular files.
621 : : *
622 : : * • The main reason we do this check at all is to protect ourselves from bind mount cycles,
623 : : * where we really want to avoid descending down in all eternity. However the .st_dev check
624 : : * is usually not sufficient for this protection anyway, as bind mount cycles from the same
625 : : * file system onto itself can't be detected that way. (Note we also do a recursion depth
626 : : * check, which is probably the better protection in this regard, which is why
627 : : * COPY_SAME_MOUNT is optional).
628 : : */
629 : :
630 [ - + ]: 20 : if (FLAGS_SET(copy_flags, COPY_SAME_MOUNT)) {
631 [ # # ]: 0 : if (buf.st_dev != original_device)
632 : 0 : continue;
633 : :
634 : 0 : r = fd_is_mount_point(dirfd(d), de->d_name, 0);
635 [ # # ]: 0 : if (r < 0)
636 : 0 : return r;
637 [ # # ]: 0 : if (r > 0)
638 : 0 : continue;
639 : : }
640 : :
641 : 20 : q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, child_display_path, progress_path, progress_bytes, userdata);
642 [ + + ]: 28 : } else if (S_ISREG(buf.st_mode))
643 : 16 : q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, progress_bytes, userdata);
644 [ + + ]: 12 : else if (S_ISLNK(buf.st_mode))
645 : 8 : q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
646 [ - + ]: 4 : else if (S_ISFIFO(buf.st_mode))
647 : 0 : q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
648 [ + - + - : 4 : else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
+ - ]
649 : 4 : q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
650 : : else
651 : 0 : q = -EOPNOTSUPP;
652 : :
653 [ - + ]: 48 : if (q == -EINTR) /* Propagate SIGINT up instantly */
654 : 0 : return q;
655 [ - + # # ]: 48 : if (q == -EEXIST && (copy_flags & COPY_MERGE))
656 : 0 : q = 0;
657 [ - + ]: 48 : if (q < 0)
658 : 0 : r = q;
659 : : }
660 : :
661 [ + - ]: 24 : if (created) {
662 : 24 : struct timespec ut[2] = {
663 : : st->st_atim,
664 : : st->st_mtim
665 : : };
666 : :
667 [ + - + - : 48 : if (fchown(fdt,
- + ]
668 : 24 : uid_is_valid(override_uid) ? override_uid : st->st_uid,
669 : 24 : gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
670 : 0 : r = -errno;
671 : :
672 [ - + ]: 24 : if (fchmod(fdt, st->st_mode & 07777) < 0)
673 : 0 : r = -errno;
674 : :
675 : 24 : (void) copy_xattr(dirfd(d), fdt);
676 : 24 : (void) futimens(fdt, ut);
677 : : }
678 : :
679 : 24 : return r;
680 : : }
681 : :
682 : 12 : int copy_tree_at_full(
683 : : int fdf,
684 : : const char *from,
685 : : int fdt,
686 : : const char *to,
687 : : uid_t override_uid,
688 : : gid_t override_gid,
689 : : CopyFlags copy_flags,
690 : : copy_progress_path_t progress_path,
691 : : copy_progress_bytes_t progress_bytes,
692 : : void *userdata) {
693 : :
694 : : struct stat st;
695 : :
696 [ - + ]: 12 : assert(from);
697 [ - + ]: 12 : assert(to);
698 : :
699 [ + + ]: 12 : if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
700 : 4 : return -errno;
701 : :
702 [ - + ]: 8 : if (S_ISREG(st.st_mode))
703 : 0 : return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, progress_bytes, userdata);
704 [ + - ]: 8 : else if (S_ISDIR(st.st_mode))
705 : 8 : return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, progress_path, progress_bytes, userdata);
706 [ # # ]: 0 : else if (S_ISLNK(st.st_mode))
707 : 0 : return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
708 [ # # ]: 0 : else if (S_ISFIFO(st.st_mode))
709 : 0 : return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
710 [ # # # # : 0 : else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
# # ]
711 : 0 : return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
712 : : else
713 : 0 : return -EOPNOTSUPP;
714 : : }
715 : :
716 : 0 : int copy_directory_fd_full(
717 : : int dirfd,
718 : : const char *to,
719 : : CopyFlags copy_flags,
720 : : copy_progress_path_t progress_path,
721 : : copy_progress_bytes_t progress_bytes,
722 : : void *userdata) {
723 : :
724 : : struct stat st;
725 : :
726 [ # # ]: 0 : assert(dirfd >= 0);
727 [ # # ]: 0 : assert(to);
728 : :
729 [ # # ]: 0 : if (fstat(dirfd, &st) < 0)
730 : 0 : return -errno;
731 : :
732 [ # # ]: 0 : if (!S_ISDIR(st.st_mode))
733 : 0 : return -ENOTDIR;
734 : :
735 : 0 : return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata);
736 : : }
737 : :
738 : 0 : int copy_directory_full(
739 : : const char *from,
740 : : const char *to,
741 : : CopyFlags copy_flags,
742 : : copy_progress_path_t progress_path,
743 : : copy_progress_bytes_t progress_bytes,
744 : : void *userdata) {
745 : :
746 : : struct stat st;
747 : :
748 [ # # ]: 0 : assert(from);
749 [ # # ]: 0 : assert(to);
750 : :
751 [ # # ]: 0 : if (lstat(from, &st) < 0)
752 : 0 : return -errno;
753 : :
754 [ # # ]: 0 : if (!S_ISDIR(st.st_mode))
755 : 0 : return -ENOTDIR;
756 : :
757 : 0 : return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata);
758 : : }
759 : :
760 : 24 : int copy_file_fd_full(
761 : : const char *from,
762 : : int fdt,
763 : : CopyFlags copy_flags,
764 : : copy_progress_bytes_t progress_bytes,
765 : : void *userdata) {
766 : :
767 : 24 : _cleanup_close_ int fdf = -1;
768 : : int r;
769 : :
770 [ - + ]: 24 : assert(from);
771 [ - + ]: 24 : assert(fdt >= 0);
772 : :
773 : 24 : fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
774 [ + + ]: 24 : if (fdf < 0)
775 : 4 : return -errno;
776 : :
777 : 20 : r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata);
778 : :
779 : 20 : (void) copy_times(fdf, fdt, copy_flags);
780 : 20 : (void) copy_xattr(fdf, fdt);
781 : :
782 : 20 : return r;
783 : : }
784 : :
785 : 4 : int copy_file_full(
786 : : const char *from,
787 : : const char *to,
788 : : int flags,
789 : : mode_t mode,
790 : : unsigned chattr_flags,
791 : : unsigned chattr_mask,
792 : : CopyFlags copy_flags,
793 : : copy_progress_bytes_t progress_bytes,
794 : : void *userdata) {
795 : :
796 : 4 : int fdt = -1, r;
797 : :
798 [ - + ]: 4 : assert(from);
799 [ - + ]: 4 : assert(to);
800 : :
801 [ + + + - ]: 8 : RUN_WITH_UMASK(0000) {
802 : 4 : fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
803 [ - + ]: 4 : if (fdt < 0)
804 : 0 : return -errno;
805 : : }
806 : :
807 [ - + ]: 4 : if (chattr_mask != 0)
808 : 0 : (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
809 : :
810 : 4 : r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
811 [ - + ]: 4 : if (r < 0) {
812 : 0 : close(fdt);
813 : 0 : (void) unlink(to);
814 : 0 : return r;
815 : : }
816 : :
817 [ - + ]: 4 : if (chattr_mask != 0)
818 : 0 : (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
819 : :
820 [ - + ]: 4 : if (close(fdt) < 0) {
821 : 0 : unlink_noerrno(to);
822 : 0 : return -errno;
823 : : }
824 : :
825 : 4 : return 0;
826 : : }
827 : :
828 : 12 : int copy_file_atomic_full(
829 : : const char *from,
830 : : const char *to,
831 : : mode_t mode,
832 : : unsigned chattr_flags,
833 : : unsigned chattr_mask,
834 : : CopyFlags copy_flags,
835 : : copy_progress_bytes_t progress_bytes,
836 : : void *userdata) {
837 : :
838 : 12 : _cleanup_(unlink_and_freep) char *t = NULL;
839 : 12 : _cleanup_close_ int fdt = -1;
840 : : int r;
841 : :
842 [ - + ]: 12 : assert(from);
843 [ - + ]: 12 : assert(to);
844 : :
845 : : /* We try to use O_TMPFILE here to create the file if we can. Note that that only works if COPY_REPLACE is not
846 : : * set though as we need to use linkat() for linking the O_TMPFILE file into the file system but that system
847 : : * call can't replace existing files. Hence, if COPY_REPLACE is set we create a temporary name in the file
848 : : * system right-away and unconditionally which we then can renameat() to the right name after we completed
849 : : * writing it. */
850 : :
851 [ + + ]: 12 : if (copy_flags & COPY_REPLACE) {
852 : 4 : r = tempfn_random(to, NULL, &t);
853 [ - + ]: 4 : if (r < 0)
854 : 0 : return r;
855 : :
856 : 4 : fdt = open(t, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
857 [ - + ]: 4 : if (fdt < 0) {
858 : 0 : t = mfree(t);
859 : 0 : return -errno;
860 : : }
861 : : } else {
862 : 8 : fdt = open_tmpfile_linkable(to, O_WRONLY|O_CLOEXEC, &t);
863 [ - + ]: 8 : if (fdt < 0)
864 : 0 : return fdt;
865 : : }
866 : :
867 [ - + ]: 12 : if (chattr_mask != 0)
868 : 0 : (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
869 : :
870 : 12 : r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
871 [ - + ]: 12 : if (r < 0)
872 : 0 : return r;
873 : :
874 [ - + ]: 12 : if (fchmod(fdt, mode) < 0)
875 : 0 : return -errno;
876 : :
877 [ + + ]: 12 : if (copy_flags & COPY_REPLACE) {
878 [ - + ]: 4 : if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0)
879 : 0 : return -errno;
880 : : } else {
881 : 8 : r = link_tmpfile(fdt, t, to);
882 [ + + ]: 8 : if (r < 0)
883 : 4 : return r;
884 : : }
885 : :
886 [ - + ]: 8 : if (chattr_mask != 0)
887 : 0 : (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
888 : :
889 : 8 : t = mfree(t);
890 : 8 : return 0;
891 : : }
892 : :
893 : 20 : int copy_times(int fdf, int fdt, CopyFlags flags) {
894 : : struct timespec ut[2];
895 : : struct stat st;
896 : :
897 [ - + ]: 20 : assert(fdf >= 0);
898 [ - + ]: 20 : assert(fdt >= 0);
899 : :
900 [ - + ]: 20 : if (fstat(fdf, &st) < 0)
901 : 0 : return -errno;
902 : :
903 : 20 : ut[0] = st.st_atim;
904 : 20 : ut[1] = st.st_mtim;
905 : :
906 [ - + ]: 20 : if (futimens(fdt, ut) < 0)
907 : 0 : return -errno;
908 : :
909 [ - + ]: 20 : if (FLAGS_SET(flags, COPY_CRTIME)) {
910 : : usec_t crtime;
911 : :
912 [ # # ]: 0 : if (fd_getcrtime(fdf, &crtime) >= 0)
913 : 0 : (void) fd_setcrtime(fdt, crtime);
914 : : }
915 : :
916 : 20 : return 0;
917 : : }
918 : :
919 : 60 : int copy_xattr(int fdf, int fdt) {
920 : 60 : _cleanup_free_ char *bufa = NULL, *bufb = NULL;
921 : 60 : size_t sza = 100, szb = 100;
922 : : ssize_t n;
923 : 60 : int ret = 0;
924 : : const char *p;
925 : :
926 : : for (;;) {
927 : 60 : bufa = malloc(sza);
928 [ - + ]: 60 : if (!bufa)
929 : 0 : return -ENOMEM;
930 : :
931 : 60 : n = flistxattr(fdf, bufa, sza);
932 [ - + ]: 60 : if (n == 0)
933 : 0 : return 0;
934 [ + - ]: 60 : if (n > 0)
935 : 60 : break;
936 [ # # ]: 0 : if (errno != ERANGE)
937 : 0 : return -errno;
938 : :
939 : 0 : sza *= 2;
940 : :
941 : 0 : bufa = mfree(bufa);
942 : : }
943 : :
944 : 60 : p = bufa;
945 [ + + ]: 120 : while (n > 0) {
946 : : size_t l;
947 : :
948 : 60 : l = strlen(p);
949 [ - + ]: 60 : assert(l < (size_t) n);
950 : :
951 [ - + ]: 60 : if (startswith(p, "user.")) {
952 : : ssize_t m;
953 : :
954 [ # # ]: 0 : if (!bufb) {
955 : 0 : bufb = malloc(szb);
956 [ # # ]: 0 : if (!bufb)
957 : 0 : return -ENOMEM;
958 : : }
959 : :
960 : 0 : m = fgetxattr(fdf, p, bufb, szb);
961 [ # # ]: 0 : if (m < 0) {
962 [ # # ]: 0 : if (errno == ERANGE) {
963 : 0 : szb *= 2;
964 : 0 : bufb = mfree(bufb);
965 : 0 : continue;
966 : : }
967 : :
968 : 0 : return -errno;
969 : : }
970 : :
971 [ # # ]: 0 : if (fsetxattr(fdt, p, bufb, m, 0) < 0)
972 : 0 : ret = -errno;
973 : : }
974 : :
975 : 60 : p += l + 1;
976 : 60 : n -= l + 1;
977 : : }
978 : :
979 : 60 : return ret;
980 : : }
|