From a238a8dfe621206624abafea1ce66297d79427df Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Fri, 15 Dec 2017 11:06:22 +1300 Subject: [PATCH] Add a lock to the wallet directory --- src/wallet/db.cpp | 66 +++++++++++++++++++++++++++++++++-------------- src/wallet/db.h | 2 +- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index f0bc8e512396a..04d4c54364736 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -20,6 +20,7 @@ #include #endif +#include #include @@ -55,6 +56,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db) } } } + +bool LockEnvDirectory(const fs::path& env_path) +{ + // Make sure only a single PIVX process is using the wallet directory. + fs::path lock_file_path = env_path / ".lock"; + FILE* file = fsbridge::fopen(lock_file_path, "a"); // empty lock file; created if it doesn't exist. + if (file) fclose(file); + + try { + static boost::interprocess::file_lock lock(lock_file_path.string().c_str()); + if (!lock.try_lock()) { + return false; + } + } catch (const boost::interprocess::interprocess_exception& e) { + return error("Error obtaining lock on wallet directory %s: %s.", env_path.string(), e.what()); + } + return true; +} } // namespace // @@ -98,13 +117,17 @@ void CDBEnv::Close() EnvShutdown(); } -bool CDBEnv::Open(const fs::path& pathIn) +bool CDBEnv::Open(const fs::path& pathIn, bool retry) { if (fDbEnvInit) return true; boost::this_thread::interruption_point(); + if (!LockEnvDirectory(pathIn)) { + return false; + } + strPath = pathIn.string(); fs::path pathLogDir = pathIn / "database"; TryCreateDirectories(pathLogDir); @@ -137,7 +160,24 @@ bool CDBEnv::Open(const fs::path& pathIn) S_IRUSR | S_IWUSR); if (ret != 0) { dbenv->close(0); - return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + LogPrintf("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + if (retry) { + // try moving the database env out of the way + fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime()); + try { + fs::rename(pathLogDir, pathDatabaseBak); + LogPrintf("Moved old %s to %s. Retrying.\n", pathLogDir.string(), pathDatabaseBak.string()); + } catch (const fs::filesystem_error&) { + // failure is ok (well, not really, but it's not worse than what we started with) + } + // try opening it again one more time + if (!Open(pathIn, false)) { + // if it still fails, it probably means we can't even create the database env + return false; + } + } else { + return false; + } } fDbEnvInit = true; @@ -266,25 +306,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle if (walletFile != wallet_file_path.filename().string()) return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, walletDir.string())); - if (!bitdb.Open(walletDir)) - { - // try moving the database env out of the way - fs::path pathDatabase = walletDir / "database"; - fs::path pathDatabaseBak = walletDir / strprintf("database.%d.bak", GetTime()); - try { - fs::rename(pathDatabase, pathDatabaseBak); - LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string()); - } catch (const fs::filesystem_error&) { - // failure is ok (well, not really, but it's not worse than what we started with) - } - - // try again - if (!bitdb.Open(walletDir)) { - // if it still fails, it probably means we can't even create the database env - errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir); - return false; - } + if (!bitdb.Open(walletDir, true)) { + errorStr = strprintf(_("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it."), walletDir); + return false; } + return true; } diff --git a/src/wallet/db.h b/src/wallet/db.h index 168f6522f986f..5254f1c41d6e7 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -70,7 +70,7 @@ class CDBEnv typedef std::pair, std::vector > KeyValPair; bool Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult); - bool Open(const fs::path& path); + bool Open(const fs::path& path, bool retry = 0); void Close(); void Flush(bool fShutdown); void CheckpointLSN(const std::string& strFile);