Commit 3600c6cd authored by Brad King's avatar Brad King
Browse files

cmSystemTools: Add RenameFile option to not replace destination

parent c6129272
......@@ -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);
......
......@@ -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;
}
......
......@@ -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,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment