# # # patch "cmd_db.cc" # from [503c0837df8062cb74dc38a7d6885903a42ae602] # to [c21a2213ce729fab7e7505724f34c3f7b703eb9f] # # patch "database.cc" # from [531d8e9f50ca3321e36abbd8d03797ea55b15c27] # to [6b4b27d8814b113925c95ce373fa8931d38903eb] # # patch "database.hh" # from [3a3eb474823b087fda8af2813e8f503b53a8c76e] # to [a006d634bcd15da827bc19e732eb2b993b122ca6] # # patch "options_list.hh" # from [374f03bbb24468a2dfb5a51e3d3f2eaa1a78b1f1] # to [820a2e9dfb65c7771b047f333f9e26d067b4ee97] # ============================================================ --- cmd_db.cc 503c0837df8062cb74dc38a7d6885903a42ae602 +++ cmd_db.cc c21a2213ce729fab7e7505724f34c3f7b703eb9f @@ -76,6 +76,23 @@ CMD(db_version, "version", "", CMD_REF(d db.version(cout); } +CMD(db_fix_certs, "fix_certs", "", CMD_REF(db), "", + N_("Attempt to fix bad certs"), + N_("Older monotone versions could sometimes associate certs with " + "the wrong key. This fixes such certs if you have the correct key, " + "and can can optionally drop any certs that you don't have the " + "correct key for. This should only be needed if you had such certs " + "in your db when upgrading from 0.44 or earlier, or if you loaded " + "such certs with 'mtn read'."), + options::opts::drop_bad_certs) +{ + E(args.size() == 0, origin::user, + F("no arguments needed")); + + database db(app); + db.fix_bad_certs(app.opts.drop_bad_certs); +} + CMD(db_dump, "dump", "", CMD_REF(db), "", N_("Dumps the contents of the database"), N_("Generates a list of SQL instructions that represent the whole " ============================================================ --- database.cc 531d8e9f50ca3321e36abbd8d03797ea55b15c27 +++ database.cc 6b4b27d8814b113925c95ce373fa8931d38903eb @@ -50,6 +50,7 @@ #include "sanity.hh" #include "migration.hh" #include "transforms.hh" +#include "ui.hh" // tickers #include "vocab.hh" #include "vocab_cast.hh" #include "xdelta.hh" @@ -1219,6 +1220,80 @@ void } void +database::fix_bad_certs(bool drop_not_fixable) +{ + vector all_keys; + get_key_ids(all_keys); + + P(F("loading certs")); + vector > all_certs; + { + results res; + query q("SELECT revision_id, name, value, keypair_id, signature, hash FROM revision_certs"); + imp->fetch(res, 6, any_rows, q); + imp->results_to_certs(res, all_certs); + } + + P(F("checking")); + + ticker checked(_("checked"), "c", 25); + ticker bad(_("bad"), "b", 1); + ticker fixed(_("fixed"), "f", 1); + shared_ptr dropped; + if (drop_not_fixable) + dropped.reset(new ticker(_("dropped"), "d", 1)); + checked.set_total(all_certs.size()); + + for (vector >::const_iterator cert_iter = all_certs.begin(); + cert_iter != all_certs.end(); ++cert_iter) + { + cert const & c(cert_iter->second); + id const & certid(cert_iter->first); + cert_status status = check_cert(c); + ++checked; + if (status == cert_bad) + { + ++bad; + bool fixed = false; + string signable; + c.signable_text(signable); + for (vector::const_iterator key_iter = all_keys.begin(); + key_iter != all_keys.end(); ++key_iter) + { + key_id const & keyid(*key_iter); + if (check_signature(keyid, signable, c.sig) == cert_ok) + { + imp->execute(query("UPDATE revision_certs SET keypair_id = ? WHERE hash = ?") + % blob(keyid.inner()()) % blob(certid())); + ++fixed; + fixed = true; + break; + } + } + if (!fixed) + { + if (drop_not_fixable) + { + imp->execute(query("DELETE FROM revision_certs WHERE hash = ?") + % blob(certid())); + ++(*dropped); + } + } + } + } + if (drop_not_fixable) + { + P(F("checked %d certs, found %d bad, fixed %d, dropped %d") + % checked.ticks % bad.ticks % fixed.ticks % dropped->ticks); + } + else + { + P(F("checked %d certs, found %d bad, fixed %d") + % checked.ticks % bad.ticks % fixed.ticks); + } +} + +void database::ensure_open() { imp->sql(); ============================================================ --- database.hh 3a3eb474823b087fda8af2813e8f503b53a8c76e +++ database.hh a006d634bcd15da827bc19e732eb2b993b122ca6 @@ -393,6 +393,7 @@ public: void version(std::ostream &); void migrate(key_store &, migration_status &); void test_migration_step(key_store &, std::string const &); + void fix_bad_certs(bool drop_not_fixable); // for kill_rev_locally: void delete_existing_rev_and_certs(revision_id const & rid); // for kill_branch_certs_locally: ============================================================ --- options_list.hh 374f03bbb24468a2dfb5a51e3d3f2eaa1a78b1f1 +++ options_list.hh 820a2e9dfb65c7771b047f333f9e26d067b4ee97 @@ -336,6 +336,14 @@ OPT(dryrun, "dry-run", bool, false, } #endif +OPT(drop_bad_certs, "drop-bad-certs", bool, false, + gettext_noop("drop certs signed by keys we don't know about")) +#ifdef option_bodies +{ + drop_bad_certs = true; +} +#endif + OPTION(globals, dump, true, "dump", gettext_noop("file to dump debugging log to, on failure")) #ifdef option_bodies