mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 22:37:30 +08:00
cmSystemTools: Add more error handling to RenameFile on Windows
Issue: #19580
This commit is contained in:
@@ -885,6 +885,9 @@ void cmSystemTools::InitializeLibUV()
|
|||||||
namespace {
|
namespace {
|
||||||
bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname)
|
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_REPLACE_EXISTING to replace an existing destination file.
|
||||||
// Use MOVEFILE_WRITE_THROUGH to flush the change to disk before returning.
|
// Use MOVEFILE_WRITE_THROUGH to flush the change to disk before returning.
|
||||||
return MoveFileExW(oldname.c_str(), newname.c_str(),
|
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
|
Try multiple times since we may be racing against another process
|
||||||
creating/opening the destination file just before our MoveFileEx. */
|
creating/opening the destination file just before our MoveFileEx. */
|
||||||
WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
|
WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
|
||||||
|
DWORD move_last_error = 0;
|
||||||
while (!cmMoveFile(oldname_wstr, newname_wstr) && --retry.Count) {
|
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.
|
// Try again only if failure was due to access/sharing permissions.
|
||||||
if (last_error != ERROR_ACCESS_DENIED &&
|
// Most often ERROR_ACCESS_DENIED (a.k.a. I/O error) for a directory, and
|
||||||
last_error != ERROR_SHARING_VIOLATION) {
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
|
DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
|
||||||
if ((attrs != INVALID_FILE_ATTRIBUTES) &&
|
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.
|
// Remove the read-only attribute from the destination file.
|
||||||
SetFileAttributesW(newname_wstr.c_str(),
|
SetFileAttributesW(newname_wstr.c_str(),
|
||||||
attrs & ~FILE_ATTRIBUTE_READONLY);
|
attrs & ~FILE_ATTRIBUTE_READONLY);
|
||||||
@@ -928,6 +946,12 @@ bool cmSystemTools::RenameFile(const std::string& oldname,
|
|||||||
cmSystemTools::Delay(retry.Delay);
|
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;
|
return retry.Count > 0;
|
||||||
#else
|
#else
|
||||||
/* On UNIX we have an OS-provided call to do this atomically. */
|
/* On UNIX we have an OS-provided call to do this atomically. */
|
||||||
|
Reference in New Issue
Block a user