]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/copy.c
Merge pull request #6851 from keszybz/fix-masking-with-empty-files
[thirdparty/systemd.git] / src / basic / copy.c
CommitLineData
849958d1
LP
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
11c3a366
TA
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>
cda134ab 27#include <sys/sendfile.h>
11c3a366 28#include <sys/stat.h>
e6bd041c 29#include <sys/xattr.h>
11c3a366
TA
30#include <time.h>
31#include <unistd.h>
cda134ab 32
b5efdb8a 33#include "alloc-util.h"
d7c7c334 34#include "btrfs-util.h"
c8b3094d 35#include "chattr-util.h"
3ffd4af2 36#include "copy.h"
a0956174 37#include "dirent-util.h"
3ffd4af2 38#include "fd-util.h"
0d39fa9c 39#include "fileio.h"
f4f15635 40#include "fs-util.h"
c004493c 41#include "io-util.h"
11c3a366 42#include "macro.h"
a44202e9 43#include "missing.h"
07630cea 44#include "string-util.h"
8420fa3a 45#include "strv.h"
93cc7779 46#include "time-util.h"
affb60b1 47#include "umask-util.h"
d01cd401 48#include "user-util.h"
89a5a90c 49#include "xattr-util.h"
849958d1 50
00a8cf77 51#define COPY_BUFFER_SIZE (16*1024u)
f2cbe59e 52
a44202e9
ZJS
53static 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
1c876927 72int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
a44202e9 73 bool try_cfr = true, try_sendfile = true, try_splice = true;
0254b455 74 int r;
7c2da2ca 75 size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
cda134ab 76
849958d1
LP
77 assert(fdf >= 0);
78 assert(fdt >= 0);
79
0254b455 80 /* Try btrfs reflinks first. */
1c876927 81 if ((copy_flags & COPY_REFLINK) &&
c622fbdb
LP
82 max_bytes == (uint64_t) -1 &&
83 lseek(fdf, 0, SEEK_CUR) == 0 &&
84 lseek(fdt, 0, SEEK_CUR) == 0) {
85
0254b455
LP
86 r = btrfs_reflink(fdf, fdt);
87 if (r >= 0)
f6d9c616 88 return 0; /* we copied the whole thing, hence hit EOF, return 0 */
0254b455
LP
89 }
90
849958d1 91 for (;;) {
cda134ab 92 ssize_t n;
93240d3a 93
59f448cf 94 if (max_bytes != (uint64_t) -1) {
93240d3a 95 if (max_bytes <= 0)
f6d9c616 96 return 1; /* return > 0 if we hit the max_bytes limit */
93240d3a 97
d219849e
ZJS
98 if (m > max_bytes)
99 m = max_bytes;
93240d3a
LP
100 }
101
a44202e9
ZJS
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) {
6402d5c6 106 if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF))
a44202e9
ZJS
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
cda134ab
LP
118 /* First try sendfile(), unless we already tried */
119 if (try_sendfile) {
cda134ab
LP
120 n = sendfile(fdt, fdf, NULL, m);
121 if (n < 0) {
00a8cf77 122 if (!IN_SET(errno, EINVAL, ENOSYS))
cda134ab
LP
123 return -errno;
124
125 try_sendfile = false;
126 /* use fallback below */
127 } else if (n == 0) /* EOF */
128 break;
00a8cf77 129 else
81d20007
LP
130 /* Success! */
131 goto next;
132 }
133
00a8cf77 134 /* Then try splice, unless we already tried */
81d20007 135 if (try_splice) {
f6d9c616 136 n = splice(fdf, NULL, fdt, NULL, m, 0);
81d20007 137 if (n < 0) {
00a8cf77 138 if (!IN_SET(errno, EINVAL, ENOSYS))
81d20007
LP
139 return -errno;
140
141 try_splice = false;
142 /* use fallback below */
143 } else if (n == 0) /* EOF */
144 break;
00a8cf77 145 else
81d20007 146 /* Success! */
cda134ab
LP
147 goto next;
148 }
149
150 /* As a fallback just copy bits by hand */
151 {
00a8cf77 152 uint8_t buf[MIN(m, COPY_BUFFER_SIZE)];
849958d1 153
00a8cf77 154 n = read(fdf, buf, sizeof buf);
cda134ab
LP
155 if (n < 0)
156 return -errno;
157 if (n == 0) /* EOF */
158 break;
159
0254b455 160 r = loop_write(fdt, buf, (size_t) n, false);
553acb7b
ZJS
161 if (r < 0)
162 return r;
cda134ab 163 }
93240d3a 164
cda134ab 165 next:
59f448cf
LP
166 if (max_bytes != (uint64_t) -1) {
167 assert(max_bytes >= (uint64_t) n);
93240d3a
LP
168 max_bytes -= n;
169 }
00a8cf77
ZJS
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
61233823 173 * close the limit of bytes we are allowed to copy. */
00a8cf77 174 m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
849958d1
LP
175 }
176
f6d9c616 177 return 0; /* return 0 if we hit EOF earlier than the size limit */
849958d1
LP
178}
179
d01cd401
LP
180static 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
849958d1
LP
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
e156347e 201 if (symlinkat(target, dt, to) < 0)
849958d1 202 return -errno;
849958d1 203
d01cd401
LP
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)
849958d1
LP
208 return -errno;
209
210 return 0;
211}
212
d01cd401
LP
213static 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
849958d1 223 _cleanup_close_ int fdf = -1, fdt = -1;
ebd93cb6 224 struct timespec ts[2];
849958d1
LP
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);
e156347e 236 if (fdt < 0)
849958d1 237 return -errno;
849958d1 238
1c876927 239 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
849958d1
LP
240 if (r < 0) {
241 unlinkat(dt, to, 0);
242 return r;
243 }
244
d01cd401
LP
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)
849958d1
LP
248 r = -errno;
249
250 if (fchmod(fdt, st->st_mode & 07777) < 0)
251 r = -errno;
252
ebd93cb6
LP
253 ts[0] = st->st_atim;
254 ts[1] = st->st_mtim;
255 (void) futimens(fdt, ts);
e6bd041c
LP
256 (void) copy_xattr(fdf, fdt);
257
849958d1
LP
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
d01cd401
LP
269static 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) {
849958d1
LP
278 int r;
279
280 assert(from);
281 assert(st);
282 assert(to);
283
284 r = mkfifoat(dt, to, st->st_mode & 07777);
e156347e 285 if (r < 0)
849958d1 286 return -errno;
849958d1 287
d01cd401
LP
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)
849958d1
LP
292 r = -errno;
293
294 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
295 r = -errno;
296
297 return r;
298}
299
d01cd401
LP
300static 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) {
849958d1
LP
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);
e156347e 316 if (r < 0)
849958d1 317 return -errno;
849958d1 318
d01cd401
LP
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)
849958d1
LP
323 r = -errno;
324
325 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
326 r = -errno;
327
328 return r;
329}
330
d7c7c334
LP
331static 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,
d01cd401
LP
338 uid_t override_uid,
339 gid_t override_gid,
1c876927 340 CopyFlags copy_flags) {
d7c7c334 341
849958d1
LP
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
849958d1
LP
348 assert(st);
349 assert(to);
350
d7c7c334
LP
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);
b498c53d
LP
355 if (fdf < 0)
356 return -errno;
849958d1
LP
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;
1c876927 366 else if (errno == EEXIST && (copy_flags & COPY_MERGE))
849958d1
LP
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
2c455af4
LP
375 r = 0;
376
8420fa3a 377 FOREACH_DIRENT_ALL(de, d, return -errno) {
849958d1
LP
378 struct stat buf;
379 int q;
380
49bfc877 381 if (dot_or_dot_dot(de->d_name))
8420fa3a
LP
382 continue;
383
849958d1
LP
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))
d01cd401 393 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
849958d1 394 else if (S_ISDIR(buf.st_mode))
d01cd401 395 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags);
849958d1 396 else if (S_ISLNK(buf.st_mode))
d01cd401 397 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
849958d1 398 else if (S_ISFIFO(buf.st_mode))
d01cd401 399 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
0e2b2cac 400 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
d01cd401 401 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
849958d1 402 else
15411c0c 403 q = -EOPNOTSUPP;
849958d1 404
1c876927 405 if (q == -EEXIST && (copy_flags & COPY_MERGE))
e156347e
LP
406 q = 0;
407
849958d1
LP
408 if (q < 0)
409 r = q;
410 }
411
3b8483c0
LP
412 if (created) {
413 struct timespec ut[2] = {
414 st->st_atim,
415 st->st_mtim
416 };
417
d01cd401
LP
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)
3b8483c0
LP
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
849958d1
LP
430 return r;
431}
432
d01cd401 433int 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
434 struct stat st;
435
436 assert(from);
437 assert(to);
438
f2cbe59e 439 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
849958d1
LP
440 return -errno;
441
442 if (S_ISREG(st.st_mode))
d01cd401 443 return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
849958d1 444 else if (S_ISDIR(st.st_mode))
d01cd401 445 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags);
849958d1 446 else if (S_ISLNK(st.st_mode))
d01cd401 447 return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
849958d1 448 else if (S_ISFIFO(st.st_mode))
d01cd401 449 return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
0e2b2cac 450 else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
d01cd401 451 return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
849958d1 452 else
15411c0c 453 return -EOPNOTSUPP;
849958d1
LP
454}
455
d01cd401
LP
456int 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);
f2cbe59e
LP
458}
459
1c876927 460int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
d7c7c334
LP
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
d01cd401 472 return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
d7c7c334
LP
473}
474
1c876927 475int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
9a50e3ca
LP
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
d01cd401 487 return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
9a50e3ca
LP
488}
489
1c876927 490int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
cda134ab 491 _cleanup_close_ int fdf = -1;
e6bd041c 492 int r;
849958d1
LP
493
494 assert(from);
cda134ab 495 assert(fdt >= 0);
849958d1
LP
496
497 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
498 if (fdf < 0)
499 return -errno;
500
1c876927 501 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
e6bd041c
LP
502
503 (void) copy_times(fdf, fdt);
504 (void) copy_xattr(fdf, fdt);
505
506 return r;
cda134ab
LP
507}
508
1c876927 509int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
a7f7d1bd 510 int fdt = -1, r;
cda134ab
LP
511
512 assert(from);
513 assert(to);
514
ebd93cb6
LP
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 }
849958d1 520
f2068bcc 521 if (chattr_flags != 0)
1ed8f8c1 522 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
f2068bcc 523
1c876927 524 r = copy_file_fd(from, fdt, copy_flags);
849958d1 525 if (r < 0) {
cda134ab 526 close(fdt);
849958d1
LP
527 unlink(to);
528 return r;
529 }
530
cda134ab
LP
531 if (close(fdt) < 0) {
532 unlink_noerrno(to);
533 return -errno;
849958d1
LP
534 }
535
536 return 0;
537}
e6bd041c 538
1c876927 539int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
a7f7d1bd 540 _cleanup_free_ char *t = NULL;
ebd93cb6
LP
541 int r;
542
543 assert(from);
544 assert(to);
545
14bcf25c 546 r = tempfn_random(to, NULL, &t);
ebd93cb6
LP
547 if (r < 0)
548 return r;
549
1c876927 550 r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags);
ebd93cb6
LP
551 if (r < 0)
552 return r;
553
1c876927 554 if (copy_flags & COPY_REPLACE) {
f85ef957
AC
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) {
ce21ed5c 561 (void) unlink(t);
f85ef957 562 return r;
ebd93cb6
LP
563 }
564
565 return 0;
566}
567
e6bd041c
LP
568int copy_times(int fdf, int fdt) {
569 struct timespec ut[2];
570 struct stat st;
a7f7d1bd 571 usec_t crtime = 0;
e6bd041c
LP
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
591int 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
97b11eed 613 bufa = mfree(bufa);
e6bd041c
LP
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;
97b11eed 636 bufb = mfree(bufb);
e6bd041c
LP
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}