Bug Summary

File:build-scan/../src/basic/copy.c
Warning:line 404, column 9
Value stored to 'fdt' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name copy.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/copy.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <dirent.h>
4#include <errno(*__errno_location ()).h>
5#include <fcntl.h>
6#include <stddef.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/sendfile.h>
11#include <sys/stat.h>
12#include <sys/xattr.h>
13#include <time.h>
14#include <unistd.h>
15
16#include "alloc-util.h"
17#include "btrfs-util.h"
18#include "chattr-util.h"
19#include "copy.h"
20#include "dirent-util.h"
21#include "fd-util.h"
22#include "fileio.h"
23#include "fs-util.h"
24#include "io-util.h"
25#include "macro.h"
26#include "missing.h"
27#include "mount-util.h"
28#include "string-util.h"
29#include "strv.h"
30#include "time-util.h"
31#include "umask-util.h"
32#include "user-util.h"
33#include "xattr-util.h"
34
35#define COPY_BUFFER_SIZE(16U*1024U) (16U*1024U)
36
37/* A safety net for descending recursively into file system trees to copy. On Linux PATH_MAX is 4096, which means the
38 * deepest valid path one can build is around 2048, which we hence use as a safety net here, to not spin endlessly in
39 * case of bind mount cycles and suchlike. */
40#define COPY_DEPTH_MAX2048U 2048U
41
42static ssize_t try_copy_file_range(
43 int fd_in, loff_t *off_in,
44 int fd_out, loff_t *off_out,
45 size_t len,
46 unsigned int flags) {
47
48 static int have = -1;
49 ssize_t r;
50
51 if (have == 0)
52 return -ENOSYS38;
53
54 r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
55 if (have < 0)
56 have = r >= 0 || errno(*__errno_location ()) != ENOSYS38;
57 if (r < 0)
58 return -errno(*__errno_location ());
59
60 return r;
61}
62
63enum {
64 FD_IS_NO_PIPE,
65 FD_IS_BLOCKING_PIPE,
66 FD_IS_NONBLOCKING_PIPE,
67};
68
69static int fd_is_nonblock_pipe(int fd) {
70 struct stat st;
71 int flags;
72
73 /* Checks whether the specified file descriptor refers to a pipe, and if so if O_NONBLOCK is set. */
74
75 if (fstat(fd, &st) < 0)
76 return -errno(*__errno_location ());
77
78 if (!S_ISFIFO(st.st_mode)((((st.st_mode)) & 0170000) == (0010000)))
79 return FD_IS_NO_PIPE;
80
81 flags = fcntl(fd, F_GETFL3);
82 if (flags < 0)
83 return -errno(*__errno_location ());
84
85 return FLAGS_SET(flags, O_NONBLOCK)(((flags) & (04000)) == (04000)) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
86}
87
88int copy_bytes_full(
89 int fdf, int fdt,
90 uint64_t max_bytes,
91 CopyFlags copy_flags,
92 void **ret_remains,
93 size_t *ret_remains_size) {
94
95 bool_Bool try_cfr = true1, try_sendfile = true1, try_splice = true1;
96 int r, nonblock_pipe = -1;
97 size_t m = SSIZE_MAX9223372036854775807L; /* that is the maximum that sendfile and c_f_r accept */
98
99 assert(fdf >= 0)do { if ((__builtin_expect(!!(!(fdf >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fdf >= 0"), "../src/basic/copy.c", 99
, __PRETTY_FUNCTION__); } while (0)
;
100 assert(fdt >= 0)do { if ((__builtin_expect(!!(!(fdt >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fdt >= 0"), "../src/basic/copy.c", 100
, __PRETTY_FUNCTION__); } while (0)
;
101
102 /* Tries to copy bytes from the file descriptor 'fdf' to 'fdt' in the smartest possible way. Copies a maximum
103 * of 'max_bytes', which may be specified as UINT64_MAX, in which no maximum is applied. Returns negative on
104 * error, zero if EOF is hit before the bytes limit is hit and positive otherwise. If the copy fails for some
105 * reason but we read but didn't yet write some data an ret_remains/ret_remains_size is not NULL, then it will
106 * be initialized with an allocated buffer containing this "remaining" data. Note that these two parameters are
107 * initialized with a valid buffer only on failure and only if there's actually data already read. Otherwise
108 * these parameters if non-NULL are set to NULL. */
109
110 if (ret_remains)
111 *ret_remains = NULL((void*)0);
112 if (ret_remains_size)
113 *ret_remains_size = 0;
114
115 /* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of
116 * source and destination first. */
117 if ((copy_flags & COPY_REFLINK)) {
118 off_t foffset;
119
120 foffset = lseek(fdf, 0, SEEK_CUR1);
121 if (foffset >= 0) {
122 off_t toffset;
123
124 toffset = lseek(fdt, 0, SEEK_CUR1);
125 if (toffset >= 0) {
126
127 if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX(18446744073709551615UL))
128 r = btrfs_reflink(fdf, fdt); /* full file reflink */
129 else
130 r = btrfs_clone_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX(18446744073709551615UL) ? 0 : max_bytes); /* partial reflink */
131 if (r >= 0) {
132 off_t t;
133
134 /* This worked, yay! Now — to be fully correct — let's adjust the file pointers */
135 if (max_bytes == UINT64_MAX(18446744073709551615UL)) {
136
137 /* We cloned to the end of the source file, let's position the read
138 * pointer there, and query it at the same time. */
139 t = lseek(fdf, 0, SEEK_END2);
140 if (t < 0)
141 return -errno(*__errno_location ());
142 if (t < foffset)
143 return -ESPIPE29;
144
145 /* Let's adjust the destination file write pointer by the same number
146 * of bytes. */
147 t = lseek(fdt, toffset + (t - foffset), SEEK_SET0);
148 if (t < 0)
149 return -errno(*__errno_location ());
150
151 return 0; /* we copied the whole thing, hence hit EOF, return 0 */
152 } else {
153 t = lseek(fdf, foffset + max_bytes, SEEK_SET0);
154 if (t < 0)
155 return -errno(*__errno_location ());
156
157 t = lseek(fdt, toffset + max_bytes, SEEK_SET0);
158 if (t < 0)
159 return -errno(*__errno_location ());
160
161 return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */
162 }
163 }
164
165 log_debug_errno(r, "Reflinking didn't work, falling back to non-reflink copying: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/basic/copy.c", 165, __func__, "Reflinking didn't work, falling back to non-reflink copying: %m"
) : -abs(_e); })
;
166 }
167 }
168 }
169
170 for (;;) {
171 ssize_t n;
172
173 if (max_bytes <= 0)
174 return 1; /* return > 0 if we hit the max_bytes limit */
175
176 if (max_bytes != UINT64_MAX(18446744073709551615UL) && m > max_bytes)
177 m = max_bytes;
178
179 /* First try copy_file_range(), unless we already tried */
180 if (try_cfr) {
181 n = try_copy_file_range(fdf, NULL((void*)0), fdt, NULL((void*)0), m, 0u);
182 if (n < 0) {
183 if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-22, -38, -18, -9})/sizeof(int)]; switch
(n) { case -22: case -38: case -18: case -9: _found = 1; break
; default: break; } _found; })
)
184 return n;
185
186 try_cfr = false0;
187 /* use fallback below */
188 } else if (n == 0) /* EOF */
189 break;
190 else
191 /* Success! */
192 goto next;
193 }
194
195 /* First try sendfile(), unless we already tried */
196 if (try_sendfile) {
197 n = sendfile(fdt, fdf, NULL((void*)0), m);
198 if (n < 0) {
199 if (!IN_SET(errno, EINVAL, ENOSYS)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){22, 38})/sizeof(int)]; switch((*__errno_location
())) { case 22: case 38: _found = 1; break; default: break; }
_found; })
)
200 return -errno(*__errno_location ());
201
202 try_sendfile = false0;
203 /* use fallback below */
204 } else if (n == 0) /* EOF */
205 break;
206 else
207 /* Success! */
208 goto next;
209 }
210
211 /* Then try splice, unless we already tried. */
212 if (try_splice) {
213
214 /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file
215 * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the
216 * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and
217 * check if either of the specified fds are a pipe, and if so, let's pass the flag
218 * automatically, depending on O_NONBLOCK being set.
219 *
220 * Here's a twist though: when we use it to move data between two pipes of which one has
221 * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK
222 * behaviour. Hence in that case we can't use splice() and still guarantee systematic
223 * O_NONBLOCK behaviour, hence don't. */
224
225 if (nonblock_pipe < 0) {
226 int a, b;
227
228 /* Check if either of these fds is a pipe, and if so non-blocking or not */
229 a = fd_is_nonblock_pipe(fdf);
230 if (a < 0)
231 return a;
232
233 b = fd_is_nonblock_pipe(fdt);
234 if (b < 0)
235 return b;
236
237 if ((a == FD_IS_NO_PIPE && b == FD_IS_NO_PIPE) ||
238 (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) ||
239 (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE))
240
241 /* splice() only works if one of the fds is a pipe. If neither is, let's skip
242 * this step right-away. As mentioned above, if one of the two fds refers to a
243 * blocking pipe and the other to a non-blocking pipe, we can't use splice()
244 * either, hence don't try either. This hence means we can only use splice() if
245 * either only one of the two fds is a pipe, or if both are pipes with the same
246 * nonblocking flag setting. */
247
248 try_splice = false0;
249 else
250 nonblock_pipe = a == FD_IS_NONBLOCKING_PIPE || b == FD_IS_NONBLOCKING_PIPE;
251 }
252 }
253
254 if (try_splice) {
255 n = splice(fdf, NULL((void*)0), fdt, NULL((void*)0), m, nonblock_pipe ? SPLICE_F_NONBLOCK2 : 0);
256 if (n < 0) {
257 if (!IN_SET(errno, EINVAL, ENOSYS)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){22, 38})/sizeof(int)]; switch((*__errno_location
())) { case 22: case 38: _found = 1; break; default: break; }
_found; })
)
258 return -errno(*__errno_location ());
259
260 try_splice = false0;
261 /* use fallback below */
262 } else if (n == 0) /* EOF */
263 break;
264 else
265 /* Success! */
266 goto next;
267 }
268
269 /* As a fallback just copy bits by hand */
270 {
271 uint8_t buf[MIN(m, COPY_BUFFER_SIZE)__extension__ ({ const typeof((m)) __unique_prefix_A8 = ((m))
; const typeof(((16U*1024U))) __unique_prefix_B9 = (((16U*1024U
))); __unique_prefix_A8 < __unique_prefix_B9 ? __unique_prefix_A8
: __unique_prefix_B9; })
], *p = buf;
272 ssize_t z;
273
274 n = read(fdf, buf, sizeof buf);
275 if (n < 0)
276 return -errno(*__errno_location ());
277 if (n == 0) /* EOF */
278 break;
279
280 z = (size_t) n;
281 do {
282 ssize_t k;
283
284 k = write(fdt, p, z);
285 if (k < 0) {
286 r = -errno(*__errno_location ());
287
288 if (ret_remains) {
289 void *copy;
290
291 copy = memdup(p, z);
292 if (!copy)
293 return -ENOMEM12;
294
295 *ret_remains = copy;
296 }
297
298 if (ret_remains_size)
299 *ret_remains_size = z;
300
301 return r;
302 }
303
304 assert(k <= z)do { if ((__builtin_expect(!!(!(k <= z)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("k <= z"), "../src/basic/copy.c", 304
, __PRETTY_FUNCTION__); } while (0)
;
305 z -= k;
306 p += k;
307 } while (z > 0);
308 }
309
310 next:
311 if (max_bytes != (uint64_t) -1) {
312 assert(max_bytes >= (uint64_t) n)do { if ((__builtin_expect(!!(!(max_bytes >= (uint64_t) n)
),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("max_bytes >= (uint64_t) n"
), "../src/basic/copy.c", 312, __PRETTY_FUNCTION__); } while (
0)
;
313 max_bytes -= n;
314 }
315 /* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
316 * so reduce our maximum by the amount we already copied,
317 * but don't go below our copy buffer size, unless we are
318 * close the limit of bytes we are allowed to copy. */
319 m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n)__extension__ ({ const typeof((__extension__ ({ const typeof(
((16U*1024U))) __unique_prefix_A10 = (((16U*1024U))); const typeof
((max_bytes)) __unique_prefix_B11 = ((max_bytes)); __unique_prefix_A10
< __unique_prefix_B11 ? __unique_prefix_A10 : __unique_prefix_B11
; }))) __unique_prefix_A12 = ((__extension__ ({ const typeof(
((16U*1024U))) __unique_prefix_A10 = (((16U*1024U))); const typeof
((max_bytes)) __unique_prefix_B11 = ((max_bytes)); __unique_prefix_A10
< __unique_prefix_B11 ? __unique_prefix_A10 : __unique_prefix_B11
; }))); const typeof((m - n)) __unique_prefix_B13 = ((m - n))
; __unique_prefix_A12 > __unique_prefix_B13 ? __unique_prefix_A12
: __unique_prefix_B13; })
;
320 }
321
322 return 0; /* return 0 if we hit EOF earlier than the size limit */
323}
324
325static int fd_copy_symlink(
326 int df,
327 const char *from,
328 const struct stat *st,
329 int dt,
330 const char *to,
331 uid_t override_uid,
332 gid_t override_gid,
333 CopyFlags copy_flags) {
334
335 _cleanup_free___attribute__((cleanup(freep))) char *target = NULL((void*)0);
336 int r;
337
338 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 338, __PRETTY_FUNCTION__
); } while (0)
;
339 assert(st)do { if ((__builtin_expect(!!(!(st)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("st"), "../src/basic/copy.c", 339, __PRETTY_FUNCTION__
); } while (0)
;
340 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 340, __PRETTY_FUNCTION__
); } while (0)
;
341
342 r = readlinkat_malloc(df, from, &target);
343 if (r < 0)
344 return r;
345
346 if (symlinkat(target, dt, to) < 0)
347 return -errno(*__errno_location ());
348
349 if (fchownat(dt, to,
350 uid_is_valid(override_uid) ? override_uid : st->st_uid,
351 gid_is_valid(override_gid) ? override_gid : st->st_gid,
352 AT_SYMLINK_NOFOLLOW0x100) < 0)
353 return -errno(*__errno_location ());
354
355 return 0;
356}
357
358static int fd_copy_regular(
359 int df,
360 const char *from,
361 const struct stat *st,
362 int dt,
363 const char *to,
364 uid_t override_uid,
365 gid_t override_gid,
366 CopyFlags copy_flags) {
367
368 _cleanup_close___attribute__((cleanup(closep))) int fdf = -1, fdt = -1;
369 struct timespec ts[2];
370 int r, q;
371
372 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 372, __PRETTY_FUNCTION__
); } while (0)
;
373 assert(st)do { if ((__builtin_expect(!!(!(st)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("st"), "../src/basic/copy.c", 373, __PRETTY_FUNCTION__
); } while (0)
;
374 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 374, __PRETTY_FUNCTION__
); } while (0)
;
375
376 fdf = openat(df, from, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400|O_NOFOLLOW0400000);
377 if (fdf < 0)
378 return -errno(*__errno_location ());
379
380 fdt = openat(dt, to, O_WRONLY01|O_CREAT0100|O_EXCL0200|O_CLOEXEC02000000|O_NOCTTY0400|O_NOFOLLOW0400000, st->st_mode & 07777);
381 if (fdt < 0)
382 return -errno(*__errno_location ());
383
384 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
385 if (r < 0) {
386 (void) unlinkat(dt, to, 0);
387 return r;
388 }
389
390 if (fchown(fdt,
391 uid_is_valid(override_uid) ? override_uid : st->st_uid,
392 gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
393 r = -errno(*__errno_location ());
394
395 if (fchmod(fdt, st->st_mode & 07777) < 0)
396 r = -errno(*__errno_location ());
397
398 ts[0] = st->st_atim;
399 ts[1] = st->st_mtim;
400 (void) futimens(fdt, ts);
401 (void) copy_xattr(fdf, fdt);
402
403 q = close(fdt);
404 fdt = -1;
Value stored to 'fdt' is never read
405
406 if (q < 0) {
407 r = -errno(*__errno_location ());
408 (void) unlinkat(dt, to, 0);
409 }
410
411 return r;
412}
413
414static int fd_copy_fifo(
415 int df,
416 const char *from,
417 const struct stat *st,
418 int dt,
419 const char *to,
420 uid_t override_uid,
421 gid_t override_gid,
422 CopyFlags copy_flags) {
423 int r;
424
425 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 425, __PRETTY_FUNCTION__
); } while (0)
;
426 assert(st)do { if ((__builtin_expect(!!(!(st)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("st"), "../src/basic/copy.c", 426, __PRETTY_FUNCTION__
); } while (0)
;
427 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 427, __PRETTY_FUNCTION__
); } while (0)
;
428
429 r = mkfifoat(dt, to, st->st_mode & 07777);
430 if (r < 0)
431 return -errno(*__errno_location ());
432
433 if (fchownat(dt, to,
434 uid_is_valid(override_uid) ? override_uid : st->st_uid,
435 gid_is_valid(override_gid) ? override_gid : st->st_gid,
436 AT_SYMLINK_NOFOLLOW0x100) < 0)
437 r = -errno(*__errno_location ());
438
439 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
440 r = -errno(*__errno_location ());
441
442 return r;
443}
444
445static int fd_copy_node(
446 int df,
447 const char *from,
448 const struct stat *st,
449 int dt,
450 const char *to,
451 uid_t override_uid,
452 gid_t override_gid,
453 CopyFlags copy_flags) {
454 int r;
455
456 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 456, __PRETTY_FUNCTION__
); } while (0)
;
457 assert(st)do { if ((__builtin_expect(!!(!(st)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("st"), "../src/basic/copy.c", 457, __PRETTY_FUNCTION__
); } while (0)
;
458 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 458, __PRETTY_FUNCTION__
); } while (0)
;
459
460 r = mknodat(dt, to, st->st_mode, st->st_rdev);
461 if (r < 0)
462 return -errno(*__errno_location ());
463
464 if (fchownat(dt, to,
465 uid_is_valid(override_uid) ? override_uid : st->st_uid,
466 gid_is_valid(override_gid) ? override_gid : st->st_gid,
467 AT_SYMLINK_NOFOLLOW0x100) < 0)
468 r = -errno(*__errno_location ());
469
470 if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
471 r = -errno(*__errno_location ());
472
473 return r;
474}
475
476static int fd_copy_directory(
477 int df,
478 const char *from,
479 const struct stat *st,
480 int dt,
481 const char *to,
482 dev_t original_device,
483 unsigned depth_left,
484 uid_t override_uid,
485 gid_t override_gid,
486 CopyFlags copy_flags) {
487
488 _cleanup_close___attribute__((cleanup(closep))) int fdf = -1, fdt = -1;
489 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
490 struct dirent *de;
491 bool_Bool created;
492 int r;
493
494 assert(st)do { if ((__builtin_expect(!!(!(st)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("st"), "../src/basic/copy.c", 494, __PRETTY_FUNCTION__
); } while (0)
;
495 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 495, __PRETTY_FUNCTION__
); } while (0)
;
496
497 if (depth_left == 0)
498 return -ENAMETOOLONG36;
499
500 if (from)
501 fdf = openat(df, from, O_RDONLY00|O_DIRECTORY0200000|O_CLOEXEC02000000|O_NOCTTY0400|O_NOFOLLOW0400000);
502 else
503 fdf = fcntl(df, F_DUPFD_CLOEXEC1030, 3);
504 if (fdf < 0)
505 return -errno(*__errno_location ());
506
507 d = fdopendir(fdf);
508 if (!d)
509 return -errno(*__errno_location ());
510 fdf = -1;
511
512 r = mkdirat(dt, to, st->st_mode & 07777);
513 if (r >= 0)
514 created = true1;
515 else if (errno(*__errno_location ()) == EEXIST17 && (copy_flags & COPY_MERGE))
516 created = false0;
517 else
518 return -errno(*__errno_location ());
519
520 fdt = openat(dt, to, O_RDONLY00|O_DIRECTORY0200000|O_CLOEXEC02000000|O_NOCTTY0400|O_NOFOLLOW0400000);
521 if (fdt < 0)
522 return -errno(*__errno_location ());
523
524 r = 0;
525
526 FOREACH_DIRENT_ALL(de, d, return -errno)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return -(*__errno_location ()); } break; } else
{
527 struct stat buf;
528 int q;
529
530 if (dot_or_dot_dot(de->d_name))
531 continue;
532
533 if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW0x100) < 0) {
534 r = -errno(*__errno_location ());
535 continue;
536 }
537
538 if (S_ISDIR(buf.st_mode)((((buf.st_mode)) & 0170000) == (0040000))) {
539 /*
540 * Don't descend into directories on other file systems, if this is requested. We do a simple
541 * .st_dev check here, which basically comes for free. Note that we do this check only on
542 * directories, not other kind of file system objects, for two reason:
543 *
544 * • The kernel's overlayfs pseudo file system that overlays multiple real file systems
545 * propagates the .st_dev field of the file system a file originates from all the way up
546 * through the stack to stat(). It doesn't do that for directories however. This means that
547 * comparing .st_dev on non-directories suggests that they all are mount points. To avoid
548 * confusion we hence avoid relying on this check for regular files.
549 *
550 * • The main reason we do this check at all is to protect ourselves from bind mount cycles,
551 * where we really want to avoid descending down in all eternity. However the .st_dev check
552 * is usually not sufficient for this protection anyway, as bind mount cycles from the same
553 * file system onto itself can't be detected that way. (Note we also do a recursion depth
554 * check, which is probably the better protection in this regard, which is why
555 * COPY_SAME_MOUNT is optional).
556 */
557
558 if (FLAGS_SET(copy_flags, COPY_SAME_MOUNT)(((copy_flags) & (COPY_SAME_MOUNT)) == (COPY_SAME_MOUNT))) {
559 if (buf.st_dev != original_device)
560 continue;
561
562 r = fd_is_mount_point(dirfd(d), de->d_name, 0);
563 if (r < 0)
564 return r;
565 if (r > 0)
566 continue;
567 }
568
569 q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags);
570 } else if (S_ISREG(buf.st_mode)((((buf.st_mode)) & 0170000) == (0100000)))
571 q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
572 else if (S_ISLNK(buf.st_mode)((((buf.st_mode)) & 0170000) == (0120000)))
573 q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
574 else if (S_ISFIFO(buf.st_mode)((((buf.st_mode)) & 0170000) == (0010000)))
575 q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
576 else if (S_ISBLK(buf.st_mode)((((buf.st_mode)) & 0170000) == (0060000)) || S_ISCHR(buf.st_mode)((((buf.st_mode)) & 0170000) == (0020000)) || S_ISSOCK(buf.st_mode)((((buf.st_mode)) & 0170000) == (0140000)))
577 q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
578 else
579 q = -EOPNOTSUPP95;
580
581 if (q == -EEXIST17 && (copy_flags & COPY_MERGE))
582 q = 0;
583
584 if (q < 0)
585 r = q;
586 }
587
588 if (created) {
589 struct timespec ut[2] = {
590 st->st_atim,
591 st->st_mtim
592 };
593
594 if (fchown(fdt,
595 uid_is_valid(override_uid) ? override_uid : st->st_uid,
596 gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
597 r = -errno(*__errno_location ());
598
599 if (fchmod(fdt, st->st_mode & 07777) < 0)
600 r = -errno(*__errno_location ());
601
602 (void) copy_xattr(dirfd(d), fdt);
603 (void) futimens(fdt, ut);
604 }
605
606 return r;
607}
608
609int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
610 struct stat st;
611
612 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 612, __PRETTY_FUNCTION__
); } while (0)
;
613 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 613, __PRETTY_FUNCTION__
); } while (0)
;
614
615 if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW0x100) < 0)
616 return -errno(*__errno_location ());
617
618 if (S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000)))
619 return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
620 else if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
621 return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX2048U, override_uid, override_gid, copy_flags);
622 else if (S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000)))
623 return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
624 else if (S_ISFIFO(st.st_mode)((((st.st_mode)) & 0170000) == (0010000)))
625 return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
626 else if (S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000)) || S_ISCHR(st.st_mode)((((st.st_mode)) & 0170000) == (0020000)) || S_ISSOCK(st.st_mode)((((st.st_mode)) & 0170000) == (0140000)))
627 return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
628 else
629 return -EOPNOTSUPP95;
630}
631
632int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
633 return copy_tree_at(AT_FDCWD-100, from, AT_FDCWD-100, to, override_uid, override_gid, copy_flags);
634}
635
636int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
637 struct stat st;
638
639 assert(dirfd >= 0)do { if ((__builtin_expect(!!(!(dirfd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("dirfd >= 0"), "../src/basic/copy.c",
639, __PRETTY_FUNCTION__); } while (0)
;
640 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 640, __PRETTY_FUNCTION__
); } while (0)
;
641
642 if (fstat(dirfd, &st) < 0)
643 return -errno(*__errno_location ());
644
645 if (!S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
646 return -ENOTDIR20;
647
648 return fd_copy_directory(dirfd, NULL((void*)0), &st, AT_FDCWD-100, to, st.st_dev, COPY_DEPTH_MAX2048U, UID_INVALID((uid_t) -1), GID_INVALID((gid_t) -1), copy_flags);
649}
650
651int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
652 struct stat st;
653
654 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 654, __PRETTY_FUNCTION__
); } while (0)
;
655 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 655, __PRETTY_FUNCTION__
); } while (0)
;
656
657 if (lstat(from, &st) < 0)
658 return -errno(*__errno_location ());
659
660 if (!S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
661 return -ENOTDIR20;
662
663 return fd_copy_directory(AT_FDCWD-100, from, &st, AT_FDCWD-100, to, st.st_dev, COPY_DEPTH_MAX2048U, UID_INVALID((uid_t) -1), GID_INVALID((gid_t) -1), copy_flags);
664}
665
666int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
667 _cleanup_close___attribute__((cleanup(closep))) int fdf = -1;
668 int r;
669
670 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 670, __PRETTY_FUNCTION__
); } while (0)
;
671 assert(fdt >= 0)do { if ((__builtin_expect(!!(!(fdt >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fdt >= 0"), "../src/basic/copy.c", 671
, __PRETTY_FUNCTION__); } while (0)
;
672
673 fdf = open(from, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400);
674 if (fdf < 0)
675 return -errno(*__errno_location ());
676
677 r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
678
679 (void) copy_times(fdf, fdt);
680 (void) copy_xattr(fdf, fdt);
681
682 return r;
683}
684
685int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
686 int fdt = -1, r;
687
688 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 688, __PRETTY_FUNCTION__
); } while (0)
;
689 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 689, __PRETTY_FUNCTION__
); } while (0)
;
690
691 RUN_WITH_UMASK(0000)for (__attribute__((cleanup(_reset_umask_))) struct _umask_struct_
_saved_umask_ = { umask(0000), 0 }; !_saved_umask_.quit ; _saved_umask_
.quit = 1)
{
692 fdt = open(to, flags|O_WRONLY01|O_CREAT0100|O_CLOEXEC02000000|O_NOCTTY0400, mode);
693 if (fdt < 0)
694 return -errno(*__errno_location ());
695 }
696
697 if (chattr_flags != 0)
698 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
699
700 r = copy_file_fd(from, fdt, copy_flags);
701 if (r < 0) {
702 close(fdt);
703 (void) unlink(to);
704 return r;
705 }
706
707 if (close(fdt) < 0) {
708 unlink_noerrno(to);
709 return -errno(*__errno_location ());
710 }
711
712 return 0;
713}
714
715int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
716 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *t = NULL((void*)0);
717 _cleanup_close___attribute__((cleanup(closep))) int fdt = -1;
718 int r;
719
720 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/basic/copy.c", 720, __PRETTY_FUNCTION__
); } while (0)
;
721 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/basic/copy.c", 721, __PRETTY_FUNCTION__
); } while (0)
;
722
723 /* We try to use O_TMPFILE here to create the file if we can. Note that that only works if COPY_REPLACE is not
724 * set though as we need to use linkat() for linking the O_TMPFILE file into the file system but that system
725 * call can't replace existing files. Hence, if COPY_REPLACE is set we create a temporary name in the file
726 * system right-away and unconditionally which we then can renameat() to the right name after we completed
727 * writing it. */
728
729 if (copy_flags & COPY_REPLACE) {
730 r = tempfn_random(to, NULL((void*)0), &t);
731 if (r < 0)
732 return r;
733
734 fdt = open(t, O_CREAT0100|O_EXCL0200|O_NOFOLLOW0400000|O_NOCTTY0400|O_WRONLY01|O_CLOEXEC02000000, 0600);
735 if (fdt < 0) {
736 t = mfree(t);
737 return -errno(*__errno_location ());
738 }
739 } else {
740 fdt = open_tmpfile_linkable(to, O_WRONLY01|O_CLOEXEC02000000, &t);
741 if (fdt < 0)
742 return fdt;
743 }
744
745 if (chattr_flags != 0)
746 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
747
748 r = copy_file_fd(from, fdt, copy_flags);
749 if (r < 0)
750 return r;
751
752 if (fchmod(fdt, mode) < 0)
753 return -errno(*__errno_location ());
754
755 if (copy_flags & COPY_REPLACE) {
756 if (renameat(AT_FDCWD-100, t, AT_FDCWD-100, to) < 0)
757 return -errno(*__errno_location ());
758 } else {
759 r = link_tmpfile(fdt, t, to);
760 if (r < 0)
761 return r;
762 }
763
764 t = mfree(t);
765 return 0;
766}
767
768int copy_times(int fdf, int fdt) {
769 struct timespec ut[2];
770 struct stat st;
771 usec_t crtime = 0;
772
773 assert(fdf >= 0)do { if ((__builtin_expect(!!(!(fdf >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fdf >= 0"), "../src/basic/copy.c", 773
, __PRETTY_FUNCTION__); } while (0)
;
774 assert(fdt >= 0)do { if ((__builtin_expect(!!(!(fdt >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fdt >= 0"), "../src/basic/copy.c", 774
, __PRETTY_FUNCTION__); } while (0)
;
775
776 if (fstat(fdf, &st) < 0)
777 return -errno(*__errno_location ());
778
779 ut[0] = st.st_atim;
780 ut[1] = st.st_mtim;
781
782 if (futimens(fdt, ut) < 0)
783 return -errno(*__errno_location ());
784
785 if (fd_getcrtime(fdf, &crtime) >= 0)
786 (void) fd_setcrtime(fdt, crtime);
787
788 return 0;
789}
790
791int copy_xattr(int fdf, int fdt) {
792 _cleanup_free___attribute__((cleanup(freep))) char *bufa = NULL((void*)0), *bufb = NULL((void*)0);
793 size_t sza = 100, szb = 100;
794 ssize_t n;
795 int ret = 0;
796 const char *p;
797
798 for (;;) {
799 bufa = malloc(sza);
800 if (!bufa)
801 return -ENOMEM12;
802
803 n = flistxattr(fdf, bufa, sza);
804 if (n == 0)
805 return 0;
806 if (n > 0)
807 break;
808 if (errno(*__errno_location ()) != ERANGE34)
809 return -errno(*__errno_location ());
810
811 sza *= 2;
812
813 bufa = mfree(bufa);
814 }
815
816 p = bufa;
817 while (n > 0) {
818 size_t l;
819
820 l = strlen(p);
821 assert(l < (size_t) n)do { if ((__builtin_expect(!!(!(l < (size_t) n)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l < (size_t) n"), "../src/basic/copy.c"
, 821, __PRETTY_FUNCTION__); } while (0)
;
822
823 if (startswith(p, "user.")) {
824 ssize_t m;
825
826 if (!bufb) {
827 bufb = malloc(szb);
828 if (!bufb)
829 return -ENOMEM12;
830 }
831
832 m = fgetxattr(fdf, p, bufb, szb);
833 if (m < 0) {
834 if (errno(*__errno_location ()) == ERANGE34) {
835 szb *= 2;
836 bufb = mfree(bufb);
837 continue;
838 }
839
840 return -errno(*__errno_location ());
841 }
842
843 if (fsetxattr(fdt, p, bufb, m, 0) < 0)
844 ret = -errno(*__errno_location ());
845 }
846
847 p += l + 1;
848 n -= l + 1;
849 }
850
851 return ret;
852}