Repository: bitcoin/bitcoin
File: src/wallet/wallet.cpp (C++)

Code before:
}

// Re-creates wallet from the backup file by renaming and moving it into the wallet's directory.
// If 'load_after_restore=true', the wallet object will be fully initialized and appended to the context.
std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings, bool load_after_restore)
{
    DatabaseOptions options;
    ReadDatabaseArgs(*context.args, options);
    options.require_existing = true;

    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)) {
            error = Untranslated("Backup file does not exist");
            status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
            return nullptr;
        }

        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);
        }
    } catch (const std::exception& e) {
        assert(!wallet);
        if (!error.empty()) error += Untranslated("\n");
        error += Untranslated(strprintf("Unexpected exception: %s", e.what()));
    }

    // Remove created wallet path only when loading fails
    if (load_after_restore && !wallet) {

Review comment (bug):
In commit "wallet: RestoreWallet failure, erase only what was created" (5ed59557b91f85d2c36d911bd2a334cb80b7494c)

This fs::exists call is redundant and could be dropped. TryCreateDirectories already returns true if the directory was created, false if it existed, and it throws an exception on other errors.

So this could simply be:

```c++
created_parent_dir = TryCreateDirectories(wallet_path);
if (!created_parent_dir) {
    error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
    status = DatabaseStatus::FAILED_ALREADY_EXISTS;
}
```



Code after:
}

// Re-creates wallet from the backup file by renaming and moving it into the wallet's directory.
// If 'load_after_restore=true', the wallet object will be fully initialized and appended to the context.
std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings, bool load_after_restore)
{
    DatabaseOptions options;
    ReadDatabaseArgs(*context.args, options);
    options.require_existing = true;

    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)) {
            error = Untranslated("Backup file does not exist");
            status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
            return nullptr;
        }

        // Wallet directories are allowed to exist, but must not contain a .dat file.
        // Any existing wallet database is treated as a hard failure to prevent overwriting.
        if (fs::exists(wallet_path)) {
            // If this is a file, it is the db and we don't want to overwrite it.
            if (!fs::is_directory(wallet_path)) {
                error = Untranslated(strprintf("Failed to restore wallet. Database file exists '%s'.", fs::PathToString(wallet_path)));
                status = DatabaseStatus::FAILED_ALREADY_EXISTS;
                return nullptr;
            }

            // Check we are not going to overwrite an existing db file
            if (fs::exists(wallet_file)) {
                error = Untranslated(strprintf("Failed to restore wallet. Database file exists in '%s'.", fs::PathToString(wallet_file)));
                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;