]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
849958d1 LP |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2014 Lennart Poettering | |
849958d1 LP |
6 | ***/ |
7 | ||
11c3a366 TA |
8 | #include <dirent.h> |
9 | #include <errno.h> | |
10 | #include <fcntl.h> | |
11 | #include <stddef.h> | |
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <string.h> | |
cda134ab | 15 | #include <sys/sendfile.h> |
11c3a366 | 16 | #include <sys/stat.h> |
e6bd041c | 17 | #include <sys/xattr.h> |
11c3a366 TA |
18 | #include <time.h> |
19 | #include <unistd.h> | |
cda134ab | 20 | |
b5efdb8a | 21 | #include "alloc-util.h" |
d7c7c334 | 22 | #include "btrfs-util.h" |
c8b3094d | 23 | #include "chattr-util.h" |
3ffd4af2 | 24 | #include "copy.h" |
a0956174 | 25 | #include "dirent-util.h" |
3ffd4af2 | 26 | #include "fd-util.h" |
0d39fa9c | 27 | #include "fileio.h" |
f4f15635 | 28 | #include "fs-util.h" |
c004493c | 29 | #include "io-util.h" |
11c3a366 | 30 | #include "macro.h" |
a44202e9 | 31 | #include "missing.h" |
07630cea | 32 | #include "string-util.h" |
8420fa3a | 33 | #include "strv.h" |
93cc7779 | 34 | #include "time-util.h" |
affb60b1 | 35 | #include "umask-util.h" |
d01cd401 | 36 | #include "user-util.h" |
89a5a90c | 37 | #include "xattr-util.h" |
849958d1 | 38 | |
00a8cf77 | 39 | #define COPY_BUFFER_SIZE (16*1024u) |
f2cbe59e | 40 | |
a44202e9 ZJS |
41 | static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, |
42 | int fd_out, loff_t *off_out, | |
43 | size_t len, | |
44 | unsigned int flags) { | |
45 | static int have = -1; | |
46 | ssize_t r; | |
47 | ||
48 | if (have == false) | |
49 | return -ENOSYS; | |
50 | ||
51 | r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); | |
52 | if (_unlikely_(have < 0)) | |
53 | have = r >= 0 || errno != ENOSYS; | |
54 | if (r >= 0) | |
55 | return r; | |
56 | else | |
57 | return -errno; | |
58 | } | |
59 | ||
e0c5c7d8 LP |
60 | enum { |
61 | FD_IS_NO_PIPE, | |
62 | FD_IS_BLOCKING_PIPE, | |
63 | FD_IS_NONBLOCKING_PIPE, | |
64 | }; | |
65 | ||
66 | static int fd_is_nonblock_pipe(int fd) { | |
67 | struct stat st; | |
68 | int flags; | |
69 | ||
70 | /* Checks whether the specified file descriptor refers to a pipe, and if so if is has O_NONBLOCK set. */ | |
71 | ||
72 | if (fstat(fd, &st) < 0) | |
73 | return -errno; | |
74 | ||
75 | if (!S_ISFIFO(st.st_mode)) | |
76 | return FD_IS_NO_PIPE; | |
77 | ||
78 | flags = fcntl(fd, F_GETFL); | |
79 | if (flags < 0) | |
80 | return -errno; | |
81 | ||
82 | return (flags & O_NONBLOCK) == O_NONBLOCK ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE; | |
83 | } | |
84 | ||
7a23c7fd LP |
85 | int copy_bytes_full( |
86 | int fdf, int fdt, | |
87 | uint64_t max_bytes, | |
88 | CopyFlags copy_flags, | |
89 | void **ret_remains, | |
90 | size_t *ret_remains_size) { | |
91 | ||
a44202e9 | 92 | bool try_cfr = true, try_sendfile = true, try_splice = true; |
e0c5c7d8 | 93 | int r, nonblock_pipe = -1; |
7c2da2ca | 94 | size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ |
cda134ab | 95 | |
849958d1 LP |
96 | assert(fdf >= 0); |
97 | assert(fdt >= 0); | |
98 | ||
78ba8cf7 LP |
99 | /* Tries to copy bytes from the file descriptor 'fdf' to 'fdt' in the smartest possible way. Copies a maximum |
100 | * of 'max_bytes', which may be specified as UINT64_MAX, in which no maximum is applied. Returns negative on | |
7a23c7fd LP |
101 | * error, zero if EOF is hit before the bytes limit is hit and positive otherwise. If the copy fails for some |
102 | * reason but we read but didn't yet write some data an ret_remains/ret_remains_size is not NULL, then it will | |
103 | * be initialized with an allocated buffer containing this "remaining" data. Note that these two parameters are | |
104 | * initialized with a valid buffer only on failure and only if there's actually data already read. Otherwise | |
105 | * these parameters if non-NULL are set to NULL. */ | |
106 | ||
107 | if (ret_remains) | |
108 | *ret_remains = NULL; | |
109 | if (ret_remains_size) | |
110 | *ret_remains_size = 0; | |
78ba8cf7 | 111 | |
5de6e116 LP |
112 | /* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of |
113 | * source and destination first. */ | |
114 | if ((copy_flags & COPY_REFLINK)) { | |
115 | off_t foffset; | |
116 | ||
117 | foffset = lseek(fdf, 0, SEEK_CUR); | |
118 | if (foffset >= 0) { | |
119 | off_t toffset; | |
120 | ||
121 | toffset = lseek(fdt, 0, SEEK_CUR); | |
122 | if (toffset >= 0) { | |
123 | ||
124 | if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX) | |
125 | r = btrfs_reflink(fdf, fdt); /* full file reflink */ | |
126 | else | |
127 | r = btrfs_clone_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */ | |
128 | if (r >= 0) { | |
129 | off_t t; | |
130 | ||
131 | /* This worked, yay! Now — to be fully correct — let's adjust the file pointers */ | |
132 | if (max_bytes == UINT64_MAX) { | |
133 | ||
134 | /* We cloned to the end of the source file, let's position the read | |
135 | * pointer there, and query it at the same time. */ | |
136 | t = lseek(fdf, 0, SEEK_END); | |
137 | if (t < 0) | |
138 | return -errno; | |
139 | if (t < foffset) | |
140 | return -ESPIPE; | |
141 | ||
142 | /* Let's adjust the destination file write pointer by the same number | |
143 | * of bytes. */ | |
144 | t = lseek(fdt, toffset + (t - foffset), SEEK_SET); | |
145 | if (t < 0) | |
146 | return -errno; | |
147 | ||
148 | return 0; /* we copied the whole thing, hence hit EOF, return 0 */ | |
149 | } else { | |
150 | t = lseek(fdf, foffset + max_bytes, SEEK_SET); | |
151 | if (t < 0) | |
152 | return -errno; | |
153 | ||
154 | t = lseek(fdt, toffset + max_bytes, SEEK_SET); | |
155 | if (t < 0) | |
156 | return -errno; | |
157 | ||
158 | return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */ | |
159 | } | |
160 | } | |
161 | ||
162 | log_debug_errno(r, "Reflinking didn't work, falling back to non-reflink copying: %m"); | |
163 | } | |
164 | } | |
0254b455 LP |
165 | } |
166 | ||
849958d1 | 167 | for (;;) { |
cda134ab | 168 | ssize_t n; |
93240d3a | 169 | |
59f448cf | 170 | if (max_bytes != (uint64_t) -1) { |
93240d3a | 171 | if (max_bytes <= 0) |
f6d9c616 | 172 | return 1; /* return > 0 if we hit the max_bytes limit */ |
93240d3a | 173 | |
d219849e ZJS |
174 | if (m > max_bytes) |
175 | m = max_bytes; | |
93240d3a LP |
176 | } |
177 | ||
a44202e9 ZJS |
178 | /* First try copy_file_range(), unless we already tried */ |
179 | if (try_cfr) { | |
180 | n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); | |
181 | if (n < 0) { | |
6402d5c6 | 182 | if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF)) |
a44202e9 ZJS |
183 | return n; |
184 | ||
185 | try_cfr = false; | |
186 | /* use fallback below */ | |
187 | } else if (n == 0) /* EOF */ | |
188 | break; | |
189 | else | |
190 | /* Success! */ | |
191 | goto next; | |
192 | } | |
193 | ||
cda134ab LP |
194 | /* First try sendfile(), unless we already tried */ |
195 | if (try_sendfile) { | |
cda134ab LP |
196 | n = sendfile(fdt, fdf, NULL, m); |
197 | if (n < 0) { | |
00a8cf77 | 198 | if (!IN_SET(errno, EINVAL, ENOSYS)) |
cda134ab LP |
199 | return -errno; |
200 | ||
201 | try_sendfile = false; | |
202 | /* use fallback below */ | |
203 | } else if (n == 0) /* EOF */ | |
204 | break; | |
00a8cf77 | 205 | else |
81d20007 LP |
206 | /* Success! */ |
207 | goto next; | |
208 | } | |
209 | ||
e0c5c7d8 LP |
210 | /* Then try splice, unless we already tried. */ |
211 | if (try_splice) { | |
212 | ||
213 | /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file | |
214 | * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the | |
215 | * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and | |
216 | * check if either of the specified fds are a pipe, and if so, let's pass the flag | |
217 | * automatically, depending on O_NONBLOCK being set. | |
218 | * | |
219 | * Here's a twist though: when we use it to move data between two pipes of which one has | |
220 | * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK | |
221 | * behaviour. Hence in that case we can't use splice() and still guarantee systematic | |
222 | * O_NONBLOCK behaviour, hence don't. */ | |
223 | ||
224 | if (nonblock_pipe < 0) { | |
225 | int a, b; | |
226 | ||
227 | /* Check if either of these fds is a pipe, and if so non-blocking or not */ | |
228 | a = fd_is_nonblock_pipe(fdf); | |
229 | if (a < 0) | |
230 | return a; | |
231 | ||
232 | b = fd_is_nonblock_pipe(fdt); | |
233 | if (b < 0) | |
234 | return b; | |
235 | ||
236 | if ((a == FD_IS_NO_PIPE && b == FD_IS_NO_PIPE) || | |
237 | (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) || | |
238 | (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE)) | |
239 | ||
240 | /* splice() only works if one of the fds is a pipe. If neither is, let's skip | |
241 | * this step right-away. As mentioned above, if one of the two fds refers to a | |
242 | * blocking pipe and the other to a non-blocking pipe, we can't use splice() | |
243 | * either, hence don't try either. This hence means we can only use splice() if | |
244 | * either only one of the two fds is a pipe, or if both are pipes with the same | |
245 | * nonblocking flag setting. */ | |
246 | ||
247 | try_splice = false; | |
248 | else | |
249 | nonblock_pipe = a == FD_IS_NONBLOCKING_PIPE || b == FD_IS_NONBLOCKING_PIPE; | |
250 | } | |
251 | } | |
252 | ||
81d20007 | 253 | if (try_splice) { |
e0c5c7d8 | 254 | n = splice(fdf, NULL, fdt, NULL, m, nonblock_pipe ? SPLICE_F_NONBLOCK : 0); |
81d20007 | 255 | if (n < 0) { |
00a8cf77 | 256 | if (!IN_SET(errno, EINVAL, ENOSYS)) |
81d20007 LP |
257 | return -errno; |
258 | ||
259 | try_splice = false; | |
260 | /* use fallback below */ | |
261 | } else if (n == 0) /* EOF */ | |
262 | break; | |
00a8cf77 | 263 | else |
81d20007 | 264 | /* Success! */ |
cda134ab LP |
265 | goto next; |
266 | } | |
267 | ||
268 | /* As a fallback just copy bits by hand */ | |
269 | { | |
7a23c7fd LP |
270 | uint8_t buf[MIN(m, COPY_BUFFER_SIZE)], *p = buf; |
271 | ssize_t z; | |
849958d1 | 272 | |
00a8cf77 | 273 | n = read(fdf, buf, sizeof buf); |
cda134ab LP |
274 | if (n < 0) |
275 | return -errno; | |
276 | if (n == 0) /* EOF */ | |
277 | break; | |
278 | ||
7a23c7fd LP |
279 | z = (size_t) n; |
280 | do { | |
281 | ssize_t k; | |
282 | ||
283 | k = write(fdt, p, z); | |
284 | if (k < 0) { | |
285 | r = -errno; | |
286 | ||
287 | if (ret_remains) { | |
288 | void *copy; | |
289 | ||
290 | copy = memdup(p, z); | |
291 | if (!copy) | |
292 | return -ENOMEM; | |
293 | ||
294 | *ret_remains = copy; | |
295 | } | |
296 | ||
297 | if (ret_remains_size) | |
298 | *ret_remains_size = z; | |
299 | ||
300 | return r; | |
301 | } | |
302 | ||
303 | assert(k <= z); | |
304 | z -= k; | |
305 | p += k; | |
306 | } while (z > 0); | |
cda134ab | 307 | } |
93240d3a | 308 | |
cda134ab | 309 | next: |
59f448cf LP |
310 | if (max_bytes != (uint64_t) -1) { |
311 | assert(max_bytes >= (uint64_t) n); | |
93240d3a LP |
312 | max_bytes -= n; |
313 | } | |
00a8cf77 ZJS |
314 | /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, |
315 | * so reduce our maximum by the amount we already copied, | |
316 | * but don't go below our copy buffer size, unless we are | |
61233823 | 317 | * close the limit of bytes we are allowed to copy. */ |
00a8cf77 | 318 | m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); |
849958d1 LP |
319 | } |
320 | ||
f6d9c616 | 321 | return 0; /* return 0 if we hit EOF earlier than the size limit */ |
849958d1 LP |
322 | } |
323 | ||
d01cd401 LP |
324 | static int fd_copy_symlink( |
325 | int df, | |
326 | const char *from, | |
327 | const struct stat *st, | |
328 | int dt, | |
329 | const char *to, | |
330 | uid_t override_uid, | |
331 | gid_t override_gid, | |
332 | CopyFlags copy_flags) { | |
333 | ||
849958d1 LP |
334 | _cleanup_free_ char *target = NULL; |
335 | int r; | |
336 | ||
337 | assert(from); | |
338 | assert(st); | |
339 | assert(to); | |
340 | ||
341 | r = readlinkat_malloc(df, from, &target); | |
342 | if (r < 0) | |
343 | return r; | |
344 | ||
e156347e | 345 | if (symlinkat(target, dt, to) < 0) |
849958d1 | 346 | return -errno; |
849958d1 | 347 | |
d01cd401 LP |
348 | if (fchownat(dt, to, |
349 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
350 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
351 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
352 | return -errno; |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
d01cd401 LP |
357 | static int fd_copy_regular( |
358 | int df, | |
359 | const char *from, | |
360 | const struct stat *st, | |
361 | int dt, | |
362 | const char *to, | |
363 | uid_t override_uid, | |
364 | gid_t override_gid, | |
365 | CopyFlags copy_flags) { | |
366 | ||
849958d1 | 367 | _cleanup_close_ int fdf = -1, fdt = -1; |
ebd93cb6 | 368 | struct timespec ts[2]; |
849958d1 LP |
369 | int r, q; |
370 | ||
371 | assert(from); | |
372 | assert(st); | |
373 | assert(to); | |
374 | ||
375 | fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
376 | if (fdf < 0) | |
377 | return -errno; | |
378 | ||
379 | fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777); | |
e156347e | 380 | if (fdt < 0) |
849958d1 | 381 | return -errno; |
849958d1 | 382 | |
1c876927 | 383 | r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); |
849958d1 | 384 | if (r < 0) { |
7b938dfb | 385 | (void) unlinkat(dt, to, 0); |
849958d1 LP |
386 | return r; |
387 | } | |
388 | ||
d01cd401 LP |
389 | if (fchown(fdt, |
390 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
391 | gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) | |
849958d1 LP |
392 | r = -errno; |
393 | ||
394 | if (fchmod(fdt, st->st_mode & 07777) < 0) | |
395 | r = -errno; | |
396 | ||
ebd93cb6 LP |
397 | ts[0] = st->st_atim; |
398 | ts[1] = st->st_mtim; | |
399 | (void) futimens(fdt, ts); | |
e6bd041c LP |
400 | (void) copy_xattr(fdf, fdt); |
401 | ||
849958d1 LP |
402 | q = close(fdt); |
403 | fdt = -1; | |
404 | ||
405 | if (q < 0) { | |
406 | r = -errno; | |
7b938dfb | 407 | (void) unlinkat(dt, to, 0); |
849958d1 LP |
408 | } |
409 | ||
410 | return r; | |
411 | } | |
412 | ||
d01cd401 LP |
413 | static int fd_copy_fifo( |
414 | int df, | |
415 | const char *from, | |
416 | const struct stat *st, | |
417 | int dt, | |
418 | const char *to, | |
419 | uid_t override_uid, | |
420 | gid_t override_gid, | |
421 | CopyFlags copy_flags) { | |
849958d1 LP |
422 | int r; |
423 | ||
424 | assert(from); | |
425 | assert(st); | |
426 | assert(to); | |
427 | ||
428 | r = mkfifoat(dt, to, st->st_mode & 07777); | |
e156347e | 429 | if (r < 0) |
849958d1 | 430 | return -errno; |
849958d1 | 431 | |
d01cd401 LP |
432 | if (fchownat(dt, to, |
433 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
434 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
435 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
436 | r = -errno; |
437 | ||
438 | if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) | |
439 | r = -errno; | |
440 | ||
441 | return r; | |
442 | } | |
443 | ||
d01cd401 LP |
444 | static int fd_copy_node( |
445 | int df, | |
446 | const char *from, | |
447 | const struct stat *st, | |
448 | int dt, | |
449 | const char *to, | |
450 | uid_t override_uid, | |
451 | gid_t override_gid, | |
452 | CopyFlags copy_flags) { | |
849958d1 LP |
453 | int r; |
454 | ||
455 | assert(from); | |
456 | assert(st); | |
457 | assert(to); | |
458 | ||
459 | r = mknodat(dt, to, st->st_mode, st->st_rdev); | |
e156347e | 460 | if (r < 0) |
849958d1 | 461 | return -errno; |
849958d1 | 462 | |
d01cd401 LP |
463 | if (fchownat(dt, to, |
464 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
465 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
466 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
467 | r = -errno; |
468 | ||
469 | if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) | |
470 | r = -errno; | |
471 | ||
472 | return r; | |
473 | } | |
474 | ||
d7c7c334 LP |
475 | static int fd_copy_directory( |
476 | int df, | |
477 | const char *from, | |
478 | const struct stat *st, | |
479 | int dt, | |
480 | const char *to, | |
481 | dev_t original_device, | |
d01cd401 LP |
482 | uid_t override_uid, |
483 | gid_t override_gid, | |
1c876927 | 484 | CopyFlags copy_flags) { |
d7c7c334 | 485 | |
849958d1 LP |
486 | _cleanup_close_ int fdf = -1, fdt = -1; |
487 | _cleanup_closedir_ DIR *d = NULL; | |
488 | struct dirent *de; | |
489 | bool created; | |
490 | int r; | |
491 | ||
849958d1 LP |
492 | assert(st); |
493 | assert(to); | |
494 | ||
d7c7c334 LP |
495 | if (from) |
496 | fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
497 | else | |
498 | fdf = fcntl(df, F_DUPFD_CLOEXEC, 3); | |
b498c53d LP |
499 | if (fdf < 0) |
500 | return -errno; | |
849958d1 LP |
501 | |
502 | d = fdopendir(fdf); | |
503 | if (!d) | |
504 | return -errno; | |
505 | fdf = -1; | |
506 | ||
507 | r = mkdirat(dt, to, st->st_mode & 07777); | |
508 | if (r >= 0) | |
509 | created = true; | |
1c876927 | 510 | else if (errno == EEXIST && (copy_flags & COPY_MERGE)) |
849958d1 LP |
511 | created = false; |
512 | else | |
513 | return -errno; | |
514 | ||
515 | fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
516 | if (fdt < 0) | |
517 | return -errno; | |
518 | ||
2c455af4 LP |
519 | r = 0; |
520 | ||
8420fa3a | 521 | FOREACH_DIRENT_ALL(de, d, return -errno) { |
849958d1 LP |
522 | struct stat buf; |
523 | int q; | |
524 | ||
49bfc877 | 525 | if (dot_or_dot_dot(de->d_name)) |
8420fa3a LP |
526 | continue; |
527 | ||
849958d1 LP |
528 | if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) { |
529 | r = -errno; | |
530 | continue; | |
531 | } | |
532 | ||
533 | if (buf.st_dev != original_device) | |
534 | continue; | |
535 | ||
536 | if (S_ISREG(buf.st_mode)) | |
d01cd401 | 537 | q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 538 | else if (S_ISDIR(buf.st_mode)) |
d01cd401 | 539 | q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags); |
849958d1 | 540 | else if (S_ISLNK(buf.st_mode)) |
d01cd401 | 541 | q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 542 | else if (S_ISFIFO(buf.st_mode)) |
d01cd401 | 543 | q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
0e2b2cac | 544 | else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode)) |
d01cd401 | 545 | q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 546 | else |
15411c0c | 547 | q = -EOPNOTSUPP; |
849958d1 | 548 | |
1c876927 | 549 | if (q == -EEXIST && (copy_flags & COPY_MERGE)) |
e156347e LP |
550 | q = 0; |
551 | ||
849958d1 LP |
552 | if (q < 0) |
553 | r = q; | |
554 | } | |
555 | ||
3b8483c0 LP |
556 | if (created) { |
557 | struct timespec ut[2] = { | |
558 | st->st_atim, | |
559 | st->st_mtim | |
560 | }; | |
561 | ||
d01cd401 LP |
562 | if (fchown(fdt, |
563 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
564 | gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) | |
3b8483c0 LP |
565 | r = -errno; |
566 | ||
567 | if (fchmod(fdt, st->st_mode & 07777) < 0) | |
568 | r = -errno; | |
569 | ||
570 | (void) copy_xattr(dirfd(d), fdt); | |
571 | (void) futimens(fdt, ut); | |
572 | } | |
573 | ||
849958d1 LP |
574 | return r; |
575 | } | |
576 | ||
d01cd401 | 577 | int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { |
849958d1 LP |
578 | struct stat st; |
579 | ||
580 | assert(from); | |
581 | assert(to); | |
582 | ||
f2cbe59e | 583 | if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0) |
849958d1 LP |
584 | return -errno; |
585 | ||
586 | if (S_ISREG(st.st_mode)) | |
d01cd401 | 587 | return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 588 | else if (S_ISDIR(st.st_mode)) |
d01cd401 | 589 | return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags); |
849958d1 | 590 | else if (S_ISLNK(st.st_mode)) |
d01cd401 | 591 | return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 592 | else if (S_ISFIFO(st.st_mode)) |
d01cd401 | 593 | return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
0e2b2cac | 594 | else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) |
d01cd401 | 595 | return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 596 | else |
15411c0c | 597 | return -EOPNOTSUPP; |
849958d1 LP |
598 | } |
599 | ||
d01cd401 LP |
600 | int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { |
601 | return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags); | |
f2cbe59e LP |
602 | } |
603 | ||
1c876927 | 604 | int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { |
d7c7c334 LP |
605 | struct stat st; |
606 | ||
607 | assert(dirfd >= 0); | |
608 | assert(to); | |
609 | ||
610 | if (fstat(dirfd, &st) < 0) | |
611 | return -errno; | |
612 | ||
613 | if (!S_ISDIR(st.st_mode)) | |
614 | return -ENOTDIR; | |
615 | ||
d01cd401 | 616 | return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); |
d7c7c334 LP |
617 | } |
618 | ||
1c876927 | 619 | int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { |
9a50e3ca LP |
620 | struct stat st; |
621 | ||
622 | assert(from); | |
623 | assert(to); | |
624 | ||
625 | if (lstat(from, &st) < 0) | |
626 | return -errno; | |
627 | ||
628 | if (!S_ISDIR(st.st_mode)) | |
629 | return -ENOTDIR; | |
630 | ||
d01cd401 | 631 | return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); |
9a50e3ca LP |
632 | } |
633 | ||
1c876927 | 634 | int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { |
cda134ab | 635 | _cleanup_close_ int fdf = -1; |
e6bd041c | 636 | int r; |
849958d1 LP |
637 | |
638 | assert(from); | |
cda134ab | 639 | assert(fdt >= 0); |
849958d1 LP |
640 | |
641 | fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); | |
642 | if (fdf < 0) | |
643 | return -errno; | |
644 | ||
1c876927 | 645 | r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); |
e6bd041c LP |
646 | |
647 | (void) copy_times(fdf, fdt); | |
648 | (void) copy_xattr(fdf, fdt); | |
649 | ||
650 | return r; | |
cda134ab LP |
651 | } |
652 | ||
1c876927 | 653 | int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { |
a7f7d1bd | 654 | int fdt = -1, r; |
cda134ab LP |
655 | |
656 | assert(from); | |
657 | assert(to); | |
658 | ||
ebd93cb6 LP |
659 | RUN_WITH_UMASK(0000) { |
660 | fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); | |
661 | if (fdt < 0) | |
662 | return -errno; | |
663 | } | |
849958d1 | 664 | |
f2068bcc | 665 | if (chattr_flags != 0) |
1ed8f8c1 | 666 | (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); |
f2068bcc | 667 | |
1c876927 | 668 | r = copy_file_fd(from, fdt, copy_flags); |
849958d1 | 669 | if (r < 0) { |
cda134ab | 670 | close(fdt); |
7b938dfb | 671 | (void) unlink(to); |
849958d1 LP |
672 | return r; |
673 | } | |
674 | ||
cda134ab LP |
675 | if (close(fdt) < 0) { |
676 | unlink_noerrno(to); | |
677 | return -errno; | |
849958d1 LP |
678 | } |
679 | ||
680 | return 0; | |
681 | } | |
e6bd041c | 682 | |
1c876927 | 683 | int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { |
a7f7d1bd | 684 | _cleanup_free_ char *t = NULL; |
ebd93cb6 LP |
685 | int r; |
686 | ||
687 | assert(from); | |
688 | assert(to); | |
689 | ||
14bcf25c | 690 | r = tempfn_random(to, NULL, &t); |
ebd93cb6 LP |
691 | if (r < 0) |
692 | return r; | |
693 | ||
1c876927 | 694 | r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags); |
ebd93cb6 LP |
695 | if (r < 0) |
696 | return r; | |
697 | ||
1c876927 | 698 | if (copy_flags & COPY_REPLACE) { |
f85ef957 AC |
699 | r = renameat(AT_FDCWD, t, AT_FDCWD, to); |
700 | if (r < 0) | |
701 | r = -errno; | |
702 | } else | |
703 | r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to); | |
704 | if (r < 0) { | |
ce21ed5c | 705 | (void) unlink(t); |
f85ef957 | 706 | return r; |
ebd93cb6 LP |
707 | } |
708 | ||
709 | return 0; | |
710 | } | |
711 | ||
e6bd041c LP |
712 | int copy_times(int fdf, int fdt) { |
713 | struct timespec ut[2]; | |
714 | struct stat st; | |
a7f7d1bd | 715 | usec_t crtime = 0; |
e6bd041c LP |
716 | |
717 | assert(fdf >= 0); | |
718 | assert(fdt >= 0); | |
719 | ||
720 | if (fstat(fdf, &st) < 0) | |
721 | return -errno; | |
722 | ||
723 | ut[0] = st.st_atim; | |
724 | ut[1] = st.st_mtim; | |
725 | ||
726 | if (futimens(fdt, ut) < 0) | |
727 | return -errno; | |
728 | ||
729 | if (fd_getcrtime(fdf, &crtime) >= 0) | |
730 | (void) fd_setcrtime(fdt, crtime); | |
731 | ||
732 | return 0; | |
733 | } | |
734 | ||
735 | int copy_xattr(int fdf, int fdt) { | |
736 | _cleanup_free_ char *bufa = NULL, *bufb = NULL; | |
737 | size_t sza = 100, szb = 100; | |
738 | ssize_t n; | |
739 | int ret = 0; | |
740 | const char *p; | |
741 | ||
742 | for (;;) { | |
743 | bufa = malloc(sza); | |
744 | if (!bufa) | |
745 | return -ENOMEM; | |
746 | ||
747 | n = flistxattr(fdf, bufa, sza); | |
748 | if (n == 0) | |
749 | return 0; | |
750 | if (n > 0) | |
751 | break; | |
752 | if (errno != ERANGE) | |
753 | return -errno; | |
754 | ||
755 | sza *= 2; | |
756 | ||
97b11eed | 757 | bufa = mfree(bufa); |
e6bd041c LP |
758 | } |
759 | ||
760 | p = bufa; | |
761 | while (n > 0) { | |
762 | size_t l; | |
763 | ||
764 | l = strlen(p); | |
765 | assert(l < (size_t) n); | |
766 | ||
767 | if (startswith(p, "user.")) { | |
768 | ssize_t m; | |
769 | ||
770 | if (!bufb) { | |
771 | bufb = malloc(szb); | |
772 | if (!bufb) | |
773 | return -ENOMEM; | |
774 | } | |
775 | ||
776 | m = fgetxattr(fdf, p, bufb, szb); | |
777 | if (m < 0) { | |
778 | if (errno == ERANGE) { | |
779 | szb *= 2; | |
97b11eed | 780 | bufb = mfree(bufb); |
e6bd041c LP |
781 | continue; |
782 | } | |
783 | ||
784 | return -errno; | |
785 | } | |
786 | ||
787 | if (fsetxattr(fdt, p, bufb, m, 0) < 0) | |
788 | ret = -errno; | |
789 | } | |
790 | ||
791 | p += l + 1; | |
792 | n -= l + 1; | |
793 | } | |
794 | ||
795 | return ret; | |
796 | } |