Skip to content

Commit e60cb99

Browse files
committed
Add a lock to the wallet directory
1 parent bbc91b7 commit e60cb99

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

src/wallet/db.cpp

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <sys/stat.h>
1919
#endif
2020

21+
#include <boost/interprocess/sync/file_lock.hpp>
2122
#include <boost/thread.hpp>
2223

2324
namespace {
@@ -52,6 +53,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
5253
}
5354
}
5455
}
56+
57+
bool LockEnvDirectory(const fs::path& env_path)
58+
{
59+
// Make sure only a single Bitcoin process is using the wallet directory.
60+
fs::path lock_file_path = env_path / ".lock";
61+
FILE* file = fsbridge::fopen(lock_file_path, "a"); // empty lock file; created if it doesn't exist.
62+
if (file) fclose(file);
63+
64+
try {
65+
static boost::interprocess::file_lock lock(lock_file_path.string().c_str());
66+
if (!lock.try_lock()) {
67+
return false;
68+
}
69+
} catch (const boost::interprocess::interprocess_exception& e) {
70+
return error("Error obtaining lock on wallet directory %s: %s.", env_path.string(), e.what());
71+
}
72+
return true;
73+
}
5574
} // namespace
5675

5776
//
@@ -95,13 +114,17 @@ void CDBEnv::Close()
95114
EnvShutdown();
96115
}
97116

98-
bool CDBEnv::Open(const fs::path& pathIn)
117+
bool CDBEnv::Open(const fs::path& pathIn, bool retry)
99118
{
100119
if (fDbEnvInit)
101120
return true;
102121

103122
boost::this_thread::interruption_point();
104123

124+
if (!LockEnvDirectory(pathIn)) {
125+
return false;
126+
}
127+
105128
strPath = pathIn.string();
106129
fs::path pathLogDir = pathIn / "database";
107130
TryCreateDirectories(pathLogDir);
@@ -134,7 +157,24 @@ bool CDBEnv::Open(const fs::path& pathIn)
134157
S_IRUSR | S_IWUSR);
135158
if (ret != 0) {
136159
dbenv->close(0);
137-
return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
160+
LogPrintf("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
161+
if (retry) {
162+
// try moving the database env out of the way
163+
fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime());
164+
try {
165+
fs::rename(pathLogDir, pathDatabaseBak);
166+
LogPrintf("Moved old %s to %s. Retrying.\n", pathLogDir.string(), pathDatabaseBak.string());
167+
} catch (const fs::filesystem_error&) {
168+
// failure is ok (well, not really, but it's not worse than what we started with)
169+
}
170+
// try opening it again one more time
171+
if (!Open(pathIn, false)) {
172+
// if it still fails, it probably means we can't even create the database env
173+
return false;
174+
}
175+
} else {
176+
return false;
177+
}
138178
}
139179

140180
fDbEnvInit = true;
@@ -269,25 +309,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle
269309
return false;
270310
}
271311

272-
if (!bitdb.Open(walletDir))
273-
{
274-
// try moving the database env out of the way
275-
fs::path pathDatabase = walletDir / "database";
276-
fs::path pathDatabaseBak = walletDir / strprintf("database.%d.bak", GetTime());
277-
try {
278-
fs::rename(pathDatabase, pathDatabaseBak);
279-
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
280-
} catch (const fs::filesystem_error&) {
281-
// failure is ok (well, not really, but it's not worse than what we started with)
282-
}
283-
284-
// try again
285-
if (!bitdb.Open(walletDir)) {
286-
// if it still fails, it probably means we can't even create the database env
287-
errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
288-
return false;
289-
}
312+
if (!bitdb.Open(walletDir, true)) {
313+
errorStr = strprintf(_("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it."), walletDir);
314+
return false;
290315
}
316+
291317
return true;
292318
}
293319

src/wallet/db.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class CDBEnv
6868
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
6969
bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
7070

71-
bool Open(const fs::path& path);
71+
bool Open(const fs::path& path, bool retry = 0);
7272
void Close();
7373
void Flush(bool fShutdown);
7474
void CheckpointLSN(const std::string& strFile);

0 commit comments

Comments
 (0)