| 324 | otherwise diagnose the failure and return -1. */ |
| 325 | |
| 326 | static off_t |
| 327 | lseek_copy (int src_fd, int dest_fd, char **abuf, idx_t buf_size, |
| 328 | off_t src_pos, count_t ibytes, |
| 329 | struct scan_inference const *scan_inference, off_t src_total_size, |
| 330 | enum Sparse_type sparse_mode, |
| 331 | bool allow_reflink, |
| 332 | char const *src_name, char const *dst_name, |
| 333 | off_t *hole_size, struct copy_debug *debug) |
| 334 | { |
| 335 | off_t last_ext_start = src_pos; |
| 336 | off_t last_ext_len = 0; |
| 337 | off_t max_ipos = ckd_add (&max_ipos, src_pos, ibytes) ? OFF_T_MAX : max_ipos; |
| 338 | |
| 339 | /* From here on, SRC_TOTAL_SIZE is bounded above by MAX_IPOS. */ |
| 340 | src_total_size = MIN (src_total_size, max_ipos); |
| 341 | |
| 342 | /* The input position after the most recent read of data, |
| 343 | or SRC_POS if no data have been read. */ |
| 344 | off_t ipos = src_pos; |
| 345 | |
| 346 | debug->sparse_detection = COPY_DEBUG_EXTERNAL; |
| 347 | |
| 348 | bool used_scan_inference = false; |
| 349 | |
| 350 | for (off_t ext_start = scan_inference->ext_start; |
| 351 | 0 <= ext_start && ext_start < max_ipos; ) |
| 352 | { |
| 353 | off_t ext_end; |
| 354 | if (ext_start == src_pos && ! used_scan_inference) |
| 355 | { |
| 356 | ext_end = scan_inference->hole_start; |
| 357 | used_scan_inference = true; |
| 358 | } |
| 359 | else |
| 360 | ext_end = lseek (src_fd, ext_start, SEEK_HOLE); |
| 361 | if (0 <= ext_end) |
| 362 | ext_end = MIN (ext_end, max_ipos); |
| 363 | else |
| 364 | { |
| 365 | if (errno != ENXIO) |
| 366 | goto cannot_lseek; |
| 367 | ext_end = src_total_size; |
| 368 | if (ext_end <= ext_start) |
| 369 | { |
| 370 | /* The input file grew; get its current size. */ |
| 371 | src_total_size = lseek (src_fd, 0, SEEK_END); |
| 372 | if (src_total_size < 0) |
| 373 | goto cannot_lseek; |
| 374 | src_total_size = MIN (src_total_size, max_ipos); |
| 375 | |
| 376 | /* If the input file shrank after growing, stop copying. */ |
| 377 | if (src_total_size <= ext_start) |
| 378 | break; |
| 379 | |
| 380 | ext_end = src_total_size; |
| 381 | } |
| 382 | } |
| 383 | /* If the input file must have grown, increase its measured size. */ |
no test coverage detected