Support for wallets outside of the default wallet directory was added in #11687, and these external wallets can be specified with paths relative to the wallet directory, e.g. bitcoin-cli loadwallet ../../mywallet
. In the RPC commands, there is no distinction between a wallet’s ’name’ and a wallet’s ‘path’. I suspect this may not be the only bug like this, since everywhere that a wallet’s name appears in code, that name might be a path, and that path may contain relative specifiers, and the consequences of that are not always obvious, and test coverage for wallets with relative paths seems like it could be improved.
This PR fixes an issue with wallet backup during migration where the wallet’s ’name’ is used in the backup filename. This goes south when that filename is appended (/=
) to the directory where we want to put the file and the wallet’s ’name’ actually gets treated as a path:
0 fs::path backup_filename = fs::PathFromString(strprintf("%s_%d.legacy.bak", (wallet_name.empty() ? "default_wallet" : wallet_name), GetTime()));
1 fs::path backup_path = this_wallet_dir / backup_filename;
Attempting to migrate a wallet with the ’name’ ../../../mywallet
results in a backup being placed in datadir/wallets/../../../mywallet/../../../mywallet_1744683963.legacy.bak
.
The solution implemented here is to use the wallet directory’s name rather than the wallet_name
when constructing the backup filename:
0 std::string legacy_wallet_dir_name = fs::PathToString(legacy_wallet_dir.filename());
1 fs::path backup_filename = fs::PathFromString(strprintf("%s_%d.legacy.bak", (wallet_name.empty() ? "default_wallet" : legacy_wallet_dir_name), GetTime()));
An alternative solution would have been to escape the path characters in the wallet’s name, but that seemed both more difficult to implement correctly, and like it might cause confusion for users.
This does not cause an issue for wallets with absolute pathnames because std::filesystem::operator/(path lhs, path rhs)
returns rhs
if rhs.is_absolute()
. (https://en.cppreference.com/w/cpp/filesystem/path/append)
Steps to reproduce on master
Build and run bitcoind
with legacy wallet creation enabled:
0$ cmake -B build -DWITH_BDB=ON && cmake --build build -j $(nproc)
1$ ./build/bin/bitcoind -regtest -deprecatedrpc=create_bdb
Create a wallet with some relative path specifiers (exercise caution with where this file may be written)
0$ ./build/bin/bitcoin-cli -regtest -named createwallet wallet_name="../../../myrelativewallet" descriptors=false
Try to migrate the wallet:
0$ ./build/bin/bitcoin-cli -regtest -named migratewallet wallet_name="../../../myrelativewallet"
You will see a message in debug.log
about trying to backup a file somewhere like: /home/user/.bitcoin/regtest/wallets/../../../myrelativewallet/../../../myrelativewallet_1744686627.legacy.bak
and migration might fail because bitcoind
doesn’t have permissions to write the backup file.