summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support
diff options
context:
space:
mode:
authorGreg Bedwell <greg_bedwell@sn.scee.net>2015-10-12 15:11:47 +0000
committerGreg Bedwell <greg_bedwell@sn.scee.net>2015-10-12 15:11:47 +0000
commit7f68a7166925b4d5e1a4c5a8eea5f6689352b89d (patch)
tree48d8bcebe721af95c5f7ec7ad713c774e53e014f /llvm/lib/Support
parent3b732ac7eeeab398211beae85e134523d514718e (diff)
downloadbcm5719-llvm-7f68a7166925b4d5e1a4c5a8eea5f6689352b89d.tar.gz
bcm5719-llvm-7f68a7166925b4d5e1a4c5a8eea5f6689352b89d.zip
Fix rename() sometimes failing if another process uses openFileForRead()
On Windows, fs::rename() could fail is another process was reading the file at the same time using fs::openFileForRead(). In most cases the user wouldn't notice as fs::rename() will continue to retry for 2000ms. Typically this is enough for the read to complete and a retry to succeed, but if the disk is being it too hard then the response time might be longer than the retry time and the rename would fail with a permission error. Add FILE_SHARE_DELETE to the sharing flags for CreateFileW() in fs::openFileForRead() and try ReplaceFileW() prior to MoveFileExW() in fs::rename(). Based on an initial patch by Edd Dawson! Differential Revision: http://reviews.llvm.org/D13647 llvm-svn: 250046
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/Windows/Path.inc38
1 files changed, 28 insertions, 10 deletions
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index 1ee45c6f362..2c111321c60 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -253,17 +253,34 @@ std::error_code rename(const Twine &from, const Twine &to) {
return ec;
std::error_code ec = std::error_code();
+
+ // Retry while we see ERROR_ACCESS_DENIED.
+ // System scanners (eg. indexer) might open the source file when it is written
+ // and closed.
+
for (int i = 0; i < 2000; i++) {
+ // Try ReplaceFile first, as it is able to associate a new data stream with
+ // the destination even if the destination file is currently open.
+ if (::ReplaceFileW(wide_to.begin(), wide_from.begin(), NULL, 0, NULL, NULL))
+ return std::error_code();
+
+ // We get ERROR_FILE_NOT_FOUND if the destination file is missing.
+ // MoveFileEx can handle this case.
+ DWORD ReplaceError = ::GetLastError();
+ ec = mapWindowsError(ReplaceError);
+ if (ReplaceError != ERROR_ACCESS_DENIED &&
+ ReplaceError != ERROR_FILE_NOT_FOUND &&
+ ReplaceError != ERROR_SHARING_VIOLATION)
+ break;
+
if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
return std::error_code();
- DWORD LastError = ::GetLastError();
- ec = mapWindowsError(LastError);
- if (LastError != ERROR_ACCESS_DENIED)
- break;
- // Retry MoveFile() at ACCESS_DENIED.
- // System scanners (eg. indexer) might open the source file when
- // It is written and closed.
+
+ DWORD MoveError = ::GetLastError();
+ ec = mapWindowsError(MoveError);
+ if (MoveError != ERROR_ACCESS_DENIED) break;
+
::Sleep(1);
}
@@ -649,9 +666,10 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
if (std::error_code EC = widenPath(Name, PathUTF16))
return EC;
- HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE H =
+ ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError();
std::error_code EC = mapWindowsError(LastError);
OpenPOWER on IntegriCloud