Copy SRC_FD to DEST_FD, using the buffer *ABUF of size BUF_SIZE for temporary storage, allocating the buffer lazily if *ABUF is null. For best results, *ABUF should be well-aligned. If ALLOW_REFLINK, possibly use copy_file_range to copy. SRC_NAME and DST_NAME are the source and destination's name. Copy no more than MAX_N_READ bytes. If HOLE_SIZE, look for holes in the input; *HOL
| 109 | If successful, return the number of bytes copied, |
| 110 | otherwise diagnose the failure and return -1. */ |
| 111 | static intmax_t |
| 112 | sparse_copy (int src_fd, int dest_fd, char **abuf, idx_t buf_size, |
| 113 | bool allow_reflink, |
| 114 | char const *src_name, char const *dst_name, |
| 115 | count_t max_n_read, off_t *hole_size, |
| 116 | struct copy_debug *debug) |
| 117 | { |
| 118 | count_t total_n_read = 0; |
| 119 | |
| 120 | if (debug->sparse_detection == COPY_DEBUG_UNKNOWN) |
| 121 | debug->sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO; |
| 122 | else if (hole_size && debug->sparse_detection == COPY_DEBUG_EXTERNAL) |
| 123 | debug->sparse_detection = COPY_DEBUG_EXTERNAL_INTERNAL; |
| 124 | |
| 125 | /* If not looking for holes, use copy_file_range if functional, |
| 126 | but don't use if reflink disallowed as that may be implicit. */ |
| 127 | if (!hole_size && allow_reflink) |
| 128 | while (0 < max_n_read) |
| 129 | { |
| 130 | /* Copy at most COPY_MAX bytes at a time; this is min |
| 131 | (SSIZE_MAX, SIZE_MAX) truncated to a value that is |
| 132 | surely aligned well. */ |
| 133 | ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30; |
| 134 | ssize_t n_copied = copy_file_range (src_fd, NULL, dest_fd, NULL, |
| 135 | MIN (max_n_read, copy_max), 0); |
| 136 | if (n_copied == 0) |
| 137 | { |
| 138 | /* copy_file_range incorrectly returns 0 when reading from |
| 139 | the proc file system on the Linux kernel through at |
| 140 | least 5.6.19 (2020), so fall back on 'read' if the |
| 141 | input file seems empty. */ |
| 142 | if (total_n_read == 0) |
| 143 | break; |
| 144 | debug->offload = COPY_DEBUG_YES; |
| 145 | return total_n_read; |
| 146 | } |
| 147 | if (n_copied < 0) |
| 148 | { |
| 149 | /* Don’t treat EFBIG as a reportable error from copy_file_range. |
| 150 | If the input is at EOF and the output position is 2**63 - 1, |
| 151 | copy_file_range (ifd, NULL, ofd, NULL, 2146435072, 0) |
| 152 | incorrectly fails with EFBIG. Problem observed on Ubuntu 25.10 |
| 153 | x86-64 with Linux kernel 6.17.0-8-generic #8-Ubuntu. */ |
| 154 | if (errno == EFBIG) |
| 155 | break; |
| 156 | |
| 157 | debug->offload = COPY_DEBUG_UNSUPPORTED; |
| 158 | |
| 159 | /* Consider operation unsupported only if no data copied. |
| 160 | For example, EPERM could occur if copy_file_range not enabled |
| 161 | in seccomp filters, so retry with a standard copy. EPERM can |
| 162 | also occur for immutable files, but that would only be in the |
| 163 | edge case where the file is made immutable after creating, |
| 164 | in which case the (more accurate) error is still shown. */ |
| 165 | if (total_n_read == 0 && is_CLONENOTSUP (errno)) |
| 166 | break; |
| 167 | |
| 168 | /* ENOENT was seen sometimes across CIFS shares, resulting in |
no test coverage detected