diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/bdb.cpp | 32 | ||||
-rw-r--r-- | src/wallet/bdb.h | 9 | ||||
-rw-r--r-- | src/wallet/db.h | 22 | ||||
-rw-r--r-- | src/wallet/walletdb.cpp | 39 | ||||
-rw-r--r-- | src/wallet/walletutil.cpp | 2 |
5 files changed, 103 insertions, 1 deletions
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 24eb2ee34c..61463aaf5e 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -824,3 +824,35 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, boo { return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close); } + +bool ExistsBerkeleyDatabase(const fs::path& path) +{ + fs::path env_directory; + std::string data_filename; + SplitWalletPath(path, env_directory, data_filename); + return IsBerkeleyBtree(env_directory / data_filename); +} + +std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) +{ + std::unique_ptr<BerkeleyDatabase> db; + { + LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor + std::string data_filename; + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename); + if (env->m_databases.count(data_filename)) { + error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string())); + status = DatabaseStatus::FAILED_ALREADY_LOADED; + return nullptr; + } + db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename)); + } + + if (options.verify && !db->Verify(error)) { + status = DatabaseStatus::FAILED_VERIFY; + return nullptr; + } + + status = DatabaseStatus::SUCCESS; + return db; +} diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 75546924e8..82ad136649 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -90,6 +90,9 @@ std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, s /** Return whether a BDB wallet database is currently loaded. */ bool IsBDBWalletLoaded(const fs::path& wallet_path); +/** Check format of database file */ +bool IsBerkeleyBtree(const fs::path& path); + class BerkeleyBatch; /** An instance of this class represents one database. @@ -224,4 +227,10 @@ public: std::string BerkeleyDatabaseVersion(); +//! Check if Berkeley database exists at specified path. +bool ExistsBerkeleyDatabase(const fs::path& path); + +//! Return object giving access to Berkeley database at specified path. +std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); + #endif // BITCOIN_WALLET_BDB_H diff --git a/src/wallet/db.h b/src/wallet/db.h index 0afaba5fd1..f0f6f03c43 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -195,4 +195,26 @@ public: std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); } }; +enum class DatabaseFormat { + BERKELEY, +}; + +struct DatabaseOptions { + bool require_existing = false; + bool require_create = false; + bool verify = true; +}; + +enum class DatabaseStatus { + SUCCESS, + FAILED_BAD_PATH, + FAILED_BAD_FORMAT, + FAILED_ALREADY_LOADED, + FAILED_ALREADY_EXISTS, + FAILED_NOT_FOUND, + FAILED_VERIFY, +}; + +std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); + #endif // BITCOIN_WALLET_DB_H diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 962ea66fa0..23c4b69777 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -13,6 +13,8 @@ #include <util/bip32.h> #include <util/system.h> #include <util/time.h> +#include <util/translation.h> +#include <wallet/bdb.h> #include <wallet/wallet.h> #include <atomic> @@ -993,6 +995,43 @@ bool WalletBatch::TxnAbort() return m_batch->TxnAbort(); } +std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) +{ + bool exists; + try { + exists = fs::symlink_status(path).type() != fs::file_not_found; + } catch (const fs::filesystem_error& e) { + error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e))); + status = DatabaseStatus::FAILED_BAD_PATH; + return nullptr; + } + + Optional<DatabaseFormat> format; + if (exists) { + if (ExistsBerkeleyDatabase(path)) { + format = DatabaseFormat::BERKELEY; + } + } else if (options.require_existing) { + error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string())); + status = DatabaseStatus::FAILED_NOT_FOUND; + return nullptr; + } + + if (!format && options.require_existing) { + error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string())); + status = DatabaseStatus::FAILED_BAD_FORMAT; + return nullptr; + } + + if (format && options.require_create) { + error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string())); + status = DatabaseStatus::FAILED_ALREADY_EXISTS; + return nullptr; + } + + return MakeBerkeleyDatabase(path, options, status, error); +} + bool IsWalletLoaded(const fs::path& wallet_path) { return IsBDBWalletLoaded(wallet_path); diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index d6a8ee9e02..e4c72aed98 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -29,7 +29,7 @@ fs::path GetWalletDir() return path; } -static bool IsBerkeleyBtree(const fs::path& path) +bool IsBerkeleyBtree(const fs::path& path) { if (!fs::exists(path)) return false; |