From 5aaeb6cf877055c47fa2bbd2ea5e8d3d2033933b Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 30 Oct 2020 16:11:28 -0400 Subject: [PATCH 1/5] MOVEONLY: Move IsBDBFile, IsSQLiteFile, and ListWalletDir This commit does not change to any code and behavior. It it is easily reviewed with the --color-moved=dimmed_zebra git diff option. Motivation for this change is to: - Consolidate redundant functions IsBDBFile /ExistsBerkeleyDatabase / SplitWalletPath, and IsSQLiteFile / ExistsSQLiteDatabase in the next commits - Detect SQLite wallets consistently regardless whether bitcoin is built with SQLite support in the next commits - Avoid attempting to open SQLite databases with the BDB library when bitcoin is built without SQLite support in the next commits --- src/wallet/bdb.cpp | 25 -------- src/wallet/bdb.h | 3 - src/wallet/db.cpp | 118 ++++++++++++++++++++++++++++++++++++++ src/wallet/db.h | 3 + src/wallet/sqlite.cpp | 34 ----------- src/wallet/sqlite.h | 1 - src/wallet/walletutil.cpp | 55 ------------------ 7 files changed, 121 insertions(+), 118 deletions(-) diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 85aae0170d8..c289f94c786 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -839,28 +839,3 @@ std::unique_ptr MakeBerkeleyDatabase(const fs::path& path, con status = DatabaseStatus::SUCCESS; return db; } - -bool IsBDBFile(const fs::path& path) -{ - if (!fs::exists(path)) return false; - - // A Berkeley DB Btree file has at least 4K. - // This check also prevents opening lock files. - boost::system::error_code ec; - auto size = fs::file_size(path, ec); - if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); - if (size < 4096) return false; - - fsbridge::ifstream file(path, std::ios::binary); - if (!file.is_open()) return false; - - file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 - uint32_t data = 0; - file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic - - // Berkeley DB Btree magic bytes, from: - // https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75 - // - big endian systems - 00 05 31 62 - // - little endian systems - 62 31 05 00 - return data == 0x00053162 || data == 0x62310500; -} diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 4f97665f086..935d0f947db 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -86,9 +86,6 @@ public: /** Get BerkeleyEnvironment and database filename given a wallet path. */ std::shared_ptr GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); -/** Check format of database file */ -bool IsBDBFile(const fs::path& path); - class BerkeleyBatch; /** An instance of this class represents one database. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index bd1d1147303..85aeaeb3ab4 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -3,11 +3,70 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include +#include #include #include +fs::path GetWalletDir(); + +#ifdef USE_BDB +bool ExistsBerkeleyDatabase(const fs::path& path); +#else +# define ExistsBerkeleyDatabase(path) (false) +#endif +#ifdef USE_SQLITE +bool ExistsSQLiteDatabase(const fs::path& path); +#else +# define ExistsSQLiteDatabase(path) (false) +#endif + +std::vector ListWalletDir() +{ + const fs::path wallet_dir = GetWalletDir(); + const size_t offset = wallet_dir.string().size() + 1; + std::vector paths; + boost::system::error_code ec; + + for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { + if (ec) { + LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string()); + continue; + } + + try { + // Get wallet path relative to walletdir by removing walletdir from the wallet path. + // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60. + const fs::path path = it->path().string().substr(offset); + + if (it->status().type() == fs::directory_file && + (ExistsBerkeleyDatabase(it->path()) || ExistsSQLiteDatabase(it->path()))) { + // Found a directory which contains wallet.dat btree file, add it as a wallet. + paths.emplace_back(path); + } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && ExistsBerkeleyDatabase(it->path())) { + if (it->path().filename() == "wallet.dat") { + // Found top-level wallet.dat btree file, add top level directory "" + // as a wallet. + paths.emplace_back(); + } else { + // Found top-level btree file not called wallet.dat. Current bitcoin + // software will never create these files but will allow them to be + // opened in a shared database environment for backwards compatibility. + // Add it to the list of available wallets. + paths.emplace_back(path); + } + } + } catch (const std::exception& e) { + LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what()); + it.no_push(); + } + } + + return paths; +} + void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename) { if (fs::is_regular_file(wallet_path)) { @@ -23,3 +82,62 @@ void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std:: database_filename = "wallet.dat"; } } + +bool IsBDBFile(const fs::path& path) +{ + if (!fs::exists(path)) return false; + + // A Berkeley DB Btree file has at least 4K. + // This check also prevents opening lock files. + boost::system::error_code ec; + auto size = fs::file_size(path, ec); + if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); + if (size < 4096) return false; + + fsbridge::ifstream file(path, std::ios::binary); + if (!file.is_open()) return false; + + file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 + uint32_t data = 0; + file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic + + // Berkeley DB Btree magic bytes, from: + // https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75 + // - big endian systems - 00 05 31 62 + // - little endian systems - 62 31 05 00 + return data == 0x00053162 || data == 0x62310500; +} + +bool IsSQLiteFile(const fs::path& path) +{ + if (!fs::exists(path)) return false; + + // A SQLite Database file is at least 512 bytes. + boost::system::error_code ec; + auto size = fs::file_size(path, ec); + if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); + if (size < 512) return false; + + fsbridge::ifstream file(path, std::ios::binary); + if (!file.is_open()) return false; + + // Magic is at beginning and is 16 bytes long + char magic[16]; + file.read(magic, 16); + + // Application id is at offset 68 and 4 bytes long + file.seekg(68, std::ios::beg); + char app_id[4]; + file.read(app_id, 4); + + file.close(); + + // Check the magic, see https://sqlite.org/fileformat2.html + std::string magic_str(magic, 16); + if (magic_str != std::string("SQLite format 3", 16)) { + return false; + } + + // Check the application id matches our network magic + return memcmp(Params().MessageStart(), app_id, 4) == 0; +} diff --git a/src/wallet/db.h b/src/wallet/db.h index 940d1cd2422..cc13f887b06 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -225,4 +225,7 @@ enum class DatabaseStatus { std::unique_ptr MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); +bool IsBDBFile(const fs::path& path); +bool IsSQLiteFile(const fs::path& path); + #endif // BITCOIN_WALLET_DB_H diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index d278d96476d..69d96dd27c6 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -596,37 +596,3 @@ std::string SQLiteDatabaseVersion() { return std::string(sqlite3_libversion()); } - -bool IsSQLiteFile(const fs::path& path) -{ - if (!fs::exists(path)) return false; - - // A SQLite Database file is at least 512 bytes. - boost::system::error_code ec; - auto size = fs::file_size(path, ec); - if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); - if (size < 512) return false; - - fsbridge::ifstream file(path, std::ios::binary); - if (!file.is_open()) return false; - - // Magic is at beginning and is 16 bytes long - char magic[16]; - file.read(magic, 16); - - // Application id is at offset 68 and 4 bytes long - file.seekg(68, std::ios::beg); - char app_id[4]; - file.read(app_id, 4); - - file.close(); - - // Check the magic, see https://sqlite.org/fileformat2.html - std::string magic_str(magic, 16); - if (magic_str != std::string("SQLite format 3", 16)) { - return false; - } - - // Check the application id matches our network magic - return memcmp(Params().MessageStart(), app_id, 4) == 0; -} diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 693a2ef55a3..3cb11614db9 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -117,6 +117,5 @@ bool ExistsSQLiteDatabase(const fs::path& path); std::unique_ptr MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); std::string SQLiteDatabaseVersion(); -bool IsSQLiteFile(const fs::path& path); #endif // BITCOIN_WALLET_SQLITE_H diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index d6e6f015db2..16ddad3a84f 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -7,17 +7,6 @@ #include #include -#ifdef USE_BDB -bool ExistsBerkeleyDatabase(const fs::path& path); -#else -# define ExistsBerkeleyDatabase(path) (false) -#endif -#ifdef USE_SQLITE -bool ExistsSQLiteDatabase(const fs::path& path); -#else -# define ExistsSQLiteDatabase(path) (false) -#endif - fs::path GetWalletDir() { fs::path path; @@ -40,50 +29,6 @@ fs::path GetWalletDir() return path; } -std::vector ListWalletDir() -{ - const fs::path wallet_dir = GetWalletDir(); - const size_t offset = wallet_dir.string().size() + 1; - std::vector paths; - boost::system::error_code ec; - - for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { - if (ec) { - LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string()); - continue; - } - - try { - // Get wallet path relative to walletdir by removing walletdir from the wallet path. - // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60. - const fs::path path = it->path().string().substr(offset); - - if (it->status().type() == fs::directory_file && - (ExistsBerkeleyDatabase(it->path()) || ExistsSQLiteDatabase(it->path()))) { - // Found a directory which contains wallet.dat btree file, add it as a wallet. - paths.emplace_back(path); - } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && ExistsBerkeleyDatabase(it->path())) { - if (it->path().filename() == "wallet.dat") { - // Found top-level wallet.dat btree file, add top level directory "" - // as a wallet. - paths.emplace_back(); - } else { - // Found top-level btree file not called wallet.dat. Current bitcoin - // software will never create these files but will allow them to be - // opened in a shared database environment for backwards compatibility. - // Add it to the list of available wallets. - paths.emplace_back(path); - } - } - } catch (const std::exception& e) { - LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what()); - it.no_push(); - } - } - - return paths; -} - bool IsFeatureSupported(int wallet_version, int feature_version) { return wallet_version >= feature_version; From 6ee9cbdd18a70894f89dd268c276d5eb47a34827 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 30 Oct 2020 16:25:56 -0400 Subject: [PATCH 2/5] refactor: Replace ListWalletDir() function with ListDatabases() No change to behavior. This is just cleanup after previous MOVEONLY commit to make db.h list function fit conventions of surrounding functions. --- src/wallet/db.cpp | 5 +---- src/wallet/db.h | 3 +++ src/wallet/interfaces.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- src/wallet/walletutil.h | 3 --- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 85aeaeb3ab4..e8b8b8abc12 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -10,8 +10,6 @@ #include -fs::path GetWalletDir(); - #ifdef USE_BDB bool ExistsBerkeleyDatabase(const fs::path& path); #else @@ -23,9 +21,8 @@ bool ExistsSQLiteDatabase(const fs::path& path); # define ExistsSQLiteDatabase(path) (false) #endif -std::vector ListWalletDir() +std::vector ListDatabases(const fs::path& wallet_dir) { - const fs::path wallet_dir = GetWalletDir(); const size_t offset = wallet_dir.string().size() + 1; std::vector paths; boost::system::error_code ec; diff --git a/src/wallet/db.h b/src/wallet/db.h index cc13f887b06..3d18e5cec0e 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -223,6 +223,9 @@ enum class DatabaseStatus { FAILED_ENCRYPT, }; +/** Recursively list database paths in directory. */ +std::vector ListDatabases(const fs::path& path); + std::unique_ptr MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); bool IsBDBFile(const fs::path& path); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 3fbba9ab921..46ef6eee3ec 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -551,7 +551,7 @@ public: std::vector listWalletDir() override { std::vector paths; - for (auto& path : ListWalletDir()) { + for (auto& path : ListDatabases(GetWalletDir())) { paths.push_back(path.string()); } return paths; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7ea6a214b24..3802bb452a2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2537,7 +2537,7 @@ static RPCHelpMan listwalletdir() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue wallets(UniValue::VARR); - for (const auto& path : ListWalletDir()) { + for (const auto& path : ListDatabases(GetWalletDir())) { UniValue wallet(UniValue::VOBJ); wallet.pushKV("name", path.string()); wallets.push_back(wallet); diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index 27521abd81c..d4143ceff47 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -65,9 +65,6 @@ enum WalletFlags : uint64_t { //! Get the path of the wallet directory. fs::path GetWalletDir(); -//! Get wallets in wallet directory. -std::vector ListWalletDir(); - /** Descriptor with some wallet metadata */ class WalletDescriptor { From 6a7a63644cd2fc56538d323cc0d5c1d7945247fd Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 30 Oct 2020 16:28:44 -0400 Subject: [PATCH 3/5] refactor: Drop call to GetWalletEnv in wallet salvage code No observable change in behavior. This just avoids a redundant environment lookup. Motivation is to be able to simplify the GetWalletEnv implementation in an upcoming commit. --- src/wallet/salvage.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index da5ca7858f2..09a9ec68cd0 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -32,8 +32,9 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v std::unique_ptr database = MakeDatabase(file_path, options, status, error); if (!database) return false; - std::string filename; - std::shared_ptr env = GetWalletEnv(file_path, filename); + BerkeleyDatabase& berkeley_database = static_cast(*database); + std::string filename = berkeley_database.Filename(); + std::shared_ptr env = berkeley_database.env; if (!env->Open(error)) { return false; From d70dc89e78ee6355e0bc37cc36cfc04ef7a86885 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 30 Oct 2020 16:41:23 -0400 Subject: [PATCH 4/5] refactor: Consolidate redundant wallet database path and exists functions No change in behavior. Just remove a little bit of code, reduce macro usage, remove duplicative functions, and make BDB and SQLite implementations more consistent with each other. --- src/wallet/bdb.cpp | 20 +++++--------------- src/wallet/bdb.h | 7 ++----- src/wallet/db.cpp | 36 ++++++++++++++++++------------------ src/wallet/db.h | 2 ++ src/wallet/sqlite.cpp | 11 ++--------- src/wallet/sqlite.h | 1 - src/wallet/test/db_tests.cpp | 7 +++++++ src/wallet/walletdb.cpp | 8 ++------ 8 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index c289f94c786..6ed48593fb6 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -53,16 +53,13 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const } /** - * @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory. - * @param[out] database_filename Filename of berkeley btree data file inside the wallet directory. + * @param[in] env_directory Path to environment directory * @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment * erases the weak pointer from the g_dbenvs map. * @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map. */ -std::shared_ptr GetWalletEnv(const fs::path& wallet_path, std::string& database_filename) +std::shared_ptr GetBerkeleyEnv(const fs::path& env_directory) { - fs::path env_directory; - SplitWalletPath(wallet_path, env_directory, database_filename); LOCK(cs_db); auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr()); if (inserted.second) { @@ -808,21 +805,14 @@ std::unique_ptr BerkeleyDatabase::MakeBatch(bool flush_on_close) return MakeUnique(*this, false, flush_on_close); } -bool ExistsBerkeleyDatabase(const fs::path& path) -{ - fs::path env_directory; - std::string data_filename; - SplitWalletPath(path, env_directory, data_filename); - return IsBDBFile(env_directory / data_filename); -} - std::unique_ptr MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) { + fs::path data_file = BDBDataFile(path); std::unique_ptr db; { LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor - std::string data_filename; - std::shared_ptr env = GetWalletEnv(path, data_filename); + std::string data_filename = data_file.filename().string(); + std::shared_ptr env = GetBerkeleyEnv(data_file.parent_path()); 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; diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 935d0f947db..bf1617d67f9 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -83,8 +83,8 @@ public: } }; -/** Get BerkeleyEnvironment and database filename given a wallet path. */ -std::shared_ptr GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); +/** Get BerkeleyEnvironment given a directory path. */ +std::shared_ptr GetBerkeleyEnv(const fs::path& env_directory); class BerkeleyBatch; @@ -223,9 +223,6 @@ 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 MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index e8b8b8abc12..425b14b8f9f 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -10,17 +10,6 @@ #include -#ifdef USE_BDB -bool ExistsBerkeleyDatabase(const fs::path& path); -#else -# define ExistsBerkeleyDatabase(path) (false) -#endif -#ifdef USE_SQLITE -bool ExistsSQLiteDatabase(const fs::path& path); -#else -# define ExistsSQLiteDatabase(path) (false) -#endif - std::vector ListDatabases(const fs::path& wallet_dir) { const size_t offset = wallet_dir.string().size() + 1; @@ -39,10 +28,10 @@ std::vector ListDatabases(const fs::path& wallet_dir) const fs::path path = it->path().string().substr(offset); if (it->status().type() == fs::directory_file && - (ExistsBerkeleyDatabase(it->path()) || ExistsSQLiteDatabase(it->path()))) { + (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) { // Found a directory which contains wallet.dat btree file, add it as a wallet. paths.emplace_back(path); - } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && ExistsBerkeleyDatabase(it->path())) { + } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) { if (it->path().filename() == "wallet.dat") { // Found top-level wallet.dat btree file, add top level directory "" // as a wallet. @@ -64,24 +53,31 @@ std::vector ListDatabases(const fs::path& wallet_dir) return paths; } -void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename) +fs::path BDBDataFile(const fs::path& wallet_path) { if (fs::is_regular_file(wallet_path)) { // Special case for backwards compatibility: if wallet path points to an // existing file, treat it as the path to a BDB data file in a parent // directory that also contains BDB log files. - env_directory = wallet_path.parent_path(); - database_filename = wallet_path.filename().string(); + return wallet_path; } else { // Normal case: Interpret wallet path as a directory path containing // data and log files. - env_directory = wallet_path; - database_filename = "wallet.dat"; + return wallet_path / "wallet.dat"; } } +fs::path SQLiteDataFile(const fs::path& path) +{ + return path / "wallet.dat"; +} + bool IsBDBFile(const fs::path& path) { +#ifndef USE_BDB + return false; +#endif + if (!fs::exists(path)) return false; // A Berkeley DB Btree file has at least 4K. @@ -107,6 +103,10 @@ bool IsBDBFile(const fs::path& path) bool IsSQLiteFile(const fs::path& path) { +#ifndef USE_SQLITE + return false; +#endif + if (!fs::exists(path)) return false; // A SQLite Database file is at least 512 bytes. diff --git a/src/wallet/db.h b/src/wallet/db.h index 3d18e5cec0e..2c75486a44b 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -228,6 +228,8 @@ std::vector ListDatabases(const fs::path& path); std::unique_ptr MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); +fs::path BDBDataFile(const fs::path& path); +fs::path SQLiteDataFile(const fs::path& path); bool IsBDBFile(const fs::path& path); bool IsSQLiteFile(const fs::path& path); diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 69d96dd27c6..0fb3b1d3c41 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -17,7 +17,6 @@ #include #include -static const char* const DATABASE_FILENAME = "wallet.dat"; static constexpr int32_t WALLET_SCHEMA_VERSION = 0; static Mutex g_sqlite_mutex; @@ -568,17 +567,11 @@ bool SQLiteBatch::TxnAbort() return res == SQLITE_OK; } -bool ExistsSQLiteDatabase(const fs::path& path) -{ - const fs::path file = path / DATABASE_FILENAME; - return fs::symlink_status(file).type() == fs::regular_file && IsSQLiteFile(file); -} - std::unique_ptr MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) { - const fs::path file = path / DATABASE_FILENAME; try { - auto db = MakeUnique(path, file); + fs::path data_file = SQLiteDataFile(path); + auto db = MakeUnique(data_file.parent_path(), data_file); if (options.verify && !db->Verify(error)) { status = DatabaseStatus::FAILED_VERIFY; return nullptr; diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 3cb11614db9..442563184e3 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -113,7 +113,6 @@ public: sqlite3* m_db{nullptr}; }; -bool ExistsSQLiteDatabase(const fs::path& path); std::unique_ptr MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); std::string SQLiteDatabaseVersion(); diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index 8f0083cd2e4..1a28852a6bb 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -13,6 +13,13 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup) +static std::shared_ptr GetWalletEnv(const fs::path& path, std::string& database_filename) +{ + fs::path data_file = BDBDataFile(path); + database_filename = data_file.filename().string(); + return GetBerkeleyEnv(data_file.parent_path()); +} + BOOST_AUTO_TEST_CASE(getwalletenv_file) { std::string test_name = "test_name.dat"; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index c0521d33865..5b72a019396 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1013,13 +1013,10 @@ std::unique_ptr MakeDatabase(const fs::path& path, const Databas Optional format; if (exists) { -#ifdef USE_BDB - if (ExistsBerkeleyDatabase(path)) { + if (IsBDBFile(BDBDataFile(path))) { format = DatabaseFormat::BERKELEY; } -#endif -#ifdef USE_SQLITE - if (ExistsSQLiteDatabase(path)) { + if (IsSQLiteFile(SQLiteDataFile(path))) { if (format) { error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string())); status = DatabaseStatus::FAILED_BAD_FORMAT; @@ -1027,7 +1024,6 @@ std::unique_ptr MakeDatabase(const fs::path& path, const Databas } format = DatabaseFormat::SQLITE; } -#endif } 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; From f3d870fc2271bf45e0269e5ae135bced1a26f620 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 30 Oct 2020 16:48:04 -0400 Subject: [PATCH 5/5] wallet: List all wallets in non-SQLite or non-BDB builds This commit does not change behavior when bitcoin is built normally with both the SQLite and BDB libraries. It just makes non-SQLite and non-BDB builds more similar to the normal build. Specifically: - It makes wallet directory lists always include all wallets so wallets don't appear missing depending on the build. - It now triggers specific "Build does not support SQLite database format" and "Build does not support Berkeley DB database format" errors if a wallet can't be loaded instead of the more ambiguous and scary "Data is not in recognized format" error. --- src/wallet/db.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 425b14b8f9f..cd49baeb786 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -74,10 +74,6 @@ fs::path SQLiteDataFile(const fs::path& path) bool IsBDBFile(const fs::path& path) { -#ifndef USE_BDB - return false; -#endif - if (!fs::exists(path)) return false; // A Berkeley DB Btree file has at least 4K. @@ -103,10 +99,6 @@ bool IsBDBFile(const fs::path& path) bool IsSQLiteFile(const fs::path& path) { -#ifndef USE_SQLITE - return false; -#endif - if (!fs::exists(path)) return false; // A SQLite Database file is at least 512 bytes.