summaryrefslogtreecommitdiffstats
path: root/Source/cmSystemTools.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-03-04 13:23:42 (GMT)
committerBrad King <brad.king@kitware.com>2021-03-04 13:47:31 (GMT)
commit3600c6cd8c09e501faa06be5f98465e994d51569 (patch)
tree1b67331f5bc6dfa2893e94b97b1fa0ae08469dd0 /Source/cmSystemTools.cxx
parentc61292726cd3018ec502f8d59e62352c8dce62d3 (diff)
downloadCMake-3600c6cd8c09e501faa06be5f98465e994d51569.zip
CMake-3600c6cd8c09e501faa06be5f98465e994d51569.tar.gz
CMake-3600c6cd8c09e501faa06be5f98465e994d51569.tar.bz2
cmSystemTools: Add RenameFile option to not replace destination
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r--Source/cmSystemTools.cxx38
1 files changed, 30 insertions, 8 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index eb02712..db5b1ac 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -973,14 +973,19 @@ void cmSystemTools::InitializeLibUV()
#ifdef _WIN32
namespace {
-bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname)
+bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
+ cmSystemTools::Replace replace)
{
// Not only ignore any previous error, but clear any memory of it.
SetLastError(0);
- // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
- return MoveFileExW(oldname.c_str(), newname.c_str(),
- MOVEFILE_REPLACE_EXISTING);
+ DWORD flags = 0;
+ if (replace == cmSystemTools::Replace::Yes) {
+ // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
+ flags = flags | MOVEFILE_REPLACE_EXISTING;
+ }
+
+ return MoveFileExW(oldname.c_str(), newname.c_str(), flags);
}
}
#endif
@@ -988,12 +993,13 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname)
bool cmSystemTools::RenameFile(const std::string& oldname,
const std::string& newname)
{
- return cmSystemTools::RenameFile(oldname, newname, nullptr) ==
+ return cmSystemTools::RenameFile(oldname, newname, Replace::Yes) ==
RenameResult::Success;
}
cmSystemTools::RenameResult cmSystemTools::RenameFile(
- std::string const& oldname, std::string const& newname, std::string* err)
+ std::string const& oldname, std::string const& newname, Replace replace,
+ std::string* err)
{
#ifdef _WIN32
# ifndef INVALID_FILE_ATTRIBUTES
@@ -1016,7 +1022,7 @@ cmSystemTools::RenameResult cmSystemTools::RenameFile(
oldname_wstr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
DWORD move_last_error = 0;
- while (!cmMoveFile(oldname_wstr, newname_wstr) && --retry.Count) {
+ while (!cmMoveFile(oldname_wstr, newname_wstr, replace) && --retry.Count) {
move_last_error = GetLastError();
// There was no error ==> the operation is not yet complete.
@@ -1032,6 +1038,9 @@ cmSystemTools::RenameResult cmSystemTools::RenameFile(
// 3) Windows Explorer has an associated directory already opened.
if (move_last_error != ERROR_ACCESS_DENIED &&
move_last_error != ERROR_SHARING_VIOLATION) {
+ if (replace == Replace::No && move_last_error == ERROR_ALREADY_EXISTS) {
+ return RenameResult::NoReplace;
+ }
ReportError(err);
return RenameResult::Failure;
}
@@ -1060,10 +1069,23 @@ cmSystemTools::RenameResult cmSystemTools::RenameFile(
if (retry.Count > 0) {
return RenameResult::Success;
}
+ if (replace == Replace::No && GetLastError() == ERROR_ALREADY_EXISTS) {
+ return RenameResult::NoReplace;
+ }
ReportError(err);
return RenameResult::Failure;
#else
- /* On UNIX we have an OS-provided call to do this atomically. */
+ // On UNIX we have OS-provided calls to create 'newname' atomically.
+ if (replace == Replace::No) {
+ if (link(oldname.c_str(), newname.c_str()) == 0) {
+ return RenameResult::Success;
+ }
+ if (errno == EEXIST) {
+ return RenameResult::NoReplace;
+ }
+ ReportError(err);
+ return RenameResult::Failure;
+ }
if (rename(oldname.c_str(), newname.c_str()) == 0) {
return RenameResult::Success;
}