diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -306,65 +306,27 @@ uiInterface.InitMessage(_("Verifying wallet(s)...")); + std::vector wallet_files = gArgs.GetArgs("-wallet"); + + // Parameter interaction code should have thrown an error if -salvagewallet + // was enabled with more than wallet file, so the wallet_files size check + // here should have no effect. + bool salvage_wallet = + gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1; + // Keep track of each wallet absolute path to detect duplicates. std::set wallet_paths; - for (const std::string &walletFile : gArgs.GetArgs("-wallet")) { - // Do some checking on wallet path. It should be either a: - // - // 1. Path where a directory can be created. - // 2. Path to an existing directory. - // 3. Path to a symlink to a directory. - // 4. For backwards compatibility, the name of a data file in - // -walletdir. - fs::path wallet_path = fs::absolute(walletFile, GetWalletDir()); - fs::file_type path_type = fs::symlink_status(wallet_path).type(); - if (!(path_type == fs::file_not_found || - path_type == fs::directory_file || - (path_type == fs::symlink_file && - fs::is_directory(wallet_path)) || - (path_type == fs::regular_file && - fs::path(walletFile).filename() == walletFile))) { - return InitError(strprintf( - _("Invalid -wallet path '%s'. -wallet path should point to a " - "directory where wallet.dat and database/log.?????????? " - "files can be stored, a location where such a directory " - "could be created, or (for backwards compatibility) the name " - "of an existing data file in -walletdir (%s)"), - walletFile, GetWalletDir())); - } + for (const auto wallet_file : wallet_files) { + fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir()); if (!wallet_paths.insert(wallet_path).second) { return InitError(strprintf(_("Error loading wallet %s. Duplicate " "-wallet filename specified."), - walletFile)); + wallet_file)); } - std::string strError; - if (!WalletBatch::VerifyEnvironment(wallet_path, strError)) { - return InitError(strError); - } - - if (gArgs.GetBoolArg("-salvagewallet", false)) { - // Recover readable keypairs: - CWallet dummyWallet(chainParams, "dummy", - WalletDatabase::CreateDummy()); - std::string backup_filename; - if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, - WalletBatch::RecoverKeysOnlyFilter, - backup_filename)) { - return false; - } - } - - std::string strWarning; - bool dbV = - WalletBatch::VerifyDatabaseFile(wallet_path, strWarning, strError); - if (!strWarning.empty()) { - InitWarning(strWarning); - } - if (!dbV) { - InitError(strError); + if (!CWallet::Verify(chainParams, wallet_file, salvage_wallet)) { return false; } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1214,6 +1214,10 @@ */ bool AbandonTransaction(const TxId &txid); + //! Verify wallet naming and perform salvage on the wallet if required + static bool Verify(const CChainParams &chainParams, std::string wallet_file, + bool salvage_wallet); + /** * Initializes the wallet, returns a new CWallet instance or a null pointer * in case of an error. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -4227,6 +4228,71 @@ return values; } +bool CWallet::Verify(const CChainParams &chainParams, std::string wallet_file, + bool salvage_wallet) { + // Do some checking on wallet path. It should be either a: + // + // 1. Path where a directory can be created. + // 2. Path to an existing directory. + // 3. Path to a symlink to a directory. + // 4. For backwards compatibility, the name of a data file in -walletdir. + LOCK(cs_wallets); + fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir()); + fs::file_type path_type = fs::symlink_status(wallet_path).type(); + if (!(path_type == fs::file_not_found || path_type == fs::directory_file || + (path_type == fs::symlink_file && fs::is_directory(wallet_path)) || + (path_type == fs::regular_file && + fs::path(wallet_file).filename() == wallet_file))) { + return InitError( + strprintf(_("Invalid -wallet path '%s'. -wallet path should point " + "to a directory where wallet.dat and " + "database/log.?????????? files can be stored, a " + "location where such a directory could be created, " + "or (for backwards compatibility) the name of an " + "existing data file in -walletdir (%s)"), + wallet_file, GetWalletDir())); + } + + // Make sure that the wallet path doesn't clash with an existing wallet path + for (auto wallet : GetWallets()) { + if (fs::absolute(wallet->GetName(), GetWalletDir()) == wallet_path) { + return InitError(strprintf(_("Error loading wallet %s. Duplicate " + "-wallet filename specified."), + wallet_file)); + } + } + + std::string strError; + if (!WalletBatch::VerifyEnvironment(wallet_path, strError)) { + return InitError(strError); + } + + if (salvage_wallet) { + // Recover readable keypairs: + CWallet dummyWallet(chainParams, "dummy", + WalletDatabase::CreateDummy()); + std::string backup_filename; + if (!WalletBatch::Recover( + wallet_path, static_cast(&dummyWallet), + WalletBatch::RecoverKeysOnlyFilter, backup_filename)) { + return false; + } + } + + std::string strWarning; + bool dbV = + WalletBatch::VerifyDatabaseFile(wallet_path, strWarning, strError); + if (!strWarning.empty()) { + InitWarning(strWarning); + } + if (!dbV) { + InitError(strError); + return false; + } + + return true; +} + CWallet *CWallet::CreateWalletFromFile(const CChainParams &chainParams, const std::string &name, const fs::path &path) {