19
19
#include " llvm/ADT/StringRef.h"
20
20
#include " llvm/ADT/StringMap.h"
21
21
#include " llvm/ADT/STLExtras.h"
22
+ #include " llvm/Support/Errc.h"
22
23
#include " llvm/Support/FileSystem.h"
23
24
#include " llvm/Support/Mutex.h"
24
25
#include " llvm/Support/Path.h"
25
26
#include " llvm/Support/raw_ostream.h"
27
+ #include " llvm/Support/WindowsError.h"
26
28
#if defined(_WIN32)
27
29
#define NOMINMAX
28
30
#include " Windows.h"
31
+ #include " winbase.h"
29
32
#endif
30
33
31
34
#if defined(_WIN32)
@@ -46,6 +49,31 @@ const unsigned Database::DATABASE_FORMAT_VERSION = 13;
46
49
47
50
static const char *DeadProcessDBSuffix = " -dead" ;
48
51
52
+ static std::error_code renameDirectory (const Twine &from, const Twine &to) {
53
+ // llvm::sys::fs::rename is not able to rename directories on Windows. Use `MoveFile` directly.
54
+ #if defined(_WIN32)
55
+ if (!llvm::sys::fs::exists (from)) {
56
+ return make_error_code (llvm::errc::no_such_file_or_directory);
57
+ }
58
+ // MoveFileW does not override an existing directory. Remove the destination if it exists.
59
+ llvm::sys::fs::remove_directories (to, /* IgnoreErrors=*/ true );
60
+ SmallVector<wchar_t , 128 > wideFrom;
61
+ if (std::error_code ec = llvm::sys::path::widenPath (from, wideFrom)) {
62
+ return ec;
63
+ }
64
+ SmallVector<wchar_t , 128 > wideTo;
65
+ if (std::error_code ec = llvm::sys::path::widenPath (to, wideTo)) {
66
+ return ec;
67
+ }
68
+ if (!::MoveFileW (wideFrom.begin (), wideTo.begin ())) {
69
+ return llvm::mapWindowsError (GetLastError ());
70
+ }
71
+ return std::error_code ();
72
+ #else
73
+ return llvm::sys::fs::rename (from, to);
74
+ #endif
75
+ }
76
+
49
77
static int providersForUSR_compare (const MDB_val *a, const MDB_val *b) {
50
78
assert (a->mv_size == sizeof (ProviderForUSRData));
51
79
assert (b->mv_size == sizeof (ProviderForUSRData));
@@ -93,8 +121,8 @@ Database::Implementation::~Implementation() {
93
121
assert (!SavedPath.empty () && !UniquePath.empty ());
94
122
// In case some other process already created the 'saved' path, override it so
95
123
// that the 'last one wins'.
96
- llvm::sys::fs::rename (SavedPath, llvm::Twine (UniquePath)+" -saved" +DeadProcessDBSuffix);
97
- if (std::error_code ec = llvm::sys::fs::rename (UniquePath, SavedPath)) {
124
+ renameDirectory (SavedPath, llvm::Twine (UniquePath)+" -saved" +DeadProcessDBSuffix);
125
+ if (std::error_code ec = renameDirectory (UniquePath, SavedPath)) {
98
126
// If the database directory already got removed or some other process beat
99
127
// us during the tiny window between the above 2 renames, then give-up,
100
128
// and let the database to be discarded.
@@ -117,7 +145,7 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
117
145
llvm::sys::path::append (savedPathBuf, " saved" );
118
146
SmallString<128 > prefixPathBuf = versionPath;
119
147
#if defined(WIN32)
120
- llvm::raw_svector_ostream (prefixPathBuf) << " / p" << GetCurrentProcessId ();
148
+ llvm::raw_svector_ostream (prefixPathBuf) << " \\ p" << GetCurrentProcessId ();
121
149
#else
122
150
llvm::raw_svector_ostream (prefixPathBuf) << " /p" << getpid ();
123
151
#endif
@@ -155,7 +183,7 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
155
183
return nullptr ;
156
184
157
185
// This succeeds for moving to an empty directory, like the newly constructed `uniqueDirPath`.
158
- if (llvm::sys::fs::rename (savedPathBuf, uniqueDirPath)) {
186
+ if (renameDirectory (savedPathBuf, uniqueDirPath)) {
159
187
// No existing database, just use the new directory.
160
188
existingDB = false ;
161
189
}
@@ -227,8 +255,8 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
227
255
// aside to a 'corrupted' path we can find it for analysis.
228
256
SmallString<128 > corruptedPathBuf = versionPath;
229
257
llvm::sys::path::append (corruptedPathBuf, " corrupted" );
230
- llvm::sys::fs::rename (corruptedPathBuf, llvm::Twine (corruptedPathBuf)+DeadProcessDBSuffix);
231
- llvm::sys::fs::rename (savedPathBuf, corruptedPathBuf);
258
+ renameDirectory (corruptedPathBuf, llvm::Twine (corruptedPathBuf)+DeadProcessDBSuffix);
259
+ renameDirectory (savedPathBuf, corruptedPathBuf);
232
260
LOG_WARN_FUNC (" failed opening database: " << err.description () << " \n "
233
261
" corrupted database saved at '" << corruptedPathBuf << " '\n "
234
262
" creating new database..." );
0 commit comments