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