wallet: RestoreWallet failure, erase only what was created

Track what RestoreWallet creates so only those files and directories
are removed during a failure and nothing else. Preexisting paths
must be left untouched.

Note:
Using fs::remove_all() instead of fs::remove() in RestoreWallet does
not cause any problems currently, but the change is necessary for the
next commit which extends RestoreWallet to work with existing directories,
which may contain files that must not be deleted.
This commit is contained in:
furszy
2026-01-05 18:12:40 -05:00
parent d861c38205
commit 4ed0693a3f

View File

@@ -470,6 +470,8 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
auto wallet_file = wallet_path / "wallet.dat";
std::shared_ptr<CWallet> wallet;
bool wallet_file_copied = false;
bool created_parent_dir = false;
try {
if (!fs::exists(backup_file)) {
@@ -478,13 +480,22 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
return nullptr;
}
if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
if (fs::exists(wallet_path)) {
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
return nullptr;
} else {
// The directory doesn't exist, create it
if (!TryCreateDirectories(wallet_path)) {
error = Untranslated(strprintf("Failed to restore database path '%s'.", fs::PathToString(wallet_path)));
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
return nullptr;
}
created_parent_dir = true;
}
fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
wallet_file_copied = true;
if (load_after_restore) {
wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
@@ -497,7 +508,13 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
// Remove created wallet path only when loading fails
if (load_after_restore && !wallet) {
fs::remove_all(wallet_path);
if (wallet_file_copied) fs::remove(wallet_file);
// Clean up the parent directory if we created it during restoration.
// As we have created it, it must be empty after deleting the wallet file.
if (created_parent_dir) {
Assume(fs::is_empty(wallet_path));
fs::remove(wallet_path);
}
}
return wallet;