]>
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 | ||
1c876927 | 60 | int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { |
a44202e9 | 61 | bool try_cfr = true, try_sendfile = true, try_splice = true; |
0254b455 | 62 | int r; |
7c2da2ca | 63 | size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ |
cda134ab | 64 | |
849958d1 LP |
65 | assert(fdf >= 0); |
66 | assert(fdt >= 0); | |
67 | ||
78ba8cf7 LP |
68 | /* Tries to copy bytes from the file descriptor 'fdf' to 'fdt' in the smartest possible way. Copies a maximum |
69 | * of 'max_bytes', which may be specified as UINT64_MAX, in which no maximum is applied. Returns negative on | |
70 | * error, zero if EOF is hit before the bytes limit is hit and positive otherwise. */ | |
71 | ||
0254b455 | 72 | /* Try btrfs reflinks first. */ |
1c876927 | 73 | if ((copy_flags & COPY_REFLINK) && |
c622fbdb LP |
74 | max_bytes == (uint64_t) -1 && |
75 | lseek(fdf, 0, SEEK_CUR) == 0 && | |
76 | lseek(fdt, 0, SEEK_CUR) == 0) { | |
77 | ||
0254b455 LP |
78 | r = btrfs_reflink(fdf, fdt); |
79 | if (r >= 0) | |
f6d9c616 | 80 | return 0; /* we copied the whole thing, hence hit EOF, return 0 */ |
0254b455 LP |
81 | } |
82 | ||
849958d1 | 83 | for (;;) { |
cda134ab | 84 | ssize_t n; |
93240d3a | 85 | |
59f448cf | 86 | if (max_bytes != (uint64_t) -1) { |
93240d3a | 87 | if (max_bytes <= 0) |
f6d9c616 | 88 | return 1; /* return > 0 if we hit the max_bytes limit */ |
93240d3a | 89 | |
d219849e ZJS |
90 | if (m > max_bytes) |
91 | m = max_bytes; | |
93240d3a LP |
92 | } |
93 | ||
a44202e9 ZJS |
94 | /* First try copy_file_range(), unless we already tried */ |
95 | if (try_cfr) { | |
96 | n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); | |
97 | if (n < 0) { | |
6402d5c6 | 98 | if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF)) |
a44202e9 ZJS |
99 | return n; |
100 | ||
101 | try_cfr = false; | |
102 | /* use fallback below */ | |
103 | } else if (n == 0) /* EOF */ | |
104 | break; | |
105 | else | |
106 | /* Success! */ | |
107 | goto next; | |
108 | } | |
109 | ||
cda134ab LP |
110 | /* First try sendfile(), unless we already tried */ |
111 | if (try_sendfile) { | |
cda134ab LP |
112 | n = sendfile(fdt, fdf, NULL, m); |
113 | if (n < 0) { | |
00a8cf77 | 114 | if (!IN_SET(errno, EINVAL, ENOSYS)) |
cda134ab LP |
115 | return -errno; |
116 | ||
117 | try_sendfile = false; | |
118 | /* use fallback below */ | |
119 | } else if (n == 0) /* EOF */ | |
120 | break; | |
00a8cf77 | 121 | else |
81d20007 LP |
122 | /* Success! */ |
123 | goto next; | |
124 | } | |
125 | ||
00a8cf77 | 126 | /* Then try splice, unless we already tried */ |
81d20007 | 127 | if (try_splice) { |
f6d9c616 | 128 | n = splice(fdf, NULL, fdt, NULL, m, 0); |
81d20007 | 129 | if (n < 0) { |
00a8cf77 | 130 | if (!IN_SET(errno, EINVAL, ENOSYS)) |
81d20007 LP |
131 | return -errno; |
132 | ||
133 | try_splice = false; | |
134 | /* use fallback below */ | |
135 | } else if (n == 0) /* EOF */ | |
136 | break; | |
00a8cf77 | 137 | else |
81d20007 | 138 | /* Success! */ |
cda134ab LP |
139 | goto next; |
140 | } | |
141 | ||
142 | /* As a fallback just copy bits by hand */ | |
143 | { | |
00a8cf77 | 144 | uint8_t buf[MIN(m, COPY_BUFFER_SIZE)]; |
849958d1 | 145 | |
00a8cf77 | 146 | n = read(fdf, buf, sizeof buf); |
cda134ab LP |
147 | if (n < 0) |
148 | return -errno; | |
149 | if (n == 0) /* EOF */ | |
150 | break; | |
151 | ||
0254b455 | 152 | r = loop_write(fdt, buf, (size_t) n, false); |
553acb7b ZJS |
153 | if (r < 0) |
154 | return r; | |
cda134ab | 155 | } |
93240d3a | 156 | |
cda134ab | 157 | next: |
59f448cf LP |
158 | if (max_bytes != (uint64_t) -1) { |
159 | assert(max_bytes >= (uint64_t) n); | |
93240d3a LP |
160 | max_bytes -= n; |
161 | } | |
00a8cf77 ZJS |
162 | /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, |
163 | * so reduce our maximum by the amount we already copied, | |
164 | * but don't go below our copy buffer size, unless we are | |
61233823 | 165 | * close the limit of bytes we are allowed to copy. */ |
00a8cf77 | 166 | m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); |
849958d1 LP |
167 | } |
168 | ||
f6d9c616 | 169 | return 0; /* return 0 if we hit EOF earlier than the size limit */ |
849958d1 LP |
170 | } |
171 | ||
d01cd401 LP |
172 | static int fd_copy_symlink( |
173 | int df, | |
174 | const char *from, | |
175 | const struct stat *st, | |
176 | int dt, | |
177 | const char *to, | |
178 | uid_t override_uid, | |
179 | gid_t override_gid, | |
180 | CopyFlags copy_flags) { | |
181 | ||
849958d1 LP |
182 | _cleanup_free_ char *target = NULL; |
183 | int r; | |
184 | ||
185 | assert(from); | |
186 | assert(st); | |
187 | assert(to); | |
188 | ||
189 | r = readlinkat_malloc(df, from, &target); | |
190 | if (r < 0) | |
191 | return r; | |
192 | ||
e156347e | 193 | if (symlinkat(target, dt, to) < 0) |
849958d1 | 194 | return -errno; |
849958d1 | 195 | |
d01cd401 LP |
196 | if (fchownat(dt, to, |
197 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
198 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
199 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
200 | return -errno; |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
d01cd401 LP |
205 | static int fd_copy_regular( |
206 | int df, | |
207 | const char *from, | |
208 | const struct stat *st, | |
209 | int dt, | |
210 | const char *to, | |
211 | uid_t override_uid, | |
212 | gid_t override_gid, | |
213 | CopyFlags copy_flags) { | |
214 | ||
849958d1 | 215 | _cleanup_close_ int fdf = -1, fdt = -1; |
ebd93cb6 | 216 | struct timespec ts[2]; |
849958d1 LP |
217 | int r, q; |
218 | ||
219 | assert(from); | |
220 | assert(st); | |
221 | assert(to); | |
222 | ||
223 | fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
224 | if (fdf < 0) | |
225 | return -errno; | |
226 | ||
227 | fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777); | |
e156347e | 228 | if (fdt < 0) |
849958d1 | 229 | return -errno; |
849958d1 | 230 | |
1c876927 | 231 | r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); |
849958d1 | 232 | if (r < 0) { |
7b938dfb | 233 | (void) unlinkat(dt, to, 0); |
849958d1 LP |
234 | return r; |
235 | } | |
236 | ||
d01cd401 LP |
237 | if (fchown(fdt, |
238 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
239 | gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) | |
849958d1 LP |
240 | r = -errno; |
241 | ||
242 | if (fchmod(fdt, st->st_mode & 07777) < 0) | |
243 | r = -errno; | |
244 | ||
ebd93cb6 LP |
245 | ts[0] = st->st_atim; |
246 | ts[1] = st->st_mtim; | |
247 | (void) futimens(fdt, ts); | |
e6bd041c LP |
248 | (void) copy_xattr(fdf, fdt); |
249 | ||
849958d1 LP |
250 | q = close(fdt); |
251 | fdt = -1; | |
252 | ||
253 | if (q < 0) { | |
254 | r = -errno; | |
7b938dfb | 255 | (void) unlinkat(dt, to, 0); |
849958d1 LP |
256 | } |
257 | ||
258 | return r; | |
259 | } | |
260 | ||
d01cd401 LP |
261 | static int fd_copy_fifo( |
262 | int df, | |
263 | const char *from, | |
264 | const struct stat *st, | |
265 | int dt, | |
266 | const char *to, | |
267 | uid_t override_uid, | |
268 | gid_t override_gid, | |
269 | CopyFlags copy_flags) { | |
849958d1 LP |
270 | int r; |
271 | ||
272 | assert(from); | |
273 | assert(st); | |
274 | assert(to); | |
275 | ||
276 | r = mkfifoat(dt, to, st->st_mode & 07777); | |
e156347e | 277 | if (r < 0) |
849958d1 | 278 | return -errno; |
849958d1 | 279 | |
d01cd401 LP |
280 | if (fchownat(dt, to, |
281 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
282 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
283 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
284 | r = -errno; |
285 | ||
286 | if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) | |
287 | r = -errno; | |
288 | ||
289 | return r; | |
290 | } | |
291 | ||
d01cd401 LP |
292 | static int fd_copy_node( |
293 | int df, | |
294 | const char *from, | |
295 | const struct stat *st, | |
296 | int dt, | |
297 | const char *to, | |
298 | uid_t override_uid, | |
299 | gid_t override_gid, | |
300 | CopyFlags copy_flags) { | |
849958d1 LP |
301 | int r; |
302 | ||
303 | assert(from); | |
304 | assert(st); | |
305 | assert(to); | |
306 | ||
307 | r = mknodat(dt, to, st->st_mode, st->st_rdev); | |
e156347e | 308 | if (r < 0) |
849958d1 | 309 | return -errno; |
849958d1 | 310 | |
d01cd401 LP |
311 | if (fchownat(dt, to, |
312 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
313 | gid_is_valid(override_gid) ? override_gid : st->st_gid, | |
314 | AT_SYMLINK_NOFOLLOW) < 0) | |
849958d1 LP |
315 | r = -errno; |
316 | ||
317 | if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) | |
318 | r = -errno; | |
319 | ||
320 | return r; | |
321 | } | |
322 | ||
d7c7c334 LP |
323 | static int fd_copy_directory( |
324 | int df, | |
325 | const char *from, | |
326 | const struct stat *st, | |
327 | int dt, | |
328 | const char *to, | |
329 | dev_t original_device, | |
d01cd401 LP |
330 | uid_t override_uid, |
331 | gid_t override_gid, | |
1c876927 | 332 | CopyFlags copy_flags) { |
d7c7c334 | 333 | |
849958d1 LP |
334 | _cleanup_close_ int fdf = -1, fdt = -1; |
335 | _cleanup_closedir_ DIR *d = NULL; | |
336 | struct dirent *de; | |
337 | bool created; | |
338 | int r; | |
339 | ||
849958d1 LP |
340 | assert(st); |
341 | assert(to); | |
342 | ||
d7c7c334 LP |
343 | if (from) |
344 | fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
345 | else | |
346 | fdf = fcntl(df, F_DUPFD_CLOEXEC, 3); | |
b498c53d LP |
347 | if (fdf < 0) |
348 | return -errno; | |
849958d1 LP |
349 | |
350 | d = fdopendir(fdf); | |
351 | if (!d) | |
352 | return -errno; | |
353 | fdf = -1; | |
354 | ||
355 | r = mkdirat(dt, to, st->st_mode & 07777); | |
356 | if (r >= 0) | |
357 | created = true; | |
1c876927 | 358 | else if (errno == EEXIST && (copy_flags & COPY_MERGE)) |
849958d1 LP |
359 | created = false; |
360 | else | |
361 | return -errno; | |
362 | ||
363 | fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
364 | if (fdt < 0) | |
365 | return -errno; | |
366 | ||
2c455af4 LP |
367 | r = 0; |
368 | ||
8420fa3a | 369 | FOREACH_DIRENT_ALL(de, d, return -errno) { |
849958d1 LP |
370 | struct stat buf; |
371 | int q; | |
372 | ||
49bfc877 | 373 | if (dot_or_dot_dot(de->d_name)) |
8420fa3a LP |
374 | continue; |
375 | ||
849958d1 LP |
376 | if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) { |
377 | r = -errno; | |
378 | continue; | |
379 | } | |
380 | ||
381 | if (buf.st_dev != original_device) | |
382 | continue; | |
383 | ||
384 | if (S_ISREG(buf.st_mode)) | |
d01cd401 | 385 | q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 386 | else if (S_ISDIR(buf.st_mode)) |
d01cd401 | 387 | q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags); |
849958d1 | 388 | else if (S_ISLNK(buf.st_mode)) |
d01cd401 | 389 | q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 390 | else if (S_ISFIFO(buf.st_mode)) |
d01cd401 | 391 | q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
0e2b2cac | 392 | else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode)) |
d01cd401 | 393 | q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |
849958d1 | 394 | else |
15411c0c | 395 | q = -EOPNOTSUPP; |
849958d1 | 396 | |
1c876927 | 397 | if (q == -EEXIST && (copy_flags & COPY_MERGE)) |
e156347e LP |
398 | q = 0; |
399 | ||
849958d1 LP |
400 | if (q < 0) |
401 | r = q; | |
402 | } | |
403 | ||
3b8483c0 LP |
404 | if (created) { |
405 | struct timespec ut[2] = { | |
406 | st->st_atim, | |
407 | st->st_mtim | |
408 | }; | |
409 | ||
d01cd401 LP |
410 | if (fchown(fdt, |
411 | uid_is_valid(override_uid) ? override_uid : st->st_uid, | |
412 | gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) | |
3b8483c0 LP |
413 | r = -errno; |
414 | ||
415 | if (fchmod(fdt, st->st_mode & 07777) < 0) | |
416 | r = -errno; | |
417 | ||
418 | (void) copy_xattr(dirfd(d), fdt); | |
419 | (void) futimens(fdt, ut); | |
420 | } | |
421 | ||
849958d1 LP |
422 | return r; |
423 | } | |
424 | ||
d01cd401 | 425 | 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 |
426 | struct stat st; |
427 | ||
428 | assert(from); | |
429 | assert(to); | |
430 | ||
f2cbe59e | 431 | if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0) |
849958d1 LP |
432 | return -errno; |
433 | ||
434 | if (S_ISREG(st.st_mode)) | |
d01cd401 | 435 | return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 436 | else if (S_ISDIR(st.st_mode)) |
d01cd401 | 437 | return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags); |
849958d1 | 438 | else if (S_ISLNK(st.st_mode)) |
d01cd401 | 439 | return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 440 | else if (S_ISFIFO(st.st_mode)) |
d01cd401 | 441 | return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
0e2b2cac | 442 | else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) |
d01cd401 | 443 | return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); |
849958d1 | 444 | else |
15411c0c | 445 | return -EOPNOTSUPP; |
849958d1 LP |
446 | } |
447 | ||
d01cd401 LP |
448 | int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { |
449 | return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags); | |
f2cbe59e LP |
450 | } |
451 | ||
1c876927 | 452 | int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { |
d7c7c334 LP |
453 | struct stat st; |
454 | ||
455 | assert(dirfd >= 0); | |
456 | assert(to); | |
457 | ||
458 | if (fstat(dirfd, &st) < 0) | |
459 | return -errno; | |
460 | ||
461 | if (!S_ISDIR(st.st_mode)) | |
462 | return -ENOTDIR; | |
463 | ||
d01cd401 | 464 | return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); |
d7c7c334 LP |
465 | } |
466 | ||
1c876927 | 467 | int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { |
9a50e3ca LP |
468 | struct stat st; |
469 | ||
470 | assert(from); | |
471 | assert(to); | |
472 | ||
473 | if (lstat(from, &st) < 0) | |
474 | return -errno; | |
475 | ||
476 | if (!S_ISDIR(st.st_mode)) | |
477 | return -ENOTDIR; | |
478 | ||
d01cd401 | 479 | return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); |
9a50e3ca LP |
480 | } |
481 | ||
1c876927 | 482 | int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { |
cda134ab | 483 | _cleanup_close_ int fdf = -1; |
e6bd041c | 484 | int r; |
849958d1 LP |
485 | |
486 | assert(from); | |
cda134ab | 487 | assert(fdt >= 0); |
849958d1 LP |
488 | |
489 | fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); | |
490 | if (fdf < 0) | |
491 | return -errno; | |
492 | ||
1c876927 | 493 | r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); |
e6bd041c LP |
494 | |
495 | (void) copy_times(fdf, fdt); | |
496 | (void) copy_xattr(fdf, fdt); | |
497 | ||
498 | return r; | |
cda134ab LP |
499 | } |
500 | ||
1c876927 | 501 | int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { |
a7f7d1bd | 502 | int fdt = -1, r; |
cda134ab LP |
503 | |
504 | assert(from); | |
505 | assert(to); | |
506 | ||
ebd93cb6 LP |
507 | RUN_WITH_UMASK(0000) { |
508 | fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); | |
509 | if (fdt < 0) | |
510 | return -errno; | |
511 | } | |
849958d1 | 512 | |
f2068bcc | 513 | if (chattr_flags != 0) |
1ed8f8c1 | 514 | (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); |
f2068bcc | 515 | |
1c876927 | 516 | r = copy_file_fd(from, fdt, copy_flags); |
849958d1 | 517 | if (r < 0) { |
cda134ab | 518 | close(fdt); |
7b938dfb | 519 | (void) unlink(to); |
849958d1 LP |
520 | return r; |
521 | } | |
522 | ||
cda134ab LP |
523 | if (close(fdt) < 0) { |
524 | unlink_noerrno(to); | |
525 | return -errno; | |
849958d1 LP |
526 | } |
527 | ||
528 | return 0; | |
529 | } | |
e6bd041c | 530 | |
1c876927 | 531 | int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { |
a7f7d1bd | 532 | _cleanup_free_ char *t = NULL; |
ebd93cb6 LP |
533 | int r; |
534 | ||
535 | assert(from); | |
536 | assert(to); | |
537 | ||
14bcf25c | 538 | r = tempfn_random(to, NULL, &t); |
ebd93cb6 LP |
539 | if (r < 0) |
540 | return r; | |
541 | ||
1c876927 | 542 | r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags); |
ebd93cb6 LP |
543 | if (r < 0) |
544 | return r; | |
545 | ||
1c876927 | 546 | if (copy_flags & COPY_REPLACE) { |
f85ef957 AC |
547 | r = renameat(AT_FDCWD, t, AT_FDCWD, to); |
548 | if (r < 0) | |
549 | r = -errno; | |
550 | } else | |
551 | r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to); | |
552 | if (r < 0) { | |
ce21ed5c | 553 | (void) unlink(t); |
f85ef957 | 554 | return r; |
ebd93cb6 LP |
555 | } |
556 | ||
557 | return 0; | |
558 | } | |
559 | ||
e6bd041c LP |
560 | int copy_times(int fdf, int fdt) { |
561 | struct timespec ut[2]; | |
562 | struct stat st; | |
a7f7d1bd | 563 | usec_t crtime = 0; |
e6bd041c LP |
564 | |
565 | assert(fdf >= 0); | |
566 | assert(fdt >= 0); | |
567 | ||
568 | if (fstat(fdf, &st) < 0) | |
569 | return -errno; | |
570 | ||
571 | ut[0] = st.st_atim; | |
572 | ut[1] = st.st_mtim; | |
573 | ||
574 | if (futimens(fdt, ut) < 0) | |
575 | return -errno; | |
576 | ||
577 | if (fd_getcrtime(fdf, &crtime) >= 0) | |
578 | (void) fd_setcrtime(fdt, crtime); | |
579 | ||
580 | return 0; | |
581 | } | |
582 | ||
583 | int copy_xattr(int fdf, int fdt) { | |
584 | _cleanup_free_ char *bufa = NULL, *bufb = NULL; | |
585 | size_t sza = 100, szb = 100; | |
586 | ssize_t n; | |
587 | int ret = 0; | |
588 | const char *p; | |
589 | ||
590 | for (;;) { | |
591 | bufa = malloc(sza); | |
592 | if (!bufa) | |
593 | return -ENOMEM; | |
594 | ||
595 | n = flistxattr(fdf, bufa, sza); | |
596 | if (n == 0) | |
597 | return 0; | |
598 | if (n > 0) | |
599 | break; | |
600 | if (errno != ERANGE) | |
601 | return -errno; | |
602 | ||
603 | sza *= 2; | |
604 | ||
97b11eed | 605 | bufa = mfree(bufa); |
e6bd041c LP |
606 | } |
607 | ||
608 | p = bufa; | |
609 | while (n > 0) { | |
610 | size_t l; | |
611 | ||
612 | l = strlen(p); | |
613 | assert(l < (size_t) n); | |
614 | ||
615 | if (startswith(p, "user.")) { | |
616 | ssize_t m; | |
617 | ||
618 | if (!bufb) { | |
619 | bufb = malloc(szb); | |
620 | if (!bufb) | |
621 | return -ENOMEM; | |
622 | } | |
623 | ||
624 | m = fgetxattr(fdf, p, bufb, szb); | |
625 | if (m < 0) { | |
626 | if (errno == ERANGE) { | |
627 | szb *= 2; | |
97b11eed | 628 | bufb = mfree(bufb); |
e6bd041c LP |
629 | continue; |
630 | } | |
631 | ||
632 | return -errno; | |
633 | } | |
634 | ||
635 | if (fsetxattr(fdt, p, bufb, m, 0) < 0) | |
636 | ret = -errno; | |
637 | } | |
638 | ||
639 | p += l + 1; | |
640 | n -= l + 1; | |
641 | } | |
642 | ||
643 | return ret; | |
644 | } |