summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRon W Moore <webbtrail@gmail.com>2020-08-25 13:44:56 (GMT)
committerBrad King <brad.king@kitware.com>2020-08-31 17:03:36 (GMT)
commit2f8ef095daa6613ca1d37fef496a48a48f74604e (patch)
treedb84fc355e820670411677533198fa8475e52289
parentd78c22aa64f63b06b39c644c5d65aee367ec74b4 (diff)
downloadCMake-2f8ef095daa6613ca1d37fef496a48a48f74604e.zip
CMake-2f8ef095daa6613ca1d37fef496a48a48f74604e.tar.gz
CMake-2f8ef095daa6613ca1d37fef496a48a48f74604e.tar.bz2
cmSystemTools: Add more error handling to RenameFile on Windows
Issue: #19580
-rw-r--r--Source/cmSystemTools.cxx32
1 files changed, 28 insertions, 4 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 3cea743..95944a2 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -885,6 +885,9 @@ void cmSystemTools::InitializeLibUV()
namespace {
bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname)
{
+ // Not only ignore any previous error, but clear any memory of it.
+ SetLastError(0);
+
// Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
// Use MOVEFILE_WRITE_THROUGH to flush the change to disk before returning.
return MoveFileExW(oldname.c_str(), newname.c_str(),
@@ -910,16 +913,31 @@ bool cmSystemTools::RenameFile(const std::string& oldname,
Try multiple times since we may be racing against another process
creating/opening the destination file just before our MoveFileEx. */
WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
+ DWORD move_last_error = 0;
while (!cmMoveFile(oldname_wstr, newname_wstr) && --retry.Count) {
- DWORD last_error = GetLastError();
+ move_last_error = GetLastError();
+
+ // There was no error ==> the operation is not yet complete.
+ if (move_last_error == NO_ERROR) {
+ break;
+ }
+
// Try again only if failure was due to access/sharing permissions.
- if (last_error != ERROR_ACCESS_DENIED &&
- last_error != ERROR_SHARING_VIOLATION) {
+ // Most often ERROR_ACCESS_DENIED (a.k.a. I/O error) for a directory, and
+ // ERROR_SHARING_VIOLATION for a file, are caused by one of the following:
+ // 1) Anti-Virus Software
+ // 2) Windows Search Indexer
+ // 3) Windows Explorer has an associated directory already opened.
+ if (move_last_error != ERROR_ACCESS_DENIED &&
+ move_last_error != ERROR_SHARING_VIOLATION) {
return false;
}
+
DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
if ((attrs != INVALID_FILE_ATTRIBUTES) &&
- (attrs & FILE_ATTRIBUTE_READONLY)) {
+ (attrs & FILE_ATTRIBUTE_READONLY) &&
+ // FILE_ATTRIBUTE_READONLY is not honored on directories.
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
// Remove the read-only attribute from the destination file.
SetFileAttributesW(newname_wstr.c_str(),
attrs & ~FILE_ATTRIBUTE_READONLY);
@@ -928,6 +946,12 @@ bool cmSystemTools::RenameFile(const std::string& oldname,
cmSystemTools::Delay(retry.Delay);
}
}
+
+ // If we were successful, then there was no error.
+ if (retry.Count > 0) {
+ move_last_error = 0;
+ }
+ SetLastError(move_last_error);
return retry.Count > 0;
#else
/* On UNIX we have an OS-provided call to do this atomically. */