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