bug#79267: cp --sparse=auto heuristic fails on a squashfs mounted drive.

Paul Eggert <[email protected]>
Newsgroups gmane.comp.gnu.core-utils.bugs
Message-ID <[email protected]>
Thanks for the bug report. Although this part of the code is messy and 
needs a revamp, in the meantime I installed the attached into the master 
branch on Savannah; please give it a try.
0001-cp-always-punch-holes-that-we-make.patch (text/x-patch, 4.9 KB)
From b7fc76269bbc830bf96320cd5cca3cfd90d33f68 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Thu, 21 Aug 2025 16:02:10 -0600
Subject: [PATCH] cp: always punch holes that we make

Problem reported by Jeremy Allison <https://bugs.gnu.org/79267>.
* src/copy.c (create_hole, sparse_copy): Omit arg PUNCH_HOLES,
as we always punch holes now.  All uses changed.
(lseek_copy): When calling sparse_copy, scan for holes when
sparse_mode == SPARSE_AUTO, as that means we are making holes.
(copy_reg): Always punch any hole made at end.
---
 src/copy.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index 77f0c561e..e328bd886 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -253,12 +253,11 @@ punch_hole (int fd, off_t offset, off_t length)
 }
 
 /* Create a hole at the end of the file with descriptor FD and name NAME.
-   If PUNCH_HOLES, avoid preallocation if requested.
    The hole is of size SIZE.  Assume FD is already at file end,
    and advance FD past the newly-created hole.  */
 
 static bool
-create_hole (int fd, char const *name, bool punch_holes, off_t size)
+create_hole (int fd, char const *name, off_t size)
 {
   off_t file_end = lseek (fd, size, SEEK_CUR);
 
@@ -272,7 +271,7 @@ create_hole (int fd, char const *name, bool punch_holes, off_t size)
      I.e., a previous write() may have preallocated extra space
      that the seek above will not discard.  A subsequent write() could
      then make this allocation permanent.  */
-  if (punch_holes && punch_hole (fd, file_end - size, size) < 0)
+  if (punch_hole (fd, file_end - size, size) < 0)
     {
       error (0, errno, _("error deallocating %s"), quoteaf (name));
       return false;
@@ -311,7 +310,6 @@ is_CLONENOTSUP (int err)
    honoring the MAKE_HOLES setting and using the BUF_SIZE-byte buffer
    *ABUF for temporary storage, allocating it lazily if *ABUF is null.
    For best results, *ABUF should be well-aligned.
-   If PUNCH_HOLES, punch holes in the output.
    Copy no more than MAX_N_READ bytes.
    If HOLE_SIZE, look for holes in the input; *HOLE_SIZE contains
    the size of the current hole so far, and update *HOLE_SIZE
@@ -322,7 +320,7 @@ is_CLONENOTSUP (int err)
    print a diagnostic and return false upon error.  */
 static bool
 sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
-             bool punch_holes, bool allow_reflink,
+             bool allow_reflink,
              char const *src_name, char const *dst_name,
              uintmax_t max_n_read, off_t *hole_size, off_t *total_n_read)
 {
@@ -437,7 +435,7 @@ sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
                 psize += csize;
               else if (prev_hole)
                 {
-                  if (! create_hole (dest_fd, dst_name, punch_holes, psize))
+                  if (! create_hole (dest_fd, dst_name, psize))
                     return false;
                   pbuf = cbuf;
                   psize = csize;
@@ -591,9 +589,7 @@ lseek_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
             *hole_size += ext_hole_size;
           else if (sparse_mode != SPARSE_NEVER)
             {
-              if (! create_hole (dest_fd, dst_name,
-                                 sparse_mode == SPARSE_ALWAYS,
-                                 ext_hole_size))
+              if (! create_hole (dest_fd, dst_name, ext_hole_size))
                 return false;
             }
           else
@@ -619,9 +615,9 @@ lseek_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
          is conservative and may miss some holes.  */
       off_t n_read;
       if ( ! sparse_copy (src_fd, dest_fd, abuf, buf_size,
-                          true, allow_reflink, src_name, dst_name,
+                          allow_reflink, src_name, dst_name,
                           ext_len,
-                          sparse_mode == SPARSE_ALWAYS ? hole_size : nullptr,
+                          sparse_mode != SPARSE_NEVER ? hole_size : nullptr,
                           &n_read))
         return false;
 
@@ -1576,7 +1572,6 @@ copy_reg (char const *src_name, char const *dst_name,
              :
 #endif
                sparse_copy (source_desc, dest_desc, &buf, buf_size,
-                            x->sparse_mode == SPARSE_ALWAYS,
                             x->reflink_mode != REFLINK_NEVER,
                             src_name, dst_name, UINTMAX_MAX,
                             make_holes ? &hole_size : nullptr, &n_read)))
@@ -1594,7 +1589,7 @@ copy_reg (char const *src_name, char const *dst_name,
               return_val = false;
               goto close_src_and_dst_desc;
             }
-          if (x->sparse_mode == SPARSE_ALWAYS
+          if (make_holes
               && punch_hole (dest_desc, n_read - hole_size, hole_size) < 0)
             {
               error (0, errno, _("error deallocating %s"), quoteaf (dst_name));
-- 
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.