summaryrefslogtreecommitdiffstats
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
parentc61292726cd3018ec502f8d59e62352c8dce62d3 (diff)
downloadCMake-3600c6cd8c09e501faa06be5f98465e994d51569.zip
CMake-3600c6cd8c09e501faa06be5f98465e994d51569.tar.gz
CMake-3600c6cd8c09e501faa06be5f98465e994d51569.tar.bz2
cmSystemTools: Add RenameFile option to not replace destination
-rw-r--r--Source/cmFileCommand.cxx4
-rw-r--r--Source/cmSystemTools.cxx38
-rw-r--r--Source/cmSystemTools.h9
3 files changed, 41 insertions, 10 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 6243bb2..ab954f2 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1348,12 +1348,14 @@ bool HandleRename(std::vector<std::string> const& args,
}
std::string err;
- switch (cmSystemTools::RenameFile(oldname, newname, &err)) {
+ switch (cmSystemTools::RenameFile(oldname, newname,
+ cmSystemTools::Replace::Yes, &err)) {
case cmSystemTools::RenameResult::Success:
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, "0");
}
return true;
+ case cmSystemTools::RenameResult::NoReplace:
case cmSystemTools::RenameResult::Failure:
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, err);
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;
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index bb90135..3cc032c 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -128,9 +128,15 @@ public:
static bool SimpleGlob(const std::string& glob,
std::vector<std::string>& files, int type = 0);
+ enum class Replace
+ {
+ Yes,
+ No,
+ };
enum class RenameResult
{
Success,
+ NoReplace,
Failure,
};
@@ -139,7 +145,8 @@ public:
static bool RenameFile(const std::string& oldname,
const std::string& newname);
static RenameResult RenameFile(std::string const& oldname,
- std::string const& newname, std::string* err);
+ std::string const& newname, Replace replace,
+ std::string* err = nullptr);
//! Rename a file if contents are different, delete the source otherwise
static void MoveFileIfDifferent(const std::string& source,