[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/3] copy: use copy_file_range
From: |
Goldwyn Rodrigues |
Subject: |
[PATCH 3/3] copy: use copy_file_range |
Date: |
Tue, 31 Jul 2018 11:38:30 -0500 |
From: Goldwyn Rodrigues <address@hidden>
Performs copy_file_range() to perform a copy. This is considers
sparse files and make sure holes are honored by performing
lseek() to SEEK_HOLE/DATA.
---
configure.ac | 1 +
src/copy.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/configure.ac b/configure.ac
index 669e9d1f2..f0bd3be23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -261,6 +261,7 @@ AC_CHECK_FUNCS([gethostid],
gl_ADD_PROG([optional_bin_progs], [hostid]))
AC_CHECK_FUNCS([sigsuspend],
gl_ADD_PROG([optional_bin_progs], [timeout]))
+AC_CHECK_FUNCS(copy_file_range)
gl_WINSIZE_IN_PTEM
diff --git a/src/copy.c b/src/copy.c
index b73aff3a5..7ceb67ec5 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1090,6 +1090,65 @@ out:
return return_val;
}
+#ifdef HAVE_COPY_FILE_RANGE
+static bool
+copy_range(int src_fd, const char *src_name, const struct stat *src_sb,
+ int dst_fd, const char *dst_name, const struct cp_options *x,
+ bool sparse_src)
+{
+ size_t len = src_sb->st_size;
+ ssize_t end, size, ret;
+ loff_t pos_in = 0, pos_out = 0;
+
+ if (len == 0)
+ return false;
+
+ while (pos_out < len)
+ {
+ end = lseek(src_fd, pos_in, SEEK_HOLE);
+ if (end < 0)
+ return false;
+
+ if (end == pos_in)
+ goto hole;
+ size = end - pos_in;
+ ret = copy_file_range(src_fd, &pos_in, dst_fd, &pos_out, size, 0);
+ if (ret < 0)
+ return false;
+ if (pos_out >= len)
+ break;
+hole:
+ end = lseek(src_fd, pos_in, SEEK_DATA);
+ if (end < 0) {
+ /* Hole at the end of file */
+ if (errno == ENXIO)
+ {
+ if (x->sparse_mode == SPARSE_NEVER)
+ end = len;
+ else
+ break;
+ }
+ else
+ return false;
+ }
+ size = end - pos_in;
+ if (x->sparse_mode == SPARSE_NEVER) {
+ if ((lseek(dst_fd, pos_out, SEEK_SET) < 0) ||
+ !write_zeros(dst_fd, size))
+ return false;
+ }
+ pos_in += size;
+ pos_out += size;
+ }
+
+ if ((pos_out < len) && (ftruncate(dst_fd, len) < 0)) {
+ error (0, errno, _("failed to extend %s"), quoteaf (dst_name));
+ return false;
+ }
+
+ return true;
+}
+#endif /* HAVE_COPY_FILE_RANGE */
/* Copy a regular file from SRC_NAME to DST_NAME.
If the source file contains holes, copies holes and blocks of zeros
@@ -1309,6 +1368,7 @@ copy_reg (char const *src_name, char const *dst_name,
{
bool make_holes = false;
bool sparse_src = is_probably_sparse (&src_open_sb);
+ bool copy_range_ok = false;
if (S_ISREG (sb.st_mode))
{
@@ -1325,10 +1385,18 @@ copy_reg (char const *src_name, char const *dst_name,
make_holes = true;
}
- return_val = copy_data(source_desc, src_name, &src_open_sb,
- dest_desc, dst_name, &sb, x, make_holes);
- if (!return_val)
- goto close_src_and_dst_desc;
+#ifdef HAVE_COPY_FILE_RANGE
+ if (!make_holes) {
+ copy_range_ok = copy_range(source_desc, src_name, &src_open_sb,
+ dest_desc, dst_name, x, sparse_src);
+ }
+#endif
+ if (!copy_range_ok) {
+ return_val = copy_data(source_desc, src_name, &src_open_sb,
+ dest_desc, dst_name, &sb, x, make_holes);
+ if (!return_val)
+ goto close_src_and_dst_desc;
+ }
}
if (x->preserve_timestamps)
--
2.16.4