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