tools/coreutils: update to 9.2
[openwrt/staging/dedeckeh.git] / tools / coreutils / patches / 001-copy-fix-reflink-auto-to-fallback-in-more-cases.patch
1 From 093a8b4bfaba60005f14493ce7ef11ed665a0176 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
3 Date: Thu, 23 Mar 2023 13:19:04 +0000
4 Subject: [PATCH] copy: fix --reflink=auto to fallback in more cases
5
6 On restricted systems like android or some containers,
7 FICLONE could return EPERM, EACCES, or ENOTTY,
8 which would have induced the command to fail to copy
9 rather than falling back to a more standard copy.
10
11 * src/copy.c (is_terminal_failure): A new function refactored
12 from handle_clone_fail().
13 (is_CLONENOTSUP): Merge in the handling of EACCES, ENOTTY, EPERM
14 as they also pertain to determination of whether cloning is supported
15 if we ever use this function in that context.
16 (handle_clone_fail): Use is_terminal_failure() in all cases,
17 so that we assume a terminal failure in less errno cases.
18 * NEWS: Mention the bug fix.
19 Addresses https://bugs.gnu.org/62404
20 ---
21 --- a/src/copy.c
22 +++ b/src/copy.c
23 @@ -278,15 +278,27 @@ create_hole (int fd, char const *name, b
24 }
25
26
27 -/* Whether the errno from FICLONE, or copy_file_range
28 - indicates operation is not supported for this file or file system. */
29 +/* Whether the errno indicates the operation is a transient failure.
30 + I.e., a failure that would indicate the operation _is_ supported,
31 + but has failed in a terminal way. */
32 +
33 +static bool
34 +is_terminal_error (int err)
35 +{
36 + return err == EIO || err == ENOMEM || err == ENOSPC || err == EDQUOT;
37 +}
38 +
39 +
40 +/* Whether the errno from FICLONE, or copy_file_range indicates
41 + the operation is not supported/allowed for this file or process. */
42
43 static bool
44 is_CLONENOTSUP (int err)
45 {
46 - return err == ENOSYS || is_ENOTSUP (err)
47 + return err == ENOSYS || err == ENOTTY || is_ENOTSUP (err)
48 || err == EINVAL || err == EBADF
49 - || err == EXDEV || err == ETXTBSY;
50 + || err == EXDEV || err == ETXTBSY
51 + || err == EPERM || err == EACCES;
52 }
53
54
55 @@ -339,20 +351,18 @@ sparse_copy (int src_fd, int dest_fd, ch
56 {
57 copy_debug.offload = COPY_DEBUG_UNSUPPORTED;
58
59 - if (is_CLONENOTSUP (errno))
60 - break;
61 -
62 - /* copy_file_range might not be enabled in seccomp filters,
63 - so retry with a standard copy. EPERM can also occur
64 - for immutable files, but that would only be in the edge case
65 - where the file is made immutable after creating/truncating,
66 + /* Consider operation unsupported only if no data copied.
67 + For example, EPERM could occur if copy_file_range not enabled
68 + in seccomp filters, so retry with a standard copy. EPERM can
69 + also occur for immutable files, but that would only be in the
70 + edge case where the file is made immutable after creating,
71 in which case the (more accurate) error is still shown. */
72 - if (errno == EPERM && *total_n_read == 0)
73 + if (*total_n_read == 0 && is_CLONENOTSUP (errno))
74 break;
75
76 /* ENOENT was seen sometimes across CIFS shares, resulting in
77 no data being copied, but subsequent standard copies succeed. */
78 - if (errno == ENOENT && *total_n_read == 0)
79 + if (*total_n_read == 0 && errno == ENOENT)
80 break;
81
82 if (errno == EINTR)
83 @@ -1172,17 +1182,15 @@ handle_clone_fail (int dst_dirfd, char c
84 char const* src_name, char const* dst_name,
85 int dest_desc, bool new_dst, enum Reflink_type reflink_mode)
86 {
87 - /* If the clone operation is creating the destination,
88 - then don't try and cater for all non transient file system errors,
89 - and instead only cater for specific transient errors. */
90 - bool transient_failure;
91 - if (dest_desc < 0) /* currently for fclonefileat(). */
92 - transient_failure = errno == EIO || errno == ENOMEM
93 - || errno == ENOSPC || errno == EDQUOT;
94 - else /* currently for FICLONE. */
95 - transient_failure = ! is_CLONENOTSUP (errno);
96 + /* When the clone operation fails, report failure only with errno values
97 + known to mean trouble when the clone is supported and called properly.
98 + Do not report failure merely because !is_CLONENOTSUP (errno),
99 + as systems may yield oddball errno values here with FICLONE.
100 + Also is_CLONENOTSUP() is not appropriate for the range of errnos
101 + possible from fclonefileat(), so it's more consistent to avoid. */
102 + bool report_failure = is_terminal_error (errno);
103
104 - if (reflink_mode == REFLINK_ALWAYS || transient_failure)
105 + if (reflink_mode == REFLINK_ALWAYS || report_failure)
106 error (0, errno, _("failed to clone %s from %s"),
107 quoteaf_n (0, dst_name), quoteaf_n (1, src_name));
108
109 @@ -1190,14 +1198,14 @@ handle_clone_fail (int dst_dirfd, char c
110 but cloned no data. */
111 if (new_dst /* currently not for fclonefileat(). */
112 && reflink_mode == REFLINK_ALWAYS
113 - && ((! transient_failure) || lseek (dest_desc, 0, SEEK_END) == 0)
114 + && ((! report_failure) || lseek (dest_desc, 0, SEEK_END) == 0)
115 && unlinkat (dst_dirfd, dst_relname, 0) != 0 && errno != ENOENT)
116 error (0, errno, _("cannot remove %s"), quoteaf (dst_name));
117
118 - if (! transient_failure)
119 + if (! report_failure)
120 copy_debug.reflink = COPY_DEBUG_UNSUPPORTED;
121
122 - if (reflink_mode == REFLINK_ALWAYS || transient_failure)
123 + if (reflink_mode == REFLINK_ALWAYS || report_failure)
124 return false;
125
126 return true;