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