| 24 | } |
| 25 | |
| 26 | bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings) |
| 27 | { |
| 28 | DatabaseOptions options; |
| 29 | DatabaseStatus status; |
| 30 | options.require_existing = true; |
| 31 | options.verify = false; |
| 32 | options.require_format = DatabaseFormat::BERKELEY; |
| 33 | std::unique_ptr<WalletDatabase> database = MakeDatabase(file_path, options, status, error); |
| 34 | if (!database) return false; |
| 35 | |
| 36 | BerkeleyDatabase& berkeley_database = static_cast<BerkeleyDatabase&>(*database); |
| 37 | std::string filename = berkeley_database.Filename(); |
| 38 | std::shared_ptr<BerkeleyEnvironment> env = berkeley_database.env; |
| 39 | |
| 40 | if (!env->Open(error)) { |
| 41 | return false; |
| 42 | } |
| 43 | |
| 44 | // Recovery procedure: |
| 45 | // move wallet file to walletfilename.timestamp.bak |
| 46 | // Call Salvage with fAggressive=true to |
| 47 | // get as much data as possible. |
| 48 | // Rewrite salvaged data to fresh wallet file |
| 49 | // Rescan so any missing transactions will be |
| 50 | // found. |
| 51 | int64_t now = GetTime(); |
| 52 | std::string newFilename = strprintf("%s.%d.bak", filename, now); |
| 53 | |
| 54 | int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr, |
| 55 | newFilename.c_str(), DB_AUTO_COMMIT); |
| 56 | if (result != 0) |
| 57 | { |
| 58 | error = strprintf(Untranslated("Failed to rename %s to %s"), filename, newFilename); |
| 59 | return false; |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * Salvage data from a file. The DB_AGGRESSIVE flag is being used (see berkeley DB->verify() method documentation). |
| 64 | * key/value pairs are appended to salvagedData which are then written out to a new wallet file. |
| 65 | * NOTE: reads the entire database into memory, so cannot be used |
| 66 | * for huge databases. |
| 67 | */ |
| 68 | std::vector<KeyValPair> salvagedData; |
| 69 | |
| 70 | std::stringstream strDump; |
| 71 | |
| 72 | Db db(env->dbenv.get(), 0); |
| 73 | result = db.verify(newFilename.c_str(), nullptr, &strDump, DB_SALVAGE | DB_AGGRESSIVE); |
| 74 | if (result == DB_VERIFY_BAD) { |
| 75 | warnings.push_back(Untranslated("Salvage: Database salvage found errors, all data may not be recoverable.")); |
| 76 | } |
| 77 | if (result != 0 && result != DB_VERIFY_BAD) { |
| 78 | error = strprintf(Untranslated("Salvage: Database salvage failed with result %d."), result); |
| 79 | return false; |
| 80 | } |
| 81 | |
| 82 | // Format of bdb dump is ascii lines: |
| 83 | // header lines... |
no test coverage detected