Skip to content

Commit b093cdb

Browse files
authored
Merge pull request #222 from ahoppen/rename-dir
Fix issue that caused database rename to and from `saved` to fail
2 parents 6120b53 + c73df08 commit b093cdb

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

lib/Database/Database.cpp

+34-6
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
#include "llvm/ADT/StringRef.h"
2020
#include "llvm/ADT/StringMap.h"
2121
#include "llvm/ADT/STLExtras.h"
22+
#include "llvm/Support/Errc.h"
2223
#include "llvm/Support/FileSystem.h"
2324
#include "llvm/Support/Mutex.h"
2425
#include "llvm/Support/Path.h"
2526
#include "llvm/Support/raw_ostream.h"
27+
#include "llvm/Support/WindowsError.h"
2628
#if defined(_WIN32)
2729
#define NOMINMAX
2830
#include "Windows.h"
31+
#include "winbase.h"
2932
#endif
3033

3134
#if defined(_WIN32)
@@ -46,6 +49,31 @@ const unsigned Database::DATABASE_FORMAT_VERSION = 13;
4649

4750
static const char *DeadProcessDBSuffix = "-dead";
4851

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+
4977
static int providersForUSR_compare(const MDB_val *a, const MDB_val *b) {
5078
assert(a->mv_size == sizeof(ProviderForUSRData));
5179
assert(b->mv_size == sizeof(ProviderForUSRData));
@@ -93,8 +121,8 @@ Database::Implementation::~Implementation() {
93121
assert(!SavedPath.empty() && !UniquePath.empty());
94122
// In case some other process already created the 'saved' path, override it so
95123
// 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)) {
98126
// If the database directory already got removed or some other process beat
99127
// us during the tiny window between the above 2 renames, then give-up,
100128
// and let the database to be discarded.
@@ -117,7 +145,7 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
117145
llvm::sys::path::append(savedPathBuf, "saved");
118146
SmallString<128> prefixPathBuf = versionPath;
119147
#if defined(WIN32)
120-
llvm::raw_svector_ostream(prefixPathBuf) << "/p" << GetCurrentProcessId();
148+
llvm::raw_svector_ostream(prefixPathBuf) << "\\p" << GetCurrentProcessId();
121149
#else
122150
llvm::raw_svector_ostream(prefixPathBuf) << "/p" << getpid();
123151
#endif
@@ -155,7 +183,7 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
155183
return nullptr;
156184

157185
// 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)) {
159187
// No existing database, just use the new directory.
160188
existingDB = false;
161189
}
@@ -227,8 +255,8 @@ Database::Implementation::create(StringRef path, bool readonly, Optional<size_t>
227255
// aside to a 'corrupted' path we can find it for analysis.
228256
SmallString<128> corruptedPathBuf = versionPath;
229257
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);
232260
LOG_WARN_FUNC("failed opening database: " << err.description() << "\n"
233261
"corrupted database saved at '" << corruptedPathBuf << "'\n"
234262
"creating new database...");

0 commit comments

Comments
 (0)