]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/copy.c
util-lib: split out globbing related calls into glob-util.[ch]
[thirdparty/systemd.git] / src / basic / copy.c
CommitLineData
849958d1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
cda134ab 22#include <sys/sendfile.h>
e6bd041c 23#include <sys/xattr.h>
cda134ab 24
d7c7c334 25#include "btrfs-util.h"
c8b3094d 26#include "chattr-util.h"
3ffd4af2 27#include "copy.h"
a0956174 28#include "dirent-util.h"
3ffd4af2 29#include "fd-util.h"
0d39fa9c 30#include "fileio.h"
f4f15635 31#include "fs-util.h"
c004493c 32#include "io-util.h"
07630cea 33#include "string-util.h"
8420fa3a 34#include "strv.h"
affb60b1 35#include "umask-util.h"
07630cea 36#include "util.h"
89a5a90c 37#include "xattr-util.h"
849958d1 38
f2cbe59e
LP
39#define COPY_BUFFER_SIZE (16*1024)
40
59f448cf 41int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
81d20007 42 bool try_sendfile = true, try_splice = true;
0254b455 43 int r;
cda134ab 44
849958d1
LP
45 assert(fdf >= 0);
46 assert(fdt >= 0);
47
0254b455 48 /* Try btrfs reflinks first. */
c622fbdb
LP
49 if (try_reflink &&
50 max_bytes == (uint64_t) -1 &&
51 lseek(fdf, 0, SEEK_CUR) == 0 &&
52 lseek(fdt, 0, SEEK_CUR) == 0) {
53
0254b455
LP
54 r = btrfs_reflink(fdf, fdt);
55 if (r >= 0)
f6d9c616 56 return 0; /* we copied the whole thing, hence hit EOF, return 0 */
0254b455
LP
57 }
58
849958d1 59 for (;;) {
f2cbe59e 60 size_t m = COPY_BUFFER_SIZE;
cda134ab 61 ssize_t n;
93240d3a 62
59f448cf 63 if (max_bytes != (uint64_t) -1) {
93240d3a
LP
64
65 if (max_bytes <= 0)
f6d9c616 66 return 1; /* return > 0 if we hit the max_bytes limit */
93240d3a 67
59f448cf 68 if ((uint64_t) m > max_bytes)
93240d3a
LP
69 m = (size_t) max_bytes;
70 }
71
cda134ab
LP
72 /* First try sendfile(), unless we already tried */
73 if (try_sendfile) {
74
75 n = sendfile(fdt, fdf, NULL, m);
76 if (n < 0) {
77 if (errno != EINVAL && errno != ENOSYS)
78 return -errno;
79
80 try_sendfile = false;
81 /* use fallback below */
82 } else if (n == 0) /* EOF */
83 break;
84 else if (n > 0)
81d20007
LP
85 /* Success! */
86 goto next;
87 }
88
89 /* The try splice, unless we already tried */
90 if (try_splice) {
f6d9c616 91 n = splice(fdf, NULL, fdt, NULL, m, 0);
81d20007
LP
92 if (n < 0) {
93 if (errno != EINVAL && errno != ENOSYS)
94 return -errno;
95
96 try_splice = false;
97 /* use fallback below */
98 } else if (n == 0) /* EOF */
99 break;
100 else if (n > 0)
101 /* Success! */
cda134ab
LP
102 goto next;
103 }
104
105 /* As a fallback just copy bits by hand */
106 {
f6d9c616 107 uint8_t buf[m];
849958d1 108
cda134ab
LP
109 n = read(fdf, buf, m);
110 if (n < 0)
111 return -errno;
112 if (n == 0) /* EOF */
113 break;
114
0254b455 115 r = loop_write(fdt, buf, (size_t) n, false);
553acb7b
ZJS
116 if (r < 0)
117 return r;
cda134ab 118 }
93240d3a 119
cda134ab 120 next:
59f448cf
LP
121 if (max_bytes != (uint64_t) -1) {
122 assert(max_bytes >= (uint64_t) n);
93240d3a
LP
123 max_bytes -= n;
124 }
849958d1
LP
125 }
126
f6d9c616 127 return 0; /* return 0 if we hit EOF earlier than the size limit */
849958d1
LP
128}
129
130static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
131 _cleanup_free_ char *target = NULL;
132 int r;
133
134 assert(from);
135 assert(st);
136 assert(to);
137
138 r = readlinkat_malloc(df, from, &target);
139 if (r < 0)
140 return r;
141
e156347e 142 if (symlinkat(target, dt, to) < 0)
849958d1 143 return -errno;
849958d1
LP
144
145 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
146 return -errno;
147
148 return 0;
149}
150
151static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
152 _cleanup_close_ int fdf = -1, fdt = -1;
ebd93cb6 153 struct timespec ts[2];
849958d1
LP
154 int r, q;
155
156 assert(from);
157 assert(st);
158 assert(to);
159
160 fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
161 if (fdf < 0)
162 return -errno;
163
164 fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
e156347e 165 if (fdt < 0)
849958d1 166 return -errno;
849958d1 167
59f448cf 168 r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
849958d1
LP
169 if (r < 0) {
170 unlinkat(dt, to, 0);
171 return r;
172 }
173
174 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
175 r = -errno;
176
177 if (fchmod(fdt, st->st_mode & 07777) < 0)
178 r = -errno;
179
ebd93cb6
LP
180 ts[0] = st->st_atim;
181 ts[1] = st->st_mtim;
182 (void) futimens(fdt, ts);
183
e6bd041c
LP
184 (void) copy_xattr(fdf, fdt);
185
849958d1
LP
186 q = close(fdt);
187 fdt = -1;
188
189 if (q < 0) {
190 r = -errno;
191 unlinkat(dt, to, 0);
192 }
193
194 return r;
195}
196
197static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
198 int r;
199
200 assert(from);
201 assert(st);
202 assert(to);
203
204 r = mkfifoat(dt, to, st->st_mode & 07777);
e156347e 205 if (r < 0)
849958d1 206 return -errno;
849958d1
LP
207
208 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
209 r = -errno;
210
211 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
212 r = -errno;
213
214 return r;
215}
216
217static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
218 int r;
219
220 assert(from);
221 assert(st);
222 assert(to);
223
224 r = mknodat(dt, to, st->st_mode, st->st_rdev);
e156347e 225 if (r < 0)
849958d1 226 return -errno;
849958d1
LP
227
228 if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
229 r = -errno;
230
231 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
232 r = -errno;
233
234 return r;
235}
236
d7c7c334
LP
237static int fd_copy_directory(
238 int df,
239 const char *from,
240 const struct stat *st,
241 int dt,
242 const char *to,
243 dev_t original_device,
244 bool merge) {
245
849958d1
LP
246 _cleanup_close_ int fdf = -1, fdt = -1;
247 _cleanup_closedir_ DIR *d = NULL;
248 struct dirent *de;
249 bool created;
250 int r;
251
849958d1
LP
252 assert(st);
253 assert(to);
254
d7c7c334
LP
255 if (from)
256 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
257 else
258 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
849958d1
LP
259
260 d = fdopendir(fdf);
261 if (!d)
262 return -errno;
263 fdf = -1;
264
265 r = mkdirat(dt, to, st->st_mode & 07777);
266 if (r >= 0)
267 created = true;
e156347e 268 else if (errno == EEXIST && merge)
849958d1
LP
269 created = false;
270 else
271 return -errno;
272
273 fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
274 if (fdt < 0)
275 return -errno;
276
2c455af4
LP
277 r = 0;
278
849958d1 279 if (created) {
ebd93cb6
LP
280 struct timespec ut[2] = {
281 st->st_atim,
282 st->st_mtim
283 };
284
849958d1
LP
285 if (fchown(fdt, st->st_uid, st->st_gid) < 0)
286 r = -errno;
287
288 if (fchmod(fdt, st->st_mode & 07777) < 0)
289 r = -errno;
e6bd041c 290
ebd93cb6
LP
291 (void) futimens(fdt, ut);
292 (void) copy_xattr(dirfd(d), fdt);
849958d1
LP
293 }
294
8420fa3a 295 FOREACH_DIRENT_ALL(de, d, return -errno) {
849958d1
LP
296 struct stat buf;
297 int q;
298
8420fa3a
LP
299 if (STR_IN_SET(de->d_name, ".", ".."))
300 continue;
301
849958d1
LP
302 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
303 r = -errno;
304 continue;
305 }
306
307 if (buf.st_dev != original_device)
308 continue;
309
310 if (S_ISREG(buf.st_mode))
311 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
312 else if (S_ISDIR(buf.st_mode))
e156347e 313 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
849958d1
LP
314 else if (S_ISLNK(buf.st_mode))
315 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
316 else if (S_ISFIFO(buf.st_mode))
317 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
318 else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
319 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
320 else
15411c0c 321 q = -EOPNOTSUPP;
849958d1 322
e156347e
LP
323 if (q == -EEXIST && merge)
324 q = 0;
325
849958d1
LP
326 if (q < 0)
327 r = q;
328 }
329
330 return r;
331}
332
f2cbe59e 333int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
849958d1
LP
334 struct stat st;
335
336 assert(from);
337 assert(to);
338
f2cbe59e 339 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
849958d1
LP
340 return -errno;
341
342 if (S_ISREG(st.st_mode))
f2cbe59e 343 return fd_copy_regular(fdf, from, &st, fdt, to);
849958d1 344 else if (S_ISDIR(st.st_mode))
f2cbe59e 345 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
849958d1 346 else if (S_ISLNK(st.st_mode))
f2cbe59e 347 return fd_copy_symlink(fdf, from, &st, fdt, to);
849958d1 348 else if (S_ISFIFO(st.st_mode))
f2cbe59e 349 return fd_copy_fifo(fdf, from, &st, fdt, to);
849958d1 350 else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
f2cbe59e 351 return fd_copy_node(fdf, from, &st, fdt, to);
849958d1 352 else
15411c0c 353 return -EOPNOTSUPP;
849958d1
LP
354}
355
f2cbe59e
LP
356int copy_tree(const char *from, const char *to, bool merge) {
357 return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
358}
359
360int copy_directory_fd(int dirfd, const char *to, bool merge) {
d7c7c334
LP
361
362 struct stat st;
363
364 assert(dirfd >= 0);
365 assert(to);
366
367 if (fstat(dirfd, &st) < 0)
368 return -errno;
369
370 if (!S_ISDIR(st.st_mode))
371 return -ENOTDIR;
372
373 return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
374}
375
7430ec6a 376int copy_file_fd(const char *from, int fdt, bool try_reflink) {
cda134ab 377 _cleanup_close_ int fdf = -1;
e6bd041c 378 int r;
849958d1
LP
379
380 assert(from);
cda134ab 381 assert(fdt >= 0);
849958d1
LP
382
383 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
384 if (fdf < 0)
385 return -errno;
386
59f448cf 387 r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
e6bd041c
LP
388
389 (void) copy_times(fdf, fdt);
390 (void) copy_xattr(fdf, fdt);
391
392 return r;
cda134ab
LP
393}
394
45030287 395int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
a7f7d1bd 396 int fdt = -1, r;
cda134ab
LP
397
398 assert(from);
399 assert(to);
400
ebd93cb6
LP
401 RUN_WITH_UMASK(0000) {
402 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
403 if (fdt < 0)
404 return -errno;
405 }
849958d1 406
f2068bcc 407 if (chattr_flags != 0)
1ed8f8c1 408 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
f2068bcc 409
7430ec6a 410 r = copy_file_fd(from, fdt, true);
849958d1 411 if (r < 0) {
cda134ab 412 close(fdt);
849958d1
LP
413 unlink(to);
414 return r;
415 }
416
cda134ab
LP
417 if (close(fdt) < 0) {
418 unlink_noerrno(to);
419 return -errno;
849958d1
LP
420 }
421
422 return 0;
423}
e6bd041c 424
45030287 425int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
a7f7d1bd 426 _cleanup_free_ char *t = NULL;
ebd93cb6
LP
427 int r;
428
429 assert(from);
430 assert(to);
431
14bcf25c 432 r = tempfn_random(to, NULL, &t);
ebd93cb6
LP
433 if (r < 0)
434 return r;
435
f2068bcc 436 r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
ebd93cb6
LP
437 if (r < 0)
438 return r;
439
f85ef957
AC
440 if (replace) {
441 r = renameat(AT_FDCWD, t, AT_FDCWD, to);
442 if (r < 0)
443 r = -errno;
444 } else
445 r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
446 if (r < 0) {
447 (void) unlink_noerrno(t);
448 return r;
ebd93cb6
LP
449 }
450
451 return 0;
452}
453
e6bd041c
LP
454int copy_times(int fdf, int fdt) {
455 struct timespec ut[2];
456 struct stat st;
a7f7d1bd 457 usec_t crtime = 0;
e6bd041c
LP
458
459 assert(fdf >= 0);
460 assert(fdt >= 0);
461
462 if (fstat(fdf, &st) < 0)
463 return -errno;
464
465 ut[0] = st.st_atim;
466 ut[1] = st.st_mtim;
467
468 if (futimens(fdt, ut) < 0)
469 return -errno;
470
471 if (fd_getcrtime(fdf, &crtime) >= 0)
472 (void) fd_setcrtime(fdt, crtime);
473
474 return 0;
475}
476
477int copy_xattr(int fdf, int fdt) {
478 _cleanup_free_ char *bufa = NULL, *bufb = NULL;
479 size_t sza = 100, szb = 100;
480 ssize_t n;
481 int ret = 0;
482 const char *p;
483
484 for (;;) {
485 bufa = malloc(sza);
486 if (!bufa)
487 return -ENOMEM;
488
489 n = flistxattr(fdf, bufa, sza);
490 if (n == 0)
491 return 0;
492 if (n > 0)
493 break;
494 if (errno != ERANGE)
495 return -errno;
496
497 sza *= 2;
498
97b11eed 499 bufa = mfree(bufa);
e6bd041c
LP
500 }
501
502 p = bufa;
503 while (n > 0) {
504 size_t l;
505
506 l = strlen(p);
507 assert(l < (size_t) n);
508
509 if (startswith(p, "user.")) {
510 ssize_t m;
511
512 if (!bufb) {
513 bufb = malloc(szb);
514 if (!bufb)
515 return -ENOMEM;
516 }
517
518 m = fgetxattr(fdf, p, bufb, szb);
519 if (m < 0) {
520 if (errno == ERANGE) {
521 szb *= 2;
97b11eed 522 bufb = mfree(bufb);
e6bd041c
LP
523 continue;
524 }
525
526 return -errno;
527 }
528
529 if (fsetxattr(fdt, p, bufb, m, 0) < 0)
530 ret = -errno;
531 }
532
533 p += l + 1;
534 n -= l + 1;
535 }
536
537 return ret;
538}