Kamil Dudka 1737e5
From 5f2dac18054d9d9b3d84e7fba8c2a6e750d2c245 Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Kamil Dudka 1737e5
Date: Wed, 1 Apr 2020 12:51:34 +0100
Kamil Dudka 1737e5
Subject: [PATCH 1/6] cp: ensure --attributes-only doesn't remove files
Kamil Dudka 1737e5
Kamil Dudka 1737e5
* src/copy.c (copy_internal): Ensure we don't unlink the destination
Kamil Dudka 1737e5
unless explicitly requested.
Kamil Dudka 1737e5
* tests/cp/attr-existing.sh: Add test cases.
Kamil Dudka 1737e5
* NEWS: Mention the bug fix.
Kamil Dudka 1737e5
Fixes https://bugs.gnu.org/40352
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Upstream-commit: 7b5f0fa47cd04c84975250d5b5da7c98e097e99f
Kamil Dudka 1737e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 src/copy.c                |  9 +++++----
Kamil Dudka 1737e5
 tests/cp/attr-existing.sh | 21 ++++++++++++++++++---
Kamil Dudka 1737e5
 2 files changed, 23 insertions(+), 7 deletions(-)
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 1737e5
index 6e5efc7..54601ce 100644
Kamil Dudka 1737e5
--- a/src/copy.c
Kamil Dudka 1737e5
+++ b/src/copy.c
Kamil Dudka 1737e5
@@ -2211,10 +2211,11 @@ copy_internal (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
                    /* Never unlink dst_name when in move mode.  */
Kamil Dudka 1737e5
                    && ! x->move_mode
Kamil Dudka 1737e5
                    && (x->unlink_dest_before_opening
Kamil Dudka 1737e5
-                       || (x->preserve_links && 1 < dst_sb.st_nlink)
Kamil Dudka 1737e5
-                       || (x->dereference == DEREF_NEVER
Kamil Dudka 1737e5
-                           && ! S_ISREG (src_sb.st_mode))
Kamil Dudka 1737e5
-                       ))
Kamil Dudka 1737e5
+                       || (x->data_copy_required
Kamil Dudka 1737e5
+                           && ((x->preserve_links && 1 < dst_sb.st_nlink)
Kamil Dudka 1737e5
+                               || (x->dereference == DEREF_NEVER
Kamil Dudka 1737e5
+                                   && ! S_ISREG (src_sb.st_mode))))
Kamil Dudka 1737e5
+                      ))
Kamil Dudka 1737e5
             {
Kamil Dudka 1737e5
               if (unlink (dst_name) != 0 && errno != ENOENT)
Kamil Dudka 1737e5
                 {
Kamil Dudka 1737e5
diff --git a/tests/cp/attr-existing.sh b/tests/cp/attr-existing.sh
Kamil Dudka 1737e5
index 59ce641..14fc844 100755
Kamil Dudka 1737e5
--- a/tests/cp/attr-existing.sh
Kamil Dudka 1737e5
+++ b/tests/cp/attr-existing.sh
Kamil Dudka 1737e5
@@ -19,11 +19,26 @@
Kamil Dudka 1737e5
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
Kamil Dudka 1737e5
 print_ver_ cp
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-printf '1' > file1
Kamil Dudka 1737e5
-printf '2' > file2
Kamil Dudka 1737e5
-printf '2' > file2.exp
Kamil Dudka 1737e5
+printf '1' > file1 || framework_failure_
Kamil Dudka 1737e5
+printf '2' > file2 || framework_failure_
Kamil Dudka 1737e5
+printf '2' > file2.exp || framework_failure_
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
 cp --attributes-only file1 file2 || fail=1
Kamil Dudka 1737e5
 cmp file2 file2.exp || fail=1
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+# coreutils v8.32 and before would remove destination files
Kamil Dudka 1737e5
+# if hardlinked or the source was not a regular file.
Kamil Dudka 1737e5
+ln file2 link2 || framework_failure_
Kamil Dudka 1737e5
+cp -a --attributes-only file1 file2 || fail=1
Kamil Dudka 1737e5
+cmp file2 file2.exp || fail=1
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+ln -s file1 sym1 || framework_failure_
Kamil Dudka 1737e5
+returns_ 1 cp -a --attributes-only sym1 file2 || fail=1
Kamil Dudka 1737e5
+cmp file2 file2.exp || fail=1
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+# One can still force removal though
Kamil Dudka 1737e5
+cp -a --remove-destination --attributes-only sym1 file2 || fail=1
Kamil Dudka 1737e5
+test -L file2 || fail=1
Kamil Dudka 1737e5
+cmp file1 file2 || fail=1
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
 Exit $fail
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Kamil Dudka 1737e5
From c728747b06e71894c96d1f27434f2484af992c75 Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: Paul Eggert <eggert@cs.ucla.edu>
Kamil Dudka 1737e5
Date: Tue, 23 Jun 2020 19:18:04 -0700
Kamil Dudka 1737e5
Subject: [PATCH 2/6] cp: refactor extent_copy
Kamil Dudka 1737e5
Kamil Dudka 1737e5
* src/copy.c (extent_copy): New arg SCAN, replacing
Kamil Dudka 1737e5
REQUIRE_NORMAL_COPY.  All callers changed.
Kamil Dudka 1737e5
(enum scantype): New type.
Kamil Dudka 1737e5
(infer_scantype): Rename from is_probably_sparse and return
Kamil Dudka 1737e5
the new type.  Add args FD and SCAN.  All callers changed.
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Upstream-commit: 761ba28400a04ee24eefe9cd4973ec8850cd7a52
Kamil Dudka 1737e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 src/copy.c | 119 +++++++++++++++++++++++++----------------------------
Kamil Dudka 1737e5
 1 file changed, 55 insertions(+), 64 deletions(-)
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 1737e5
index 54601ce..f694f91 100644
Kamil Dudka 1737e5
--- a/src/copy.c
Kamil Dudka 1737e5
+++ b/src/copy.c
Kamil Dudka 1737e5
@@ -422,9 +422,8 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
              size_t hole_size, off_t src_total_size,
Kamil Dudka 1737e5
              enum Sparse_type sparse_mode,
Kamil Dudka 1737e5
              char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
-             bool *require_normal_copy)
Kamil Dudka 1737e5
+             struct extent_scan *scan)
Kamil Dudka 1737e5
 {
Kamil Dudka 1737e5
-  struct extent_scan scan;
Kamil Dudka 1737e5
   off_t last_ext_start = 0;
Kamil Dudka 1737e5
   off_t last_ext_len = 0;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -432,45 +431,25 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
      We may need this at the end, for a final ftruncate.  */
Kamil Dudka 1737e5
   off_t dest_pos = 0;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-  extent_scan_init (src_fd, &scan;;
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-  *require_normal_copy = false;
Kamil Dudka 1737e5
   bool wrote_hole_at_eof = true;
Kamil Dudka 1737e5
-  do
Kamil Dudka 1737e5
+  while (true)
Kamil Dudka 1737e5
     {
Kamil Dudka 1737e5
-      bool ok = extent_scan_read (&scan;;
Kamil Dudka 1737e5
-      if (! ok)
Kamil Dudka 1737e5
-        {
Kamil Dudka 1737e5
-          if (scan.hit_final_extent)
Kamil Dudka 1737e5
-            break;
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-          if (scan.initial_scan_failed)
Kamil Dudka 1737e5
-            {
Kamil Dudka 1737e5
-              *require_normal_copy = true;
Kamil Dudka 1737e5
-              return false;
Kamil Dudka 1737e5
-            }
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-          error (0, errno, _("%s: failed to get extents info"),
Kamil Dudka 1737e5
-                 quotef (src_name));
Kamil Dudka 1737e5
-          return false;
Kamil Dudka 1737e5
-        }
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
       bool empty_extent = false;
Kamil Dudka 1737e5
-      for (unsigned int i = 0; i < scan.ei_count || empty_extent; i++)
Kamil Dudka 1737e5
+      for (unsigned int i = 0; i < scan->ei_count || empty_extent; i++)
Kamil Dudka 1737e5
         {
Kamil Dudka 1737e5
           off_t ext_start;
Kamil Dudka 1737e5
           off_t ext_len;
Kamil Dudka 1737e5
           off_t ext_hole_size;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-          if (i < scan.ei_count)
Kamil Dudka 1737e5
+          if (i < scan->ei_count)
Kamil Dudka 1737e5
             {
Kamil Dudka 1737e5
-              ext_start = scan.ext_info[i].ext_logical;
Kamil Dudka 1737e5
-              ext_len = scan.ext_info[i].ext_length;
Kamil Dudka 1737e5
+              ext_start = scan->ext_info[i].ext_logical;
Kamil Dudka 1737e5
+              ext_len = scan->ext_info[i].ext_length;
Kamil Dudka 1737e5
             }
Kamil Dudka 1737e5
           else /* empty extent at EOF.  */
Kamil Dudka 1737e5
             {
Kamil Dudka 1737e5
               i--;
Kamil Dudka 1737e5
-              ext_start = last_ext_start + scan.ext_info[i].ext_length;
Kamil Dudka 1737e5
+              ext_start = last_ext_start + scan->ext_info[i].ext_length;
Kamil Dudka 1737e5
               ext_len = 0;
Kamil Dudka 1737e5
             }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -498,7 +477,7 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
                 {
Kamil Dudka 1737e5
                   error (0, errno, _("cannot lseek %s"), quoteaf (src_name));
Kamil Dudka 1737e5
                 fail:
Kamil Dudka 1737e5
-                  extent_scan_free (&scan;;
Kamil Dudka 1737e5
+                  extent_scan_free (scan);
Kamil Dudka 1737e5
                   return false;
Kamil Dudka 1737e5
                 }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -539,7 +518,7 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
           /* For now, do not treat FIEMAP_EXTENT_UNWRITTEN specially,
Kamil Dudka 1737e5
              because that (in combination with no sync) would lead to data
Kamil Dudka 1737e5
              loss at least on XFS and ext4 when using 2.6.39-rc3 kernels.  */
Kamil Dudka 1737e5
-          if (0 && (scan.ext_info[i].ext_flags & FIEMAP_EXTENT_UNWRITTEN))
Kamil Dudka 1737e5
+          if (0 && (scan->ext_info[i].ext_flags & FIEMAP_EXTENT_UNWRITTEN))
Kamil Dudka 1737e5
             {
Kamil Dudka 1737e5
               empty_extent = true;
Kamil Dudka 1737e5
               last_ext_len = 0;
Kamil Dudka 1737e5
@@ -571,16 +550,23 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
              extents beyond the apparent size.  */
Kamil Dudka 1737e5
           if (dest_pos == src_total_size)
Kamil Dudka 1737e5
             {
Kamil Dudka 1737e5
-              scan.hit_final_extent = true;
Kamil Dudka 1737e5
+              scan->hit_final_extent = true;
Kamil Dudka 1737e5
               break;
Kamil Dudka 1737e5
             }
Kamil Dudka 1737e5
         }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
       /* Release the space allocated to scan->ext_info.  */
Kamil Dudka 1737e5
-      extent_scan_free (&scan;;
Kamil Dudka 1737e5
+      extent_scan_free (scan);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+      if (scan->hit_final_extent)
Kamil Dudka 1737e5
+        break;
Kamil Dudka 1737e5
+      if (! extent_scan_read (scan) && ! scan->hit_final_extent)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          error (0, errno, _("%s: failed to get extents info"),
Kamil Dudka 1737e5
+                 quotef (src_name));
Kamil Dudka 1737e5
+          return false;
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
     }
Kamil Dudka 1737e5
-  while (! scan.hit_final_extent);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
   /* When the source file ends with a hole, we have to do a little more work,
Kamil Dudka 1737e5
      since the above copied only up to and including the final extent.
Kamil Dudka 1737e5
@@ -1021,16 +1007,35 @@ fchmod_or_lchmod (int desc, char const *name, mode_t mode)
Kamil Dudka 1737e5
 # define HAVE_STRUCT_STAT_ST_BLOCKS 0
Kamil Dudka 1737e5
 #endif
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+/* Type of scan being done on the input when looking for sparseness.  */
Kamil Dudka 1737e5
+enum scantype
Kamil Dudka 1737e5
+  {
Kamil Dudka 1737e5
+   /* No fancy scanning; just read and write.  */
Kamil Dudka 1737e5
+   PLAIN_SCANTYPE,
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   /* Read and examine data looking for zero blocks; useful when
Kamil Dudka 1737e5
+      attempting to create sparse output.  */
Kamil Dudka 1737e5
+   ZERO_SCANTYPE,
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   /* Extent information is available.  */
Kamil Dudka 1737e5
+   EXTENT_SCANTYPE
Kamil Dudka 1737e5
+  };
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
 /* Use a heuristic to determine whether stat buffer SB comes from a file
Kamil Dudka 1737e5
    with sparse blocks.  If the file has fewer blocks than would normally
Kamil Dudka 1737e5
    be needed for a file of its size, then at least one of the blocks in
Kamil Dudka 1737e5
    the file is a hole.  In that case, return true.  */
Kamil Dudka 1737e5
-static bool
Kamil Dudka 1737e5
-is_probably_sparse (struct stat const *sb)
Kamil Dudka 1737e5
+static enum scantype
Kamil Dudka 1737e5
+infer_scantype (int fd, struct stat const *sb, struct extent_scan *scan)
Kamil Dudka 1737e5
 {
Kamil Dudka 1737e5
-  return (HAVE_STRUCT_STAT_ST_BLOCKS
Kamil Dudka 1737e5
-          && S_ISREG (sb->st_mode)
Kamil Dudka 1737e5
-          && ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE);
Kamil Dudka 1737e5
+  if (! (HAVE_STRUCT_STAT_ST_BLOCKS
Kamil Dudka 1737e5
+         && S_ISREG (sb->st_mode)
Kamil Dudka 1737e5
+         && ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE))
Kamil Dudka 1737e5
+    return PLAIN_SCANTYPE;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  extent_scan_init (fd, scan);
Kamil Dudka 1737e5
+  extent_scan_read (scan);
Kamil Dudka 1737e5
+  return scan->initial_scan_failed ? ZERO_SCANTYPE : EXTENT_SCANTYPE;
Kamil Dudka 1737e5
 }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -1061,6 +1066,7 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
   mode_t src_mode = src_sb->st_mode;
Kamil Dudka 1737e5
   struct stat sb;
Kamil Dudka 1737e5
   struct stat src_open_sb;
Kamil Dudka 1737e5
+  struct extent_scan scan;
Kamil Dudka 1737e5
   bool return_val = true;
Kamil Dudka 1737e5
   bool data_copy_required = x->data_copy_required;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -1260,23 +1266,13 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
       fdadvise (source_desc, 0, 0, FADVISE_SEQUENTIAL);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
       /* Deal with sparse files.  */
Kamil Dudka 1737e5
-      bool make_holes = false;
Kamil Dudka 1737e5
-      bool sparse_src = is_probably_sparse (&src_open_sb);
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-      if (S_ISREG (sb.st_mode))
Kamil Dudka 1737e5
-        {
Kamil Dudka 1737e5
-          /* Even with --sparse=always, try to create holes only
Kamil Dudka 1737e5
-             if the destination is a regular file.  */
Kamil Dudka 1737e5
-          if (x->sparse_mode == SPARSE_ALWAYS)
Kamil Dudka 1737e5
-            make_holes = true;
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-          /* Use a heuristic to determine whether SRC_NAME contains any sparse
Kamil Dudka 1737e5
-             blocks.  If the file has fewer blocks than would normally be
Kamil Dudka 1737e5
-             needed for a file of its size, then at least one of the blocks in
Kamil Dudka 1737e5
-             the file is a hole.  */
Kamil Dudka 1737e5
-          if (x->sparse_mode == SPARSE_AUTO && sparse_src)
Kamil Dudka 1737e5
-            make_holes = true;
Kamil Dudka 1737e5
-        }
Kamil Dudka 1737e5
+      enum scantype scantype = infer_scantype (source_desc, &src_open_sb,
Kamil Dudka 1737e5
+                                               &scan;;
Kamil Dudka 1737e5
+      bool make_holes
Kamil Dudka 1737e5
+        = (S_ISREG (sb.st_mode)
Kamil Dudka 1737e5
+           && (x->sparse_mode == SPARSE_ALWAYS
Kamil Dudka 1737e5
+               || (x->sparse_mode == SPARSE_AUTO
Kamil Dudka 1737e5
+                   && scantype != PLAIN_SCANTYPE)));
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
       /* If not making a sparse file, try to use a more-efficient
Kamil Dudka 1737e5
          buffer size.  */
Kamil Dudka 1737e5
@@ -1305,10 +1301,8 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
       buf_alloc = xmalloc (buf_size + buf_alignment);
Kamil Dudka 1737e5
       buf = ptr_align (buf_alloc, buf_alignment);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-      if (sparse_src)
Kamil Dudka 1737e5
+      if (scantype == EXTENT_SCANTYPE)
Kamil Dudka 1737e5
         {
Kamil Dudka 1737e5
-          bool normal_copy_required;
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
           /* Perform an efficient extent-based copy, falling back to the
Kamil Dudka 1737e5
              standard copy only if the initial extent scan fails.  If the
Kamil Dudka 1737e5
              '--sparse=never' option is specified, write all data but use
Kamil Dudka 1737e5
@@ -1316,14 +1310,11 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
           if (extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,
Kamil Dudka 1737e5
                            src_open_sb.st_size,
Kamil Dudka 1737e5
                            make_holes ? x->sparse_mode : SPARSE_NEVER,
Kamil Dudka 1737e5
-                           src_name, dst_name, &normal_copy_required))
Kamil Dudka 1737e5
+                           src_name, dst_name, &scan))
Kamil Dudka 1737e5
             goto preserve_metadata;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-          if (! normal_copy_required)
Kamil Dudka 1737e5
-            {
Kamil Dudka 1737e5
-              return_val = false;
Kamil Dudka 1737e5
-              goto close_src_and_dst_desc;
Kamil Dudka 1737e5
-            }
Kamil Dudka 1737e5
+          return_val = false;
Kamil Dudka 1737e5
+          goto close_src_and_dst_desc;
Kamil Dudka 1737e5
         }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
       off_t n_read;
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Kamil Dudka 1737e5
From ed7ff81de507bef46991f4caac550f41ab65e3ed Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: Paul Eggert <eggert@cs.ucla.edu>
Kamil Dudka 1737e5
Date: Wed, 24 Jun 2020 17:05:20 -0700
Kamil Dudka 1737e5
Subject: [PATCH 3/6] cp: avoid copy_reg goto
Kamil Dudka 1737e5
Kamil Dudka 1737e5
* src/copy.c (copy_reg): Redo to avoid label and goto.
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Upstream-commit: 2fcd0f3328f5181a2986905fa5469a0152c67279
Kamil Dudka 1737e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 src/copy.c | 34 +++++++++++-----------------------
Kamil Dudka 1737e5
 1 file changed, 11 insertions(+), 23 deletions(-)
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 1737e5
index f694f91..b382cfa 100644
Kamil Dudka 1737e5
--- a/src/copy.c
Kamil Dudka 1737e5
+++ b/src/copy.c
Kamil Dudka 1737e5
@@ -1301,29 +1301,18 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
       buf_alloc = xmalloc (buf_size + buf_alignment);
Kamil Dudka 1737e5
       buf = ptr_align (buf_alloc, buf_alignment);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-      if (scantype == EXTENT_SCANTYPE)
Kamil Dudka 1737e5
-        {
Kamil Dudka 1737e5
-          /* Perform an efficient extent-based copy, falling back to the
Kamil Dudka 1737e5
-             standard copy only if the initial extent scan fails.  If the
Kamil Dudka 1737e5
-             '--sparse=never' option is specified, write all data but use
Kamil Dudka 1737e5
-             any extents to read more efficiently.  */
Kamil Dudka 1737e5
-          if (extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,
Kamil Dudka 1737e5
-                           src_open_sb.st_size,
Kamil Dudka 1737e5
-                           make_holes ? x->sparse_mode : SPARSE_NEVER,
Kamil Dudka 1737e5
-                           src_name, dst_name, &scan))
Kamil Dudka 1737e5
-            goto preserve_metadata;
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
-          return_val = false;
Kamil Dudka 1737e5
-          goto close_src_and_dst_desc;
Kamil Dudka 1737e5
-        }
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
       off_t n_read;
Kamil Dudka 1737e5
-      bool wrote_hole_at_eof;
Kamil Dudka 1737e5
-      if (! sparse_copy (source_desc, dest_desc, buf, buf_size,
Kamil Dudka 1737e5
-                         make_holes ? hole_size : 0,
Kamil Dudka 1737e5
-                         x->sparse_mode == SPARSE_ALWAYS, src_name, dst_name,
Kamil Dudka 1737e5
-                         UINTMAX_MAX, &n_read,
Kamil Dudka 1737e5
-                         &wrote_hole_at_eof))
Kamil Dudka 1737e5
+      bool wrote_hole_at_eof = false;
Kamil Dudka 1737e5
+      if (! (scantype == EXTENT_SCANTYPE
Kamil Dudka 1737e5
+             ? extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,
Kamil Dudka 1737e5
+                            src_open_sb.st_size,
Kamil Dudka 1737e5
+                            make_holes ? x->sparse_mode : SPARSE_NEVER,
Kamil Dudka 1737e5
+                            src_name, dst_name, &scan)
Kamil Dudka 1737e5
+             : sparse_copy (source_desc, dest_desc, buf, buf_size,
Kamil Dudka 1737e5
+                            make_holes ? hole_size : 0,
Kamil Dudka 1737e5
+                            x->sparse_mode == SPARSE_ALWAYS,
Kamil Dudka 1737e5
+                            src_name, dst_name, UINTMAX_MAX, &n_read,
Kamil Dudka 1737e5
+                            &wrote_hole_at_eof)))
Kamil Dudka 1737e5
         {
Kamil Dudka 1737e5
           return_val = false;
Kamil Dudka 1737e5
           goto close_src_and_dst_desc;
Kamil Dudka 1737e5
@@ -1336,7 +1325,6 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
         }
Kamil Dudka 1737e5
     }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-preserve_metadata:
Kamil Dudka 1737e5
   if (x->preserve_timestamps)
Kamil Dudka 1737e5
     {
Kamil Dudka 1737e5
       struct timespec timespec[2];
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Kamil Dudka 1737e5
From 5631bded3a385ca0bbd77456b50767fe5580240c Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: Paul Eggert <eggert@cs.ucla.edu>
Kamil Dudka 1737e5
Date: Thu, 25 Jun 2020 16:31:44 -0700
Kamil Dudka 1737e5
Subject: [PATCH 4/6] cp: use SEEK_DATA/SEEK_HOLE if available
Kamil Dudka 1737e5
Kamil Dudka 1737e5
If it works, prefer lseek with SEEK_DATA and SEEK_HOLE to FIEMAP,
Kamil Dudka 1737e5
as lseek is simpler and more portable (will be in next POSIX).
Kamil Dudka 1737e5
Problem reported in 2011 by Jeff Liu (Bug#8061).
Kamil Dudka 1737e5
* NEWS: Mention this.
Kamil Dudka 1737e5
* src/copy.c (lseek_copy) [SEEK_HOLE]: New function.
Kamil Dudka 1737e5
(enum scantype): New constants ERROR_SCANTYPE, LSEEK_SCANTYPE.
Kamil Dudka 1737e5
(union scan_inference): New type.
Kamil Dudka 1737e5
(infer_scantype): Last arg is now union scan_inference *,
Kamil Dudka 1737e5
not struct extent_scan *.  All callers changed.
Kamil Dudka 1737e5
Prefer SEEK_HOLE to FIEMAP if both work, since
Kamil Dudka 1737e5
SEEK_HOLE is simpler and more portable.
Kamil Dudka 1737e5
(copy_reg): Do the fdadvise after initial scan, in case the scan
Kamil Dudka 1737e5
fails.  Report an error if the initial scan fails.
Kamil Dudka 1737e5
(copy_reg) [SEEK_HOLE]: Use lseek_copy if scantype says so.
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Upstream-commit: a6eaee501f6ec0c152abe88640203a64c390993e
Kamil Dudka 1737e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 src/copy.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++---
Kamil Dudka 1737e5
 1 file changed, 198 insertions(+), 11 deletions(-)
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 1737e5
index b382cfa..d88f8cf 100644
Kamil Dudka 1737e5
--- a/src/copy.c
Kamil Dudka 1737e5
+++ b/src/copy.c
Kamil Dudka 1737e5
@@ -416,7 +416,12 @@ write_zeros (int fd, off_t n_bytes)
Kamil Dudka 1737e5
    Upon a successful copy, return true.  If the initial extent scan
Kamil Dudka 1737e5
    fails, set *NORMAL_COPY_REQUIRED to true and return false.
Kamil Dudka 1737e5
    Upon any other failure, set *NORMAL_COPY_REQUIRED to false and
Kamil Dudka 1737e5
-   return false.  */
Kamil Dudka 1737e5
+   return false.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   FIXME: Once we no longer need to support Linux kernel versions
Kamil Dudka 1737e5
+   before 3.1 (2011), this function can be retired as it is superseded
Kamil Dudka 1737e5
+   by lseek_copy.  That is, we no longer need extent-scan.h and can
Kamil Dudka 1737e5
+   remove any of the code that uses it.  */
Kamil Dudka 1737e5
 static bool
Kamil Dudka 1737e5
 extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
              size_t hole_size, off_t src_total_size,
Kamil Dudka 1737e5
@@ -595,6 +600,150 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
   return true;
Kamil Dudka 1737e5
 }
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+#ifdef SEEK_HOLE
Kamil Dudka 1737e5
+/* Perform an efficient extent copy, if possible.  This avoids
Kamil Dudka 1737e5
+   the overhead of detecting holes in hole-introducing/preserving
Kamil Dudka 1737e5
+   copy, and thus makes copying sparse files much more efficient.
Kamil Dudka 1737e5
+   Copy from SRC_FD to DEST_FD, using BUF (of size BUF_SIZE) for a buffer.
Kamil Dudka 1737e5
+   Look for holes of size HOLE_SIZE in the input.
Kamil Dudka 1737e5
+   The input file is of size SRC_TOTAL_SIZE.
Kamil Dudka 1737e5
+   Use SPARSE_MODE to determine whether to create holes in the output.
Kamil Dudka 1737e5
+   SRC_NAME and DST_NAME are the input and output file names.
Kamil Dudka 1737e5
+   Return true if successful, false (with a diagnostic) otherwise.  */
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+static bool
Kamil Dudka 1737e5
+lseek_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
+            size_t hole_size, off_t ext_start, off_t src_total_size,
Kamil Dudka 1737e5
+            enum Sparse_type sparse_mode,
Kamil Dudka 1737e5
+            char const *src_name, char const *dst_name)
Kamil Dudka 1737e5
+{
Kamil Dudka 1737e5
+  off_t last_ext_start = 0;
Kamil Dudka 1737e5
+  off_t last_ext_len = 0;
Kamil Dudka 1737e5
+  off_t dest_pos = 0;
Kamil Dudka 1737e5
+  bool wrote_hole_at_eof = true;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  while (0 <= ext_start)
Kamil Dudka 1737e5
+    {
Kamil Dudka 1737e5
+      off_t ext_end = lseek (src_fd, ext_start, SEEK_HOLE);
Kamil Dudka 1737e5
+      if (ext_end < 0)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          if (errno != ENXIO)
Kamil Dudka 1737e5
+            goto cannot_lseek;
Kamil Dudka 1737e5
+          ext_end = src_total_size;
Kamil Dudka 1737e5
+          if (ext_end <= ext_start)
Kamil Dudka 1737e5
+            {
Kamil Dudka 1737e5
+              /* The input file grew; get its current size.  */
Kamil Dudka 1737e5
+              src_total_size = lseek (src_fd, 0, SEEK_END);
Kamil Dudka 1737e5
+              if (src_total_size < 0)
Kamil Dudka 1737e5
+                goto cannot_lseek;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+              /* If the input file shrank after growing, stop copying.  */
Kamil Dudka 1737e5
+              if (src_total_size <= ext_start)
Kamil Dudka 1737e5
+                break;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+              ext_end = src_total_size;
Kamil Dudka 1737e5
+            }
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
+      /* If the input file must have grown, increase its measured size.  */
Kamil Dudka 1737e5
+      if (src_total_size < ext_end)
Kamil Dudka 1737e5
+        src_total_size = ext_end;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      if (lseek (src_fd, ext_start, SEEK_SET) < 0)
Kamil Dudka 1737e5
+        goto cannot_lseek;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      wrote_hole_at_eof = false;
Kamil Dudka 1737e5
+      off_t ext_hole_size = ext_start - last_ext_start - last_ext_len;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      if (ext_hole_size)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          if (sparse_mode != SPARSE_NEVER)
Kamil Dudka 1737e5
+            {
Kamil Dudka 1737e5
+              if (! create_hole (dest_fd, dst_name,
Kamil Dudka 1737e5
+                                 sparse_mode == SPARSE_ALWAYS,
Kamil Dudka 1737e5
+                                 ext_hole_size))
Kamil Dudka 1737e5
+                return false;
Kamil Dudka 1737e5
+              wrote_hole_at_eof = true;
Kamil Dudka 1737e5
+            }
Kamil Dudka 1737e5
+          else
Kamil Dudka 1737e5
+            {
Kamil Dudka 1737e5
+              /* When not inducing holes and when there is a hole between
Kamil Dudka 1737e5
+                 the end of the previous extent and the beginning of the
Kamil Dudka 1737e5
+                 current one, write zeros to the destination file.  */
Kamil Dudka 1737e5
+              if (! write_zeros (dest_fd, ext_hole_size))
Kamil Dudka 1737e5
+                {
Kamil Dudka 1737e5
+                  error (0, errno, _("%s: write failed"),
Kamil Dudka 1737e5
+                         quotef (dst_name));
Kamil Dudka 1737e5
+                  return false;
Kamil Dudka 1737e5
+                }
Kamil Dudka 1737e5
+            }
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      off_t ext_len = ext_end - ext_start;
Kamil Dudka 1737e5
+      last_ext_start = ext_start;
Kamil Dudka 1737e5
+      last_ext_len = ext_len;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      /* Copy this extent, looking for further opportunities to not
Kamil Dudka 1737e5
+         bother to write zeros unless --sparse=never, since SEEK_HOLE
Kamil Dudka 1737e5
+         is conservative and may miss some holes.  */
Kamil Dudka 1737e5
+      off_t n_read;
Kamil Dudka 1737e5
+      bool read_hole;
Kamil Dudka 1737e5
+      if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
Kamil Dudka 1737e5
+                          sparse_mode == SPARSE_NEVER ? 0 : hole_size,
Kamil Dudka 1737e5
+                          true, src_name, dst_name, ext_len, &n_read,
Kamil Dudka 1737e5
+                          &read_hole))
Kamil Dudka 1737e5
+        return false;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      dest_pos = ext_start + n_read;
Kamil Dudka 1737e5
+      if (n_read)
Kamil Dudka 1737e5
+        wrote_hole_at_eof = read_hole;
Kamil Dudka 1737e5
+      if (n_read < ext_len)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          /* The input file shrank.  */
Kamil Dudka 1737e5
+          src_total_size = dest_pos;
Kamil Dudka 1737e5
+          break;
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+      ext_start = lseek (src_fd, dest_pos, SEEK_DATA);
Kamil Dudka 1737e5
+      if (ext_start < 0)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          if (errno != ENXIO)
Kamil Dudka 1737e5
+            goto cannot_lseek;
Kamil Dudka 1737e5
+          break;
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
+    }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  /* When the source file ends with a hole, we have to do a little more work,
Kamil Dudka 1737e5
+     since the above copied only up to and including the final extent.
Kamil Dudka 1737e5
+     In order to complete the copy, we may have to insert a hole or write
Kamil Dudka 1737e5
+     zeros in the destination corresponding to the source file's hole-at-EOF.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+     In addition, if the final extent was a block of zeros at EOF and we've
Kamil Dudka 1737e5
+     just converted them to a hole in the destination, we must call ftruncate
Kamil Dudka 1737e5
+     here in order to record the proper length in the destination.  */
Kamil Dudka 1737e5
+  if ((dest_pos < src_total_size || wrote_hole_at_eof)
Kamil Dudka 1737e5
+      && ! (sparse_mode == SPARSE_NEVER
Kamil Dudka 1737e5
+            ? write_zeros (dest_fd, src_total_size - dest_pos)
Kamil Dudka 1737e5
+            : ftruncate (dest_fd, src_total_size) == 0))
Kamil Dudka 1737e5
+    {
Kamil Dudka 1737e5
+      error (0, errno, _("failed to extend %s"), quoteaf (dst_name));
Kamil Dudka 1737e5
+      return false;
Kamil Dudka 1737e5
+    }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  if (sparse_mode == SPARSE_ALWAYS && dest_pos < src_total_size
Kamil Dudka 1737e5
+      && punch_hole (dest_fd, dest_pos, src_total_size - dest_pos) < 0)
Kamil Dudka 1737e5
+    {
Kamil Dudka 1737e5
+      error (0, errno, _("error deallocating %s"), quoteaf (dst_name));
Kamil Dudka 1737e5
+      return false;
Kamil Dudka 1737e5
+    }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  return true;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+ cannot_lseek:
Kamil Dudka 1737e5
+  error (0, errno, _("cannot lseek %s"), quoteaf (src_name));
Kamil Dudka 1737e5
+  return false;
Kamil Dudka 1737e5
+}
Kamil Dudka 1737e5
+#endif
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
 /* FIXME: describe */
Kamil Dudka 1737e5
 /* FIXME: rewrite this to use a hash table so we avoid the quadratic
Kamil Dudka 1737e5
    performance hit that's probably noticeable only on trees deeper
Kamil Dudka 1737e5
@@ -1010,6 +1159,9 @@ fchmod_or_lchmod (int desc, char const *name, mode_t mode)
Kamil Dudka 1737e5
 /* Type of scan being done on the input when looking for sparseness.  */
Kamil Dudka 1737e5
 enum scantype
Kamil Dudka 1737e5
   {
Kamil Dudka 1737e5
+   /* An error was found when determining scantype.  */
Kamil Dudka 1737e5
+   ERROR_SCANTYPE,
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
    /* No fancy scanning; just read and write.  */
Kamil Dudka 1737e5
    PLAIN_SCANTYPE,
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -1017,22 +1169,44 @@ enum scantype
Kamil Dudka 1737e5
       attempting to create sparse output.  */
Kamil Dudka 1737e5
    ZERO_SCANTYPE,
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+   /* lseek information is available.  */
Kamil Dudka 1737e5
+   LSEEK_SCANTYPE,
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
    /* Extent information is available.  */
Kamil Dudka 1737e5
    EXTENT_SCANTYPE
Kamil Dudka 1737e5
   };
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-/* Use a heuristic to determine whether stat buffer SB comes from a file
Kamil Dudka 1737e5
-   with sparse blocks.  If the file has fewer blocks than would normally
Kamil Dudka 1737e5
-   be needed for a file of its size, then at least one of the blocks in
Kamil Dudka 1737e5
-   the file is a hole.  In that case, return true.  */
Kamil Dudka 1737e5
+/* Result of infer_scantype.  */
Kamil Dudka 1737e5
+union scan_inference
Kamil Dudka 1737e5
+{
Kamil Dudka 1737e5
+  /* Used if infer_scantype returns LSEEK_SCANTYPE.  This is the
Kamil Dudka 1737e5
+     offset of the first data block, or -1 if the file has no data.  */
Kamil Dudka 1737e5
+  off_t ext_start;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  /* Used if infer_scantype returns EXTENT_SCANTYPE.  */
Kamil Dudka 1737e5
+  struct extent_scan extent_scan;
Kamil Dudka 1737e5
+};
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+/* Return how to scan a file with descriptor FD and stat buffer SB.
Kamil Dudka 1737e5
+   Store any information gathered into *SCAN.  */
Kamil Dudka 1737e5
 static enum scantype
Kamil Dudka 1737e5
-infer_scantype (int fd, struct stat const *sb, struct extent_scan *scan)
Kamil Dudka 1737e5
+infer_scantype (int fd, struct stat const *sb,
Kamil Dudka 1737e5
+                union scan_inference *scan_inference)
Kamil Dudka 1737e5
 {
Kamil Dudka 1737e5
   if (! (HAVE_STRUCT_STAT_ST_BLOCKS
Kamil Dudka 1737e5
          && S_ISREG (sb->st_mode)
Kamil Dudka 1737e5
          && ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE))
Kamil Dudka 1737e5
     return PLAIN_SCANTYPE;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+#ifdef SEEK_HOLE
Kamil Dudka 1737e5
+  scan_inference->ext_start = lseek (fd, 0, SEEK_DATA);
Kamil Dudka 1737e5
+  if (0 <= scan_inference->ext_start)
Kamil Dudka 1737e5
+    return LSEEK_SCANTYPE;
Kamil Dudka 1737e5
+  else if (errno != EINVAL && errno != ENOTSUP)
Kamil Dudka 1737e5
+    return errno == ENXIO ? LSEEK_SCANTYPE : ERROR_SCANTYPE;
Kamil Dudka 1737e5
+#endif
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  struct extent_scan *scan = &scan_inference->extent_scan;
Kamil Dudka 1737e5
   extent_scan_init (fd, scan);
Kamil Dudka 1737e5
   extent_scan_read (scan);
Kamil Dudka 1737e5
   return scan->initial_scan_failed ? ZERO_SCANTYPE : EXTENT_SCANTYPE;
Kamil Dudka 1737e5
@@ -1066,7 +1240,7 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
   mode_t src_mode = src_sb->st_mode;
Kamil Dudka 1737e5
   struct stat sb;
Kamil Dudka 1737e5
   struct stat src_open_sb;
Kamil Dudka 1737e5
-  struct extent_scan scan;
Kamil Dudka 1737e5
+  union scan_inference scan_inference;
Kamil Dudka 1737e5
   bool return_val = true;
Kamil Dudka 1737e5
   bool data_copy_required = x->data_copy_required;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
@@ -1263,17 +1437,23 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
       size_t buf_size = io_blksize (sb);
Kamil Dudka 1737e5
       size_t hole_size = ST_BLKSIZE (sb);
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-      fdadvise (source_desc, 0, 0, FADVISE_SEQUENTIAL);
Kamil Dudka 1737e5
-
Kamil Dudka 1737e5
       /* Deal with sparse files.  */
Kamil Dudka 1737e5
       enum scantype scantype = infer_scantype (source_desc, &src_open_sb,
Kamil Dudka 1737e5
-                                               &scan;;
Kamil Dudka 1737e5
+                                               &scan_inference);
Kamil Dudka 1737e5
+      if (scantype == ERROR_SCANTYPE)
Kamil Dudka 1737e5
+        {
Kamil Dudka 1737e5
+          error (0, errno, _("cannot lseek %s"), quoteaf (src_name));
Kamil Dudka 1737e5
+          return_val = false;
Kamil Dudka 1737e5
+          goto close_src_and_dst_desc;
Kamil Dudka 1737e5
+        }
Kamil Dudka 1737e5
       bool make_holes
Kamil Dudka 1737e5
         = (S_ISREG (sb.st_mode)
Kamil Dudka 1737e5
            && (x->sparse_mode == SPARSE_ALWAYS
Kamil Dudka 1737e5
                || (x->sparse_mode == SPARSE_AUTO
Kamil Dudka 1737e5
                    && scantype != PLAIN_SCANTYPE)));
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+      fdadvise (source_desc, 0, 0, FADVISE_SEQUENTIAL);
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
       /* If not making a sparse file, try to use a more-efficient
Kamil Dudka 1737e5
          buffer size.  */
Kamil Dudka 1737e5
       if (! make_holes)
Kamil Dudka 1737e5
@@ -1307,7 +1487,14 @@ copy_reg (char const *src_name, char const *dst_name,
Kamil Dudka 1737e5
              ? extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,
Kamil Dudka 1737e5
                             src_open_sb.st_size,
Kamil Dudka 1737e5
                             make_holes ? x->sparse_mode : SPARSE_NEVER,
Kamil Dudka 1737e5
-                            src_name, dst_name, &scan)
Kamil Dudka 1737e5
+                            src_name, dst_name, &scan_inference.extent_scan)
Kamil Dudka 1737e5
+#ifdef SEEK_HOLE
Kamil Dudka 1737e5
+             : scantype == LSEEK_SCANTYPE
Kamil Dudka 1737e5
+             ? lseek_copy (source_desc, dest_desc, buf, buf_size, hole_size,
Kamil Dudka 1737e5
+                           scan_inference.ext_start, src_open_sb.st_size,
Kamil Dudka 1737e5
+                           make_holes ? x->sparse_mode : SPARSE_NEVER,
Kamil Dudka 1737e5
+                           src_name, dst_name)
Kamil Dudka 1737e5
+#endif
Kamil Dudka 1737e5
              : sparse_copy (source_desc, dest_desc, buf, buf_size,
Kamil Dudka 1737e5
                             make_holes ? hole_size : 0,
Kamil Dudka 1737e5
                             x->sparse_mode == SPARSE_ALWAYS,
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Kamil Dudka 1737e5
From be7466be92d779cfbece418d4de33191ae52ab4a Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
Date: Wed, 24 Mar 2021 16:06:53 +0100
Kamil Dudka 1737e5
Subject: [PATCH 5/6] import the copy-file-range module from gnulib
Kamil Dudka 1737e5
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 aclocal.m4            |  1 +
Kamil Dudka 1737e5
 lib/config.hin        |  3 +++
Kamil Dudka 1737e5
 lib/copy-file-range.c | 33 +++++++++++++++++++++++++++++++++
Kamil Dudka 1737e5
 lib/gnulib.mk         | 10 ++++++++++
Kamil Dudka 1737e5
 m4/copy-file-range.m4 | 36 ++++++++++++++++++++++++++++++++++++
Kamil Dudka 1737e5
 m4/gnulib-comp.m4     |  8 ++++++++
Kamil Dudka 1737e5
 6 files changed, 91 insertions(+)
Kamil Dudka 1737e5
 create mode 100644 lib/copy-file-range.c
Kamil Dudka 1737e5
 create mode 100644 m4/copy-file-range.m4
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/aclocal.m4 b/aclocal.m4
Kamil Dudka 1737e5
index 713f7c5..09a7ea8 100644
Kamil Dudka 1737e5
--- a/aclocal.m4
Kamil Dudka 1737e5
+++ b/aclocal.m4
Kamil Dudka 1737e5
@@ -1163,6 +1163,7 @@ m4_include([m4/closedir.m4])
Kamil Dudka 1737e5
 m4_include([m4/codeset.m4])
Kamil Dudka 1737e5
 m4_include([m4/config-h.m4])
Kamil Dudka 1737e5
 m4_include([m4/configmake.m4])
Kamil Dudka 1737e5
+m4_include([m4/copy-file-range.m4])
Kamil Dudka 1737e5
 m4_include([m4/ctype.m4])
Kamil Dudka 1737e5
 m4_include([m4/cycle-check.m4])
Kamil Dudka 1737e5
 m4_include([m4/d-ino.m4])
Kamil Dudka 1737e5
diff --git a/lib/config.hin b/lib/config.hin
Kamil Dudka 1737e5
index 9769c39..bf9f9f8 100644
Kamil Dudka 1737e5
--- a/lib/config.hin
Kamil Dudka 1737e5
+++ b/lib/config.hin
Kamil Dudka 1737e5
@@ -370,6 +370,9 @@
Kamil Dudka 1737e5
 /* Define to 1 when the gnulib module connect should be tested. */
Kamil Dudka 1737e5
 #undef GNULIB_TEST_CONNECT
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+/* Define to 1 when the gnulib module copy-file-range should be tested. */
Kamil Dudka 1737e5
+#undef GNULIB_TEST_COPY_FILE_RANGE
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
 /* Define to 1 when the gnulib module dirfd should be tested. */
Kamil Dudka 1737e5
 #undef GNULIB_TEST_DIRFD
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
diff --git a/lib/copy-file-range.c b/lib/copy-file-range.c
Kamil Dudka 1737e5
new file mode 100644
Kamil Dudka 1737e5
index 0000000..069f144
Kamil Dudka 1737e5
--- /dev/null
Kamil Dudka 1737e5
+++ b/lib/copy-file-range.c
Kamil Dudka 1737e5
@@ -0,0 +1,33 @@
Kamil Dudka 1737e5
+/* Stub for copy_file_range
Kamil Dudka 1737e5
+   Copyright 2019-2020 Free Software Foundation, Inc.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   This program is free software: you can redistribute it and/or modify
Kamil Dudka 1737e5
+   it under the terms of the GNU General Public License as published by
Kamil Dudka 1737e5
+   the Free Software Foundation; either version 3 of the License, or
Kamil Dudka 1737e5
+   (at your option) any later version.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   This program is distributed in the hope that it will be useful,
Kamil Dudka 1737e5
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
Kamil Dudka 1737e5
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Kamil Dudka 1737e5
+   GNU General Public License for more details.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+   You should have received a copy of the GNU General Public License
Kamil Dudka 1737e5
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+#include <config.h>
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+#include <unistd.h>
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+#include <errno.h>
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+ssize_t
Kamil Dudka 1737e5
+copy_file_range (int infd, off_t *pinoff,
Kamil Dudka 1737e5
+                 int outfd, off_t *poutoff,
Kamil Dudka 1737e5
+                 size_t length, unsigned int flags)
Kamil Dudka 1737e5
+{
Kamil Dudka 1737e5
+  /* There is little need to emulate copy_file_range with read+write,
Kamil Dudka 1737e5
+     since programs that use copy_file_range must fall back on
Kamil Dudka 1737e5
+     read+write anyway.  */
Kamil Dudka 1737e5
+  errno = ENOSYS;
Kamil Dudka 1737e5
+  return -1;
Kamil Dudka 1737e5
+}
Kamil Dudka 1737e5
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
Kamil Dudka 1737e5
index b3633b8..86829f3 100644
Kamil Dudka 1737e5
--- a/lib/gnulib.mk
Kamil Dudka 1737e5
+++ b/lib/gnulib.mk
Kamil Dudka 1737e5
@@ -65,6 +65,7 @@
Kamil Dudka 1737e5
 #  closeout \
Kamil Dudka 1737e5
 #  config-h \
Kamil Dudka 1737e5
 #  configmake \
Kamil Dudka 1737e5
+#  copy-file-range \
Kamil Dudka 1737e5
 #  crypto/md5 \
Kamil Dudka 1737e5
 #  crypto/sha1 \
Kamil Dudka 1737e5
 #  crypto/sha256 \
Kamil Dudka 1737e5
@@ -800,6 +801,15 @@ CLEANFILES += lib/configmake.h lib/configmake.h-t
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
 ## end   gnulib module configmake
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
+## begin gnulib module copy-file-range
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+EXTRA_DIST += lib/copy-file-range.c
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+EXTRA_lib_libcoreutils_a_SOURCES += lib/copy-file-range.c
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+## end   gnulib module copy-file-range
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
 ## begin gnulib module count-leading-zeros
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
 lib_libcoreutils_a_SOURCES += lib/count-leading-zeros.c
Kamil Dudka 1737e5
diff --git a/m4/copy-file-range.m4 b/m4/copy-file-range.m4
Kamil Dudka 1737e5
new file mode 100644
Kamil Dudka 1737e5
index 0000000..5c5a274
Kamil Dudka 1737e5
--- /dev/null
Kamil Dudka 1737e5
+++ b/m4/copy-file-range.m4
Kamil Dudka 1737e5
@@ -0,0 +1,36 @@
Kamil Dudka 1737e5
+# copy-file-range.m4
Kamil Dudka 1737e5
+dnl Copyright 2019-2020 Free Software Foundation, Inc.
Kamil Dudka 1737e5
+dnl This file is free software; the Free Software Foundation
Kamil Dudka 1737e5
+dnl gives unlimited permission to copy and/or distribute it,
Kamil Dudka 1737e5
+dnl with or without modifications, as long as this notice is preserved.
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+AC_DEFUN([gl_FUNC_COPY_FILE_RANGE],
Kamil Dudka 1737e5
+[
Kamil Dudka 1737e5
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  dnl Persuade glibc <unistd.h> to declare copy_file_range.
Kamil Dudka 1737e5
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  dnl Use AC_LINK_IFELSE, rather than AC_CHECK_FUNCS or a variant,
Kamil Dudka 1737e5
+  dnl since we don't want AC_CHECK_FUNCS's checks for glibc stubs.
Kamil Dudka 1737e5
+  dnl Programs that use copy_file_range must fall back on read+write
Kamil Dudka 1737e5
+  dnl anyway, and there's little point to substituting the Gnulib stub
Kamil Dudka 1737e5
+  dnl for a glibc stub.
Kamil Dudka 1737e5
+  AC_CACHE_CHECK([for copy_file_range], [gl_cv_func_copy_file_range],
Kamil Dudka 1737e5
+    [AC_LINK_IFELSE(
Kamil Dudka 1737e5
+       [AC_LANG_PROGRAM(
Kamil Dudka 1737e5
+          [[#include <unistd.h>
Kamil Dudka 1737e5
+          ]],
Kamil Dudka 1737e5
+          [[ssize_t (*func) (int, off_t *, int, off_t, size_t, unsigned)
Kamil Dudka 1737e5
+              = copy_file_range;
Kamil Dudka 1737e5
+            return func (0, 0, 0, 0, 0, 0) & 127;
Kamil Dudka 1737e5
+          ]])
Kamil Dudka 1737e5
+       ],
Kamil Dudka 1737e5
+       [gl_cv_func_copy_file_range=yes],
Kamil Dudka 1737e5
+       [gl_cv_func_copy_file_range=no])
Kamil Dudka 1737e5
+    ])
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  if test "$gl_cv_func_copy_file_range" != yes; then
Kamil Dudka 1737e5
+    HAVE_COPY_FILE_RANGE=0
Kamil Dudka 1737e5
+  fi
Kamil Dudka 1737e5
+])
Kamil Dudka 1737e5
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
Kamil Dudka 1737e5
index dead90e..953e7f0 100644
Kamil Dudka 1737e5
--- a/m4/gnulib-comp.m4
Kamil Dudka 1737e5
+++ b/m4/gnulib-comp.m4
Kamil Dudka 1737e5
@@ -129,6 +129,7 @@ AC_DEFUN([gl_EARLY],
Kamil Dudka 1737e5
   # Code from module configmake:
Kamil Dudka 1737e5
   # Code from module connect:
Kamil Dudka 1737e5
   # Code from module connect-tests:
Kamil Dudka 1737e5
+  # Code from module copy-file-range:
Kamil Dudka 1737e5
   # Code from module count-leading-zeros:
Kamil Dudka 1737e5
   # Code from module count-leading-zeros-tests:
Kamil Dudka 1737e5
   # Code from module crypto/af_alg:
Kamil Dudka 1737e5
@@ -977,6 +978,11 @@ AC_DEFUN([gl_INIT],
Kamil Dudka 1737e5
   gl_DIRENT_MODULE_INDICATOR([closedir])
Kamil Dudka 1737e5
   gl_CONFIG_H
Kamil Dudka 1737e5
   gl_CONFIGMAKE_PREP
Kamil Dudka 1737e5
+  gl_FUNC_COPY_FILE_RANGE
Kamil Dudka 1737e5
+  if test $HAVE_COPY_FILE_RANGE = 0; then
Kamil Dudka 1737e5
+    AC_LIBOBJ([copy-file-range])
Kamil Dudka 1737e5
+  fi
Kamil Dudka 1737e5
+  gl_UNISTD_MODULE_INDICATOR([copy-file-range])
Kamil Dudka 1737e5
   gl_AF_ALG
Kamil Dudka 1737e5
   AC_DEFINE([GL_COMPILE_CRYPTO_STREAM], 1, [Compile Gnulib crypto stream ops.])
Kamil Dudka 1737e5
   AC_REQUIRE([AC_C_RESTRICT])
Kamil Dudka 1737e5
@@ -2746,6 +2752,7 @@ AC_DEFUN([gl_FILE_LIST], [
Kamil Dudka 1737e5
   lib/closeout.c
Kamil Dudka 1737e5
   lib/closeout.h
Kamil Dudka 1737e5
   lib/copy-acl.c
Kamil Dudka 1737e5
+  lib/copy-file-range.c
Kamil Dudka 1737e5
   lib/count-leading-zeros.c
Kamil Dudka 1737e5
   lib/count-leading-zeros.h
Kamil Dudka 1737e5
   lib/creat-safer.c
Kamil Dudka 1737e5
@@ -3438,6 +3445,7 @@ AC_DEFUN([gl_FILE_LIST], [
Kamil Dudka 1737e5
   m4/codeset.m4
Kamil Dudka 1737e5
   m4/config-h.m4
Kamil Dudka 1737e5
   m4/configmake.m4
Kamil Dudka 1737e5
+  m4/copy-file-range.m4
Kamil Dudka 1737e5
   m4/ctype.m4
Kamil Dudka 1737e5
   m4/cycle-check.m4
Kamil Dudka 1737e5
   m4/d-ino.m4
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Kamil Dudka 1737e5
From 48370c95bcf7c25ce021fbd2145062d3d29ae6d5 Mon Sep 17 00:00:00 2001
Kamil Dudka 1737e5
From: Paul Eggert <eggert@cs.ucla.edu>
Kamil Dudka 1737e5
Date: Thu, 25 Jun 2020 17:34:23 -0700
Kamil Dudka 1737e5
Subject: [PATCH 6/6] cp: use copy_file_range if available
Kamil Dudka 1737e5
Kamil Dudka 1737e5
* NEWS: Mention this.
Kamil Dudka 1737e5
* bootstrap.conf (gnulib_modules): Add copy-file-range.
Kamil Dudka 1737e5
* src/copy.c (sparse_copy): Try copy_file_range if not
Kamil Dudka 1737e5
looking for holes.
Kamil Dudka 1737e5
Kamil Dudka 1737e5
Upstream-commit: 4b04a0c3b792d27909670a81d21f2a3b3e0ea563
Kamil Dudka 1737e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 1737e5
---
Kamil Dudka 1737e5
 bootstrap.conf |  1 +
Kamil Dudka 1737e5
 src/copy.c     | 40 ++++++++++++++++++++++++++++++++++++++++
Kamil Dudka 1737e5
 2 files changed, 41 insertions(+)
Kamil Dudka 1737e5
Kamil Dudka 1737e5
diff --git a/bootstrap.conf b/bootstrap.conf
Kamil Dudka 1737e5
index 2a342c1..7d53e28 100644
Kamil Dudka 1737e5
--- a/bootstrap.conf
Kamil Dudka 1737e5
+++ b/bootstrap.conf
Kamil Dudka 1737e5
@@ -54,6 +54,7 @@ gnulib_modules="
Kamil Dudka 1737e5
   closeout
Kamil Dudka 1737e5
   config-h
Kamil Dudka 1737e5
   configmake
Kamil Dudka 1737e5
+  copy-file-range
Kamil Dudka 1737e5
   crypto/md5
Kamil Dudka 1737e5
   crypto/sha1
Kamil Dudka 1737e5
   crypto/sha256
Kamil Dudka 1737e5
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 1737e5
index d88f8cf..4050f69 100644
Kamil Dudka 1737e5
--- a/src/copy.c
Kamil Dudka 1737e5
+++ b/src/copy.c
Kamil Dudka 1737e5
@@ -265,6 +265,46 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
Kamil Dudka 1737e5
 {
Kamil Dudka 1737e5
   *last_write_made_hole = false;
Kamil Dudka 1737e5
   *total_n_read = 0;
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
+  /* If not looking for holes, use copy_file_range if available.  */
Kamil Dudka 1737e5
+  if (!hole_size)
Kamil Dudka 1737e5
+    while (max_n_read)
Kamil Dudka 1737e5
+      {
Kamil Dudka 1737e5
+        /* Copy at most COPY_MAX bytes at a time; this is min
Kamil Dudka 1737e5
+           (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
Kamil Dudka 1737e5
+           surely aligned well.  */
Kamil Dudka 1737e5
+        ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
Kamil Dudka 1737e5
+        ptrdiff_t copy_max = MIN (ssize_max, SIZE_MAX) >> 30 << 30;
Kamil Dudka 1737e5
+        ssize_t n_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
Kamil Dudka 1737e5
+                                            MIN (max_n_read, copy_max), 0);
Kamil Dudka 1737e5
+        if (n_copied == 0)
Kamil Dudka 1737e5
+          {
Kamil Dudka 1737e5
+            /* copy_file_range incorrectly returns 0 when reading from
Kamil Dudka 1737e5
+               the proc file system on the Linux kernel through at
Kamil Dudka 1737e5
+               least 5.6.19 (2020), so fall back on 'read' if the
Kamil Dudka 1737e5
+               input file seems empty.  */
Kamil Dudka 1737e5
+            if (*total_n_read == 0)
Kamil Dudka 1737e5
+              break;
Kamil Dudka 1737e5
+            return true;
Kamil Dudka 1737e5
+          }
Kamil Dudka 1737e5
+        if (n_copied < 0)
Kamil Dudka 1737e5
+          {
Kamil Dudka 1737e5
+            if (errno == ENOSYS || errno == EINVAL
Kamil Dudka 1737e5
+                || errno == EBADF || errno == EXDEV)
Kamil Dudka 1737e5
+              break;
Kamil Dudka 1737e5
+            if (errno == EINTR)
Kamil Dudka 1737e5
+              n_copied = 0;
Kamil Dudka 1737e5
+            else
Kamil Dudka 1737e5
+              {
Kamil Dudka 1737e5
+                error (0, errno, _("error copying %s to %s"),
Kamil Dudka 1737e5
+                       quoteaf_n (0, src_name), quoteaf_n (1, dst_name));
Kamil Dudka 1737e5
+                return false;
Kamil Dudka 1737e5
+              }
Kamil Dudka 1737e5
+          }
Kamil Dudka 1737e5
+        max_n_read -= n_copied;
Kamil Dudka 1737e5
+        *total_n_read += n_copied;
Kamil Dudka 1737e5
+      }
Kamil Dudka 1737e5
+
Kamil Dudka 1737e5
   bool make_hole = false;
Kamil Dudka 1737e5
   off_t psize = 0;
Kamil Dudka 1737e5
 
Kamil Dudka 1737e5
-- 
Kamil Dudka 1737e5
2.26.3
Kamil Dudka 1737e5