diff options
| -rw-r--r-- | llvm/lib/Support/Path.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/Support/Unix/Path.inc | 48 | 
2 files changed, 50 insertions, 0 deletions
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index 902df74a68f..9466591c25e 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -935,6 +935,7 @@ std::error_code create_directories(const Twine &Path, bool IgnoreExisting,    return create_directory(P, IgnoreExisting, Perms);  } +#ifndef __APPLE__  static std::error_code copy_file_internal(int ReadFD, int WriteFD) {    const size_t BufSize = 4096;    char *Buf = new char[BufSize]; @@ -988,6 +989,7 @@ std::error_code copy_file(const Twine &From, int ToFD) {    return EC;  } +#endif  ErrorOr<MD5::MD5Result> md5_contents(int FD) {    MD5 Hash; diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index 05ccc6cc5e4..fbe3ed11c59 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -37,6 +37,7 @@  #ifdef __APPLE__  #include <mach-o/dyld.h>  #include <sys/attr.h> +#include <copyfile.h>  #elif defined(__DragonFly__)  #include <sys/mount.h>  #endif @@ -1113,5 +1114,52 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {  } // end namespace path +namespace fs { + +#ifdef __APPLE__ +/// This implementation tries to perform an APFS CoW clone of the file, +/// which can be much faster and uses less space. +std::error_code copy_file(const Twine &From, const Twine &To) { +  uint32_t Flag = COPYFILE_DATA; +  if (__builtin_available(macos 10.12, *)) { +    bool IsSymlink; +    if (std::error_code Error = is_symlink_file(From, IsSymlink)) +      return Error; +    // COPYFILE_CLONE clones the symlink instead of following it +    // and returns EEXISTS if the target file already exists. +    if (!IsSymlink && !exists(To)) +      Flag = COPYFILE_CLONE; +  } + +  int Status = +      copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag); + +  if (Status == 0) +    return std::error_code(); +  return std::error_code(errno, std::generic_category()); +} + +/// This implementation tries to perform an APFS CoW clone of the file, +/// which can be much faster and uses less space. +std::error_code copy_file(const Twine &From, int ToFD) { +  int ReadFD; +  if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) +    return EC; + +  uint32_t Flag = COPYFILE_DATA; +  if (__builtin_available(macos 10.12, *)) +    Flag = COPYFILE_CLONE; + +  int Status = fcopyfile(ReadFD, ToFD, /*State*/ NULL, Flag); + +  close(ReadFD); +  if (Status == 0) +    return std::error_code(); +  return std::error_code(errno, std::generic_category()); +} +#endif + +} // end namespace fs +  } // end namespace sys  } // end namespace llvm  | 

