coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] [RFC] cp: MacOS clonefile support


From: Mingye Wang
Subject: [PATCH] [RFC] cp: MacOS clonefile support
Date: Sun, 23 Aug 2020 02:10:12 +0800

This patch enables using the macOS 10.12+ clonefile(2) system call for
reflinking on supported filesystems. The system BSD cp(1) only
supports -c (--reflink=always), which is quite a pain.

Tested on a hackintosh machine with macOS 10.15. And yes, this is a
resubmission.
---
 configure.ac | 14 ++++++++++++++
 src/copy.c   | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 69d4e7d..07ad5c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -362,6 +362,20 @@ case $utils_cv_func_setpriority,$ac_cv_func_nice in
   gl_ADD_PROG([optional_bin_progs], [nice])
 esac
 
+AC_CACHE_CHECK([for clonefile],
+  [utils_cv_func_clonefile],
+  [AC_LINK_IFELSE(
+    [AC_LANG_PROGRAM(
+       [[#include <sys/attr.h>
+         #include <sys/clonefile.h>
+       ]],
+       [[clonefile("", "", CLONE_NOFOLLOW);]])],
+    [utils_cv_func_clonefile=yes],
+    [utils_cv_func_clonefile=no])])
+if test $utils_cv_func_clonefile = yes; then
+  AC_DEFINE([HAVE_CLONEFILE], [1], [Define if clonefile exists.])
+fi
+
 if test "$cross_compiling" = yes || test -c /dev/stdin <.; then
   AC_DEFINE([DEV_FD_MIGHT_BE_CHR], [1],
     [Define to 1 if /dev/std{in,out,err} and /dev/fd/N, if they exist, might be
diff --git a/src/copy.c b/src/copy.c
index 4050f69..fad8189 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -73,6 +73,11 @@
 # include "verror.h"
 #endif
 
+#if HAVE_CLONEFILE
+# include <sys/attr.h>
+# include <sys/clonefile.h>
+#endif
+
 #if HAVE_LINUX_FALLOC_H
 # include <linux/falloc.h>
 #endif
@@ -1311,12 +1316,48 @@ copy_reg (char const *src_name, char const *dst_name,
       goto close_src_desc;
     }
 
+#if HAVE_CLONEFILE
+  /* The macOS clonefile() syscall is like link in that it takes
+     pathnames. Do it first. */
+  if (data_copy_required && x->reflink_mode)
+    {
+      bool clone_ok = false;
+      if (! *new_dst)
+        {
+          if (unlink(dst_name) != 0)
+            {
+              error (0, errno, _("cannot remove %s"), quoteaf (dst_name));
+              goto noclone;
+            }
+          if (x->verbose)
+            printf (_("removed %s\n"), quoteaf (dst_name));
+        }
+      uint32_t cloneflags = 0;
+      if (x->dereference == DEREF_NEVER) cloneflags |= CLONE_NOFOLLOW;
+      /* CLONE_NOOWNERCOPY (0x0002) is recently added with no specific
+       * date. Let's not feed ourselves to Apple-versioning. */
+      clone_ok = clonefile (src_name, dst_name, cloneflags) == 0;
+      noclone:;
+      if (clone_ok || x->reflink_mode == REFLINK_ALWAYS)
+        {
+          if (!clone_ok)
+            {
+              error (0, errno, _("failed to clone %s from %s"),
+                     quoteaf_n (0, dst_name), quoteaf_n (1, src_name));
+              return false;
+            }
+          data_copy_required = false;
+          *new_dst = false;
+        }
+    }
+#endif
+
   /* The semantics of the following open calls are mandated
      by the specs for both cp and mv.  */
   if (! *new_dst)
     {
       int open_flags =
-        O_WRONLY | O_BINARY | (x->data_copy_required ? O_TRUNC : 0);
+        O_WRONLY | O_BINARY | (data_copy_required ? O_TRUNC : 0);
       dest_desc = open (dst_name, open_flags);
       dest_errno = errno;
 
@@ -1453,6 +1494,7 @@ copy_reg (char const *src_name, char const *dst_name,
       goto close_src_and_dst_desc;
     }
 
+#if ! HAVE_CLONEFILE
   /* --attributes-only overrides --reflink.  */
   if (data_copy_required && x->reflink_mode)
     {
@@ -1469,6 +1511,7 @@ copy_reg (char const *src_name, char const *dst_name,
           data_copy_required = false;
         }
     }
+#endif
 
   if (data_copy_required)
     {
-- 
2.20.1.windows.1



reply via email to

[Prev in Thread] Current Thread [Next in Thread]