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