|
|
@ -18,6 +18,7 @@ |
|
|
|
#include <sys/stat.h> |
|
|
|
#include <sys/stat.h> |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/interprocess/sync/file_lock.hpp> |
|
|
|
#include <boost/thread.hpp> |
|
|
|
#include <boost/thread.hpp> |
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
namespace { |
|
|
@ -52,6 +53,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool LockEnvDirectory(const fs::path& env_path) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Make sure only a single Bitcoin 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
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -95,13 +114,17 @@ void CDBEnv::Close() |
|
|
|
EnvShutdown(); |
|
|
|
EnvShutdown(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool CDBEnv::Open(const fs::path& pathIn) |
|
|
|
bool CDBEnv::Open(const fs::path& pathIn, bool retry) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (fDbEnvInit) |
|
|
|
if (fDbEnvInit) |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!LockEnvDirectory(pathIn)) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
strPath = pathIn.string(); |
|
|
|
strPath = pathIn.string(); |
|
|
|
fs::path pathLogDir = pathIn / "database"; |
|
|
|
fs::path pathLogDir = pathIn / "database"; |
|
|
|
TryCreateDirectories(pathLogDir); |
|
|
|
TryCreateDirectories(pathLogDir); |
|
|
@ -134,7 +157,24 @@ bool CDBEnv::Open(const fs::path& pathIn) |
|
|
|
S_IRUSR | S_IWUSR); |
|
|
|
S_IRUSR | S_IWUSR); |
|
|
|
if (ret != 0) { |
|
|
|
if (ret != 0) { |
|
|
|
dbenv->close(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; |
|
|
|
fDbEnvInit = true; |
|
|
@ -269,25 +309,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!bitdb.Open(walletDir)) |
|
|
|
if (!bitdb.Open(walletDir, true)) { |
|
|
|
{ |
|
|
|
errorStr = strprintf(_("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it."), 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; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|