]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/copy.c
Merge pull request #8700 from keszybz/hibernation
[thirdparty/systemd.git] / src / basic / copy.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6 ***/
7
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/sendfile.h>
16 #include <sys/stat.h>
17 #include <sys/xattr.h>
18 #include <time.h>
19 #include <unistd.h>
20
21 #include "alloc-util.h"
22 #include "btrfs-util.h"
23 #include "chattr-util.h"
24 #include "copy.h"
25 #include "dirent-util.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "fs-util.h"
29 #include "io-util.h"
30 #include "macro.h"
31 #include "missing.h"
32 #include "string-util.h"
33 #include "strv.h"
34 #include "time-util.h"
35 #include "umask-util.h"
36 #include "user-util.h"
37 #include "xattr-util.h"
38
39 #define COPY_BUFFER_SIZE (16*1024u)
40
41 static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
42 int fd_out, loff_t *off_out,
43 size_t len,
44 unsigned int flags) {
45 static int have = -1;
46 ssize_t r;
47
48 if (have == false)
49 return -ENOSYS;
50
51 r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
52 if (_unlikely_(have < 0))
53 have = r >= 0 || errno != ENOSYS;
54 if (r >= 0)
55 return r;
56 else
57 return -errno;
58 }
59
60 int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
61 bool try_cfr = true, try_sendfile = true, try_splice = true;
62 int r;
63 size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
64
65 assert(fdf >= 0);
66 assert(fdt >= 0);
67
68 /* Try btrfs reflinks first. */
69 if ((copy_flags & COPY_REFLINK) &&
70 max_bytes == (uint64_t) -1 &&
71 lseek(fdf, 0, SEEK_CUR) == 0 &&
72 lseek(fdt, 0, SEEK_CUR) == 0) {
73
74 r = btrfs_reflink(fdf, fdt);
75 if (r >= 0)
76 return 0; /* we copied the whole thing, hence hit EOF, return 0 */
77 }
78
79 for (;;) {
80 ssize_t n;
81
82 if (max_bytes != (uint64_t) -1) {
83 if (max_bytes <= 0)
84 return 1; /* return > 0 if we hit the max_bytes limit */
85
86 if (m > max_bytes)
87 m = max_bytes;
88 }
89
90 /* First try copy_file_range(), unless we already tried */
91 if (try_cfr) {
92 n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u);
93 if (n < 0) {
94 if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF))
95 return n;
96
97 try_cfr = false;
98 /* use fallback below */
99 } else if (n == 0) /* EOF */
100 break;
101 else
102 /* Success! */
103 goto next;
104 }
105
106 /* First try sendfile(), unless we already tried */
107 if (try_sendfile) {
108 n = sendfile(fdt, fdf, NULL, m);
109 if (n < 0) {
110 if (!IN_SET(errno, EINVAL, ENOSYS))
111 return -errno;
112
113 try_sendfile = false;
114 /* use fallback below */
115 } else if (n == 0) /* EOF */
116 break;
117 else
118 /* Success! */
119 goto next;
120 }
121
122 /* Then try splice, unless we already tried */
123 if (try_splice) {
124 n = splice(fdf, NULL, fdt, NULL, m, 0);
125 if (n < 0) {
126 if (!IN_SET(errno, EINVAL, ENOSYS))
127 return -errno;
128
129 try_splice = false;
130 /* use fallback below */
131 } else if (n == 0) /* EOF */
132 break;
133 else
134 /* Success! */
135 goto next;
136 }
137
138 /* As a fallback just copy bits by hand */
139 {
140 uint8_t buf[MIN(m, COPY_BUFFER_SIZE)];
141
142 n = read(fdf, buf, sizeof buf);
143 if (n < 0)
144 return -errno;
145 if (n == 0) /* EOF */
146 break;
147
148 r = loop_write(fdt, buf, (size_t) n, false);
149 if (r < 0)
150 return r;
151 }
152
153 next:
154 if (max_bytes != (uint64_t) -1) {
155 assert(max_bytes >= (uint64_t) n);
156 max_bytes -= n;
157 }
158 /* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
159 * so reduce our maximum by the amount we already copied,
160 * but don't go below our copy buffer size, unless we are
161 * close the limit of bytes we are allowed to copy. */
162 m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
163 }
164
165 return 0; /* return 0 if we hit EOF earlier than the size limit */
166 }
167
168 static int fd_copy_symlink(
169 int df,
170 const char *from,
171 const struct stat *st,
172 int dt,
173 const char *to,
174 uid_t override_uid,
175 gid_t override_gid,
176 CopyFlags copy_flags) {
177
178 _cleanup_free_ char *target = NULL;
179 int r;
180
181 assert(from);
182 assert(st);
183 assert(to);
184
185 r = readlinkat_malloc(df, from, &target);
186 if (r < 0)
187 return r;
188
189 if (symlinkat(target, dt, to) < 0)
190 return -errno;
191
192 if (fchownat(dt, to,
193 uid_is_valid(override_uid) ? override_uid : st->st_uid,
194 gid_is_valid(override_gid) ? override_gid : st->st_gid,
195 AT_SYMLINK_NOFOLLOW) < 0)
196 return -errno;
197
198 return 0;
199 }
200
201 static int fd_copy_regular(
202 int df,
203 const char *from,
204 const struct stat *st,
205 int dt,
206 const char *to,
207 uid_t override_uid,
208 gid_t override_gid,
209 CopyFlags copy_flags) {
210
211 _cleanup_close_ int fdf = -1, fdt = -1;
212 struct timespec ts[2];
213 int r, q;
214
215 assert(from);
216 assert(st);
217 assert(to);
218
219 fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
220 if (fdf < 0)
221 return -errno;
222
223 fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
224 if (fdt < 0)
225 return -errno;
226
227 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
228 if (r < 0) {
229 (void) unlinkat(dt, to, 0);
230 return r;
231 }
232
233 if (fchown(fdt,
234 uid_is_valid(override_uid) ? override_uid : st->st_uid,
235 gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
236 r = -errno;
237
238 if (fchmod(fdt, st->st_mode & 07777) < 0)
239 r = -errno;
240
241 ts[0] = st->st_atim;
242 ts[1] = st->st_mtim;
243 (void) futimens(fdt, ts);
244 (void) copy_xattr(fdf, fdt);
245
246 q = close(fdt);
247 fdt = -1;
248
249 if (q < 0) {
250 r = -errno;
251 (void) unlinkat(dt, to, 0);
252 }
253
254 return r;
255 }
256
257 static int fd_copy_fifo(
258 int df,
259 const char *from,
260 const struct stat *st,
261 int dt,
262 const char *to,
263 uid_t override_uid,
264 gid_t override_gid,
265 CopyFlags copy_flags) {
266 int r;
267
268 assert(from);
269 assert(st);
270 assert(to);
271
272 r = mkfifoat(dt, to, st->st_mode & 07777);
273 if (r < 0)
274 return -errno;
275
276 if (fchownat(dt, to,
277 uid_is_valid(override_uid) ? override_uid : st->st_uid,
278 gid_is_valid(override_gid) ? override_gid : st->st_gid,
279 AT_SYMLINK_NOFOLLOW) < 0)
280 r = -errno;
281
282 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
283 r = -errno;
284
285 return r;
286 }
287
288 static int fd_copy_node(
289 int df,
290 const char *from,
291 const struct stat *st,
292 int dt,
293 const char *to,
294 uid_t override_uid,
295 gid_t override_gid,
296 CopyFlags copy_flags) {
297 int r;
298
299 assert(from);
300 assert(st);
301 assert(to);
302
303 r = mknodat(dt, to, st->st_mode, st->st_rdev);
304 if (r < 0)
305 return -errno;
306
307 if (fchownat(dt, to,
308 uid_is_valid(override_uid) ? override_uid : st->st_uid,
309 gid_is_valid(override_gid) ? override_gid : st->st_gid,
310 AT_SYMLINK_NOFOLLOW) < 0)
311 r = -errno;
312
313 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
314 r = -errno;
315
316 return r;
317 }
318
319 static int fd_copy_directory(
320 int df,
321 const char *from,
322 const struct stat *st,
323 int dt,
324 const char *to,
325 dev_t original_device,
326 uid_t override_uid,
327 gid_t override_gid,
328 CopyFlags copy_flags) {
329
330 _cleanup_close_ int fdf = -1, fdt = -1;
331 _cleanup_closedir_ DIR *d = NULL;
332 struct dirent *de;
333 bool created;
334 int r;
335
336 assert(st);
337 assert(to);
338
339 if (from)
340 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
341 else
342 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
343 if (fdf < 0)
344 return -errno;
345
346 d = fdopendir(fdf);
347 if (!d)
348 return -errno;
349 fdf = -1;
350
351 r = mkdirat(dt, to, st->st_mode & 07777);
352 if (r >= 0)
353 created = true;
354 else if (errno == EEXIST && (copy_flags & COPY_MERGE))
355 created = false;
356 else
357 return -errno;
358
359 fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
360 if (fdt < 0)
361 return -errno;
362
363 r = 0;
364
365 FOREACH_DIRENT_ALL(de, d, return -errno) {
366 struct stat buf;
367 int q;
368
369 if (dot_or_dot_dot(de->d_name))
370 continue;
371
372 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
373 r = -errno;
374 continue;
375 }
376
377 if (buf.st_dev != original_device)
378 continue;
379
380 if (S_ISREG(buf.st_mode))
381 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
382 else if (S_ISDIR(buf.st_mode))
383 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags);
384 else if (S_ISLNK(buf.st_mode))
385 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
386 else if (S_ISFIFO(buf.st_mode))
387 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
388 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
389 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
390 else
391 q = -EOPNOTSUPP;
392
393 if (q == -EEXIST && (copy_flags & COPY_MERGE))
394 q = 0;
395
396 if (q < 0)
397 r = q;
398 }
399
400 if (created) {
401 struct timespec ut[2] = {
402 st->st_atim,
403 st->st_mtim
404 };
405
406 if (fchown(fdt,
407 uid_is_valid(override_uid) ? override_uid : st->st_uid,
408 gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
409 r = -errno;
410
411 if (fchmod(fdt, st->st_mode & 07777) < 0)
412 r = -errno;
413
414 (void) copy_xattr(dirfd(d), fdt);
415 (void) futimens(fdt, ut);
416 }
417
418 return r;
419 }
420
421 int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
422 struct stat st;
423
424 assert(from);
425 assert(to);
426
427 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
428 return -errno;
429
430 if (S_ISREG(st.st_mode))
431 return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
432 else if (S_ISDIR(st.st_mode))
433 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags);
434 else if (S_ISLNK(st.st_mode))
435 return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
436 else if (S_ISFIFO(st.st_mode))
437 return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
438 else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
439 return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
440 else
441 return -EOPNOTSUPP;
442 }
443
444 int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
445 return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags);
446 }
447
448 int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
449 struct stat st;
450
451 assert(dirfd >= 0);
452 assert(to);
453
454 if (fstat(dirfd, &st) < 0)
455 return -errno;
456
457 if (!S_ISDIR(st.st_mode))
458 return -ENOTDIR;
459
460 return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
461 }
462
463 int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
464 struct stat st;
465
466 assert(from);
467 assert(to);
468
469 if (lstat(from, &st) < 0)
470 return -errno;
471
472 if (!S_ISDIR(st.st_mode))
473 return -ENOTDIR;
474
475 return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
476 }
477
478 int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
479 _cleanup_close_ int fdf = -1;
480 int r;
481
482 assert(from);
483 assert(fdt >= 0);
484
485 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
486 if (fdf < 0)
487 return -errno;
488
489 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
490
491 (void) copy_times(fdf, fdt);
492 (void) copy_xattr(fdf, fdt);
493
494 return r;
495 }
496
497 int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
498 int fdt = -1, r;
499
500 assert(from);
501 assert(to);
502
503 RUN_WITH_UMASK(0000) {
504 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
505 if (fdt < 0)
506 return -errno;
507 }
508
509 if (chattr_flags != 0)
510 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
511
512 r = copy_file_fd(from, fdt, copy_flags);
513 if (r < 0) {
514 close(fdt);
515 (void) unlink(to);
516 return r;
517 }
518
519 if (close(fdt) < 0) {
520 unlink_noerrno(to);
521 return -errno;
522 }
523
524 return 0;
525 }
526
527 int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
528 _cleanup_free_ char *t = NULL;
529 int r;
530
531 assert(from);
532 assert(to);
533
534 r = tempfn_random(to, NULL, &t);
535 if (r < 0)
536 return r;
537
538 r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags);
539 if (r < 0)
540 return r;
541
542 if (copy_flags & COPY_REPLACE) {
543 r = renameat(AT_FDCWD, t, AT_FDCWD, to);
544 if (r < 0)
545 r = -errno;
546 } else
547 r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
548 if (r < 0) {
549 (void) unlink(t);
550 return r;
551 }
552
553 return 0;
554 }
555
556 int copy_times(int fdf, int fdt) {
557 struct timespec ut[2];
558 struct stat st;
559 usec_t crtime = 0;
560
561 assert(fdf >= 0);
562 assert(fdt >= 0);
563
564 if (fstat(fdf, &st) < 0)
565 return -errno;
566
567 ut[0] = st.st_atim;
568 ut[1] = st.st_mtim;
569
570 if (futimens(fdt, ut) < 0)
571 return -errno;
572
573 if (fd_getcrtime(fdf, &crtime) >= 0)
574 (void) fd_setcrtime(fdt, crtime);
575
576 return 0;
577 }
578
579 int copy_xattr(int fdf, int fdt) {
580 _cleanup_free_ char *bufa = NULL, *bufb = NULL;
581 size_t sza = 100, szb = 100;
582 ssize_t n;
583 int ret = 0;
584 const char *p;
585
586 for (;;) {
587 bufa = malloc(sza);
588 if (!bufa)
589 return -ENOMEM;
590
591 n = flistxattr(fdf, bufa, sza);
592 if (n == 0)
593 return 0;
594 if (n > 0)
595 break;
596 if (errno != ERANGE)
597 return -errno;
598
599 sza *= 2;
600
601 bufa = mfree(bufa);
602 }
603
604 p = bufa;
605 while (n > 0) {
606 size_t l;
607
608 l = strlen(p);
609 assert(l < (size_t) n);
610
611 if (startswith(p, "user.")) {
612 ssize_t m;
613
614 if (!bufb) {
615 bufb = malloc(szb);
616 if (!bufb)
617 return -ENOMEM;
618 }
619
620 m = fgetxattr(fdf, p, bufb, szb);
621 if (m < 0) {
622 if (errno == ERANGE) {
623 szb *= 2;
624 bufb = mfree(bufb);
625 continue;
626 }
627
628 return -errno;
629 }
630
631 if (fsetxattr(fdt, p, bufb, m, 0) < 0)
632 ret = -errno;
633 }
634
635 p += l + 1;
636 n -= l + 1;
637 }
638
639 return ret;
640 }