diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 34c76ec4c..c0c9afe13 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -4,6 +4,8 @@ #include +#include + fs::path GetWalletDir() { fs::path path; @@ -25,3 +27,51 @@ fs::path GetWalletDir() return path; } + +static bool IsBerkeleyBtree(const fs::path& path) +{ + // A Berkeley DB Btree file has at least 4K. + // This check also prevents opening lock files. + boost::system::error_code ec; + if (fs::file_size(path, ec) < 4096) return false; + + fs::ifstream file(path.string(), 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; +} + +std::vector ListWalletDir() +{ + const fs::path wallet_dir = GetWalletDir(); + std::vector paths; + + for (auto it = fs::recursive_directory_iterator(wallet_dir); it != end(it); ++it) { + if (it->status().type() == fs::directory_file && IsBerkeleyBtree(it->path() / "wallet.dat")) { + // Found a directory which contains wallet.dat btree file, add it as a wallet. + paths.emplace_back(fs::relative(it->path(), wallet_dir)); + } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBerkeleyBtree(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(fs::relative(it->path(), wallet_dir)); + } + } + } + + return paths; +} diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index 7c4295461..77f5ca428 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -5,10 +5,14 @@ #ifndef BITCOIN_WALLET_WALLETUTIL_H #define BITCOIN_WALLET_WALLETUTIL_H -#include -#include +#include + +#include //! Get the path of the wallet directory. fs::path GetWalletDir(); +//! Get wallets in wallet directory. +std::vector ListWalletDir(); + #endif // BITCOIN_WALLET_WALLETUTIL_H