Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/walletutil.cpp
// Copyright (c) 2017 The Bitcoin Core developers | // Copyright (c) 2017 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <wallet/walletutil.h> | #include <wallet/walletutil.h> | ||||
#include <logging.h> | #include <logging.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
bool ExistsBerkeleyDatabase(const fs::path &path); | |||||
fs::path GetWalletDir() { | fs::path GetWalletDir() { | ||||
fs::path path; | fs::path path; | ||||
if (gArgs.IsArgSet("-walletdir")) { | if (gArgs.IsArgSet("-walletdir")) { | ||||
path = gArgs.GetArg("-walletdir", ""); | path = gArgs.GetArg("-walletdir", ""); | ||||
if (!fs::is_directory(path)) { | if (!fs::is_directory(path)) { | ||||
// If the path specified doesn't exist, we return the deliberately | // If the path specified doesn't exist, we return the deliberately | ||||
// invalid empty string. | // invalid empty string. | ||||
path = ""; | path = ""; | ||||
} | } | ||||
} else { | } else { | ||||
path = GetDataDir(); | path = GetDataDir(); | ||||
// If a wallets directory exists, use that, otherwise default to | // If a wallets directory exists, use that, otherwise default to | ||||
// GetDataDir | // GetDataDir | ||||
if (fs::is_directory(path / "wallets")) { | if (fs::is_directory(path / "wallets")) { | ||||
path /= "wallets"; | path /= "wallets"; | ||||
} | } | ||||
} | } | ||||
return path; | return path; | ||||
} | } | ||||
bool IsBerkeleyBtree(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; | |||||
} | |||||
// Magic bytes start at offset 12 | |||||
file.seekg(12, std::ios::beg); | |||||
uint32_t data = 0; | |||||
// Read 4 bytes of file to compare against magic | |||||
file.read((char *)&data, sizeof(data)); | |||||
// 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<fs::path> ListWalletDir() { | std::vector<fs::path> ListWalletDir() { | ||||
const fs::path wallet_dir = GetWalletDir(); | const fs::path wallet_dir = GetWalletDir(); | ||||
const size_t offset = wallet_dir.string().size() + 1; | const size_t offset = wallet_dir.string().size() + 1; | ||||
std::vector<fs::path> paths; | std::vector<fs::path> paths; | ||||
boost::system::error_code ec; | boost::system::error_code ec; | ||||
for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); | for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); | ||||
it != fs::recursive_directory_iterator(); it.increment(ec)) { | it != fs::recursive_directory_iterator(); it.increment(ec)) { | ||||
if (ec) { | if (ec) { | ||||
LogPrintf("%s: %s %s\n", __func__, ec.message(), | LogPrintf("%s: %s %s\n", __func__, ec.message(), | ||||
it->path().string()); | it->path().string()); | ||||
continue; | continue; | ||||
} | } | ||||
// Get wallet path relative to walletdir by removing walletdir from the | // Get wallet path relative to walletdir by removing walletdir from the | ||||
// wallet path. This can be replaced by | // wallet path. This can be replaced by | ||||
// boost::filesystem::lexically_relative once boost is bumped to 1.60. | // boost::filesystem::lexically_relative once boost is bumped to 1.60. | ||||
const fs::path path = it->path().string().substr(offset); | const fs::path path = it->path().string().substr(offset); | ||||
if (it->status().type() == fs::directory_file && | if (it->status().type() == fs::directory_file && | ||||
IsBerkeleyBtree(it->path() / "wallet.dat")) { | ExistsBerkeleyDatabase(it->path())) { | ||||
// Found a directory which contains wallet.dat btree file, add it as | // Found a directory which contains wallet.dat btree file, add it as | ||||
// a wallet. | // a wallet. | ||||
paths.emplace_back(path); | paths.emplace_back(path); | ||||
} else if (it.level() == 0 && | } else if (it.level() == 0 && | ||||
it->symlink_status().type() == fs::regular_file && | it->symlink_status().type() == fs::regular_file && | ||||
IsBerkeleyBtree(it->path())) { | ExistsBerkeleyDatabase(it->path())) { | ||||
if (it->path().filename() == "wallet.dat") { | if (it->path().filename() == "wallet.dat") { | ||||
// Found top-level wallet.dat btree file, add top level | // Found top-level wallet.dat btree file, add top level | ||||
// directory "" as a wallet. | // directory "" as a wallet. | ||||
paths.emplace_back(); | paths.emplace_back(); | ||||
} else { | } else { | ||||
// Found top-level btree file not called wallet.dat. Current | // Found top-level btree file not called wallet.dat. Current | ||||
// bitcoin software will never create these files but will allow | // bitcoin software will never create these files but will allow | ||||
// them to be opened in a shared database environment for | // them to be opened in a shared database environment for | ||||
Show All 9 Lines |