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