Merge branch 'upstream-KWSys' into update-kwsys

* upstream-KWSys:
  KWSys 2018-12-12 (abb8c680)
This commit is contained in:
Brad King 2018-12-12 08:14:53 -05:00
commit b29d96701b

View File

@ -82,6 +82,10 @@
# include <signal.h> /* sigprocmask */
#endif
#ifdef __linux
# include <linux/fs.h>
#endif
// Windows API.
#if defined(_WIN32)
# include <windows.h>
@ -2158,43 +2162,11 @@ bool SystemTools::FilesDiffer(const std::string& source,
}
/**
* Copy a file named by "source" to the file named by "destination".
* Blockwise copy source to destination file
*/
bool SystemTools::CopyFileAlways(const std::string& source,
static bool CopyFileContentBlockwise(const std::string& source,
const std::string& destination)
{
// If files are the same do not copy
if (SystemTools::SameFile(source, destination)) {
return true;
}
mode_t perm = 0;
bool perms = SystemTools::GetPermissions(source, perm);
std::string real_destination = destination;
if (SystemTools::FileIsDirectory(source)) {
SystemTools::MakeDirectory(destination);
} else {
const int bufferSize = 4096;
char buffer[bufferSize];
// If destination is a directory, try to create a file with the same
// name as the source in that directory.
std::string destination_dir;
if (SystemTools::FileIsDirectory(destination)) {
destination_dir = real_destination;
SystemTools::ConvertToUnixSlashes(real_destination);
real_destination += '/';
std::string source_name = source;
real_destination += SystemTools::GetFilenameName(source_name);
} else {
destination_dir = SystemTools::GetFilenamePath(destination);
}
// Create destination directory
SystemTools::MakeDirectory(destination_dir);
// Open files
#if defined(_WIN32)
kwsys::ifstream fin(
@ -2211,15 +2183,14 @@ bool SystemTools::CopyFileAlways(const std::string& source,
// can be written to.
// If the remove fails continue so that files in read only directories
// that do not allow file removal can be modified.
SystemTools::RemoveFile(real_destination);
SystemTools::RemoveFile(destination);
#if defined(_WIN32)
kwsys::ofstream fout(
Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(real_destination))
.c_str(),
Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
#else
kwsys::ofstream fout(real_destination.c_str(),
kwsys::ofstream fout(destination.c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
#endif
if (!fout) {
@ -2232,6 +2203,9 @@ bool SystemTools::CopyFileAlways(const std::string& source,
// before using the data, but the fin.gcount() will be zero if an
// error occurred. Therefore, the loop should be safe everywhere.
while (fin) {
const int bufferSize = 4096;
char buffer[bufferSize];
fin.read(buffer, bufferSize);
if (fin.gcount()) {
fout.write(buffer, fin.gcount());
@ -2251,6 +2225,97 @@ bool SystemTools::CopyFileAlways(const std::string& source,
if (!fout) {
return false;
}
return true;
}
/**
* Clone the source file to the destination file
*
* If available, the Linux FICLONE ioctl is used to create a check
* copy-on-write clone of the source file.
*
* The method returns false for the following cases:
* - The code has not been compiled on Linux or the ioctl was unknown
* - The source and destination is on different file systems
* - The underlying filesystem does not support file cloning
* - An unspecified error occurred
*/
static bool CloneFileContent(const std::string& source,
const std::string& destination)
{
#if defined(__linux) && defined(FICLONE)
int in = open(source.c_str(), O_RDONLY);
if (in < 0) {
return false;
}
SystemTools::RemoveFile(destination);
int out =
open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (out < 0) {
close(in);
return false;
}
int result = ioctl(out, FICLONE, in);
close(in);
close(out);
if (result < 0) {
return false;
}
return true;
#else
(void)source;
(void)destination;
return false;
#endif
}
/**
* Copy a file named by "source" to the file named by "destination".
*/
bool SystemTools::CopyFileAlways(const std::string& source,
const std::string& destination)
{
// If files are the same do not copy
if (SystemTools::SameFile(source, destination)) {
return true;
}
mode_t perm = 0;
bool perms = SystemTools::GetPermissions(source, perm);
std::string real_destination = destination;
if (SystemTools::FileIsDirectory(source)) {
SystemTools::MakeDirectory(destination);
} else {
// If destination is a directory, try to create a file with the same
// name as the source in that directory.
std::string destination_dir;
if (SystemTools::FileIsDirectory(destination)) {
destination_dir = real_destination;
SystemTools::ConvertToUnixSlashes(real_destination);
real_destination += '/';
std::string source_name = source;
real_destination += SystemTools::GetFilenameName(source_name);
} else {
destination_dir = SystemTools::GetFilenamePath(destination);
}
// Create destination directory
SystemTools::MakeDirectory(destination_dir);
if (!CloneFileContent(source, real_destination)) {
// if cloning did not succeed, fall back to blockwise copy
if (!CopyFileContentBlockwise(source, real_destination)) {
return false;
}
}
}
if (perms) {
if (!SystemTools::SetPermissions(real_destination, perm)) {