MCPcopy Create free account
hub / github.com/coreutils/coreutils / sparse_copy

Function sparse_copy

src/copy-file-data.c:111–276  ·  view source on GitHub ↗

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

Source from the content-addressed store, hash-verified

109 If successful, return the number of bytes copied,
110 otherwise diagnose the failure and return -1. */
111static intmax_t
112sparse_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

Callers 2

lseek_copyFunction · 0.85
copy_file_dataFunction · 0.85

Calls 3

is_CLONENOTSUPFunction · 0.85
is_nulFunction · 0.85
create_holeFunction · 0.85

Tested by

no test coverage detected