gpg: Remove tofu database format "split".
authorWerner Koch <wk@gnupg.org>
Fri, 5 Aug 2016 12:40:36 +0000 (14:40 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 10 Aug 2016 14:55:04 +0000 (16:55 +0200)
* g10/options.h (struct opt): Remove field tofu_db_format.
* g10/gpg.h (server_control_s): Add fields tofu.batch_update_ref and
tofu.batch_update_started.
* g10/gpg.c (parse_tofu_db_format): Remove.
(main): Make option --tofu-db-format obsolete.
* g10/tofu.c: Major rework.  Remove the pretty complicated and slower
split format and with that all the caching.  Use the dbs struct
directly.  Move global vars for batch update into CTRL.  Change
calling conventions of some function to take CTRL or DBS pointers
instead of  the former low-level database pointer.
--

The split database format might have been nice for use with Unison but
it bypasses the concept of a relational database by doing parts of
this itself and also risking deadlocks.  Working with the Tofu
database for debugging or experiments is also not possible with parts
of the database logic implemented in gpg.

The Tofu support is quite new and we can assume that it is not in real
use now.  Thus we better remove that now so that we do not need to
maintain it for all future.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/DETAILS
doc/gpg.texi
g10/gpg.c
g10/gpg.h
g10/gpgv.c
g10/keylist.c
g10/options.h
g10/test-stubs.c
g10/tofu.c
g10/tofu.h
tests/openpgp/tofu.scm

index 0139fdb..794026b 100644 (file)
@@ -1144,6 +1144,55 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
               stored in the version info record.
 
 
+* Database scheme for the TOFU info
+
+#+begin_src sql
+--
+-- The VERSION table holds the version of our TOFU data structures.
+--
+CREATE TABLE version (
+  version integer -- As of now this is always 1
+);
+
+--
+-- The BINDINGS table associates mail addresses with keys.
+--
+CREATE TABLE bindings (
+  oid integer primary key autoincrement,
+  fingerprint text, -- The key's fingerprint in hex
+  email text,       -- The normalized mail address destilled from user_id
+  user_id text,     -- The unmodified user id
+  time integer,     -- The time this binding was first observed.
+  policy boolean check
+       (policy in (1, 2, 3, 4, 5)), -- The trust policy with the values:
+                                    --   1 := Auto
+                                    --   2 := Good
+                                    --   3 := Unknown
+                                    --   4 := Bad
+                                    --   5 := Ask
+  conflict string,  -- NULL or a hex formatted fingerprint.
+  unique (fingerprint, email)
+);
+
+CREATE INDEX bindings_fingerprint_email on bindings (fingerprint, email);
+CREATE INDEX bindings_email on bindings (email);
+
+--
+-- The SIGNATURES table records all data signatures we verified
+--
+CREATE TABLE signatures (
+  binding integer not null, -- Link to bindings table,
+                            -- references bindings.oid.
+  sig_digest text,          -- The digest of the signed message.
+  origin text,              -- String describing who initially fed
+                            -- the signature to gpg (e.g. "email:claws").
+  sig_time integer,         -- Timestamp from the signature.
+  time integer,             -- Time this record was created.
+  primary key (binding, sig_digest, origin)
+);
+#+end_src
+
+
 * GNU extensions to the S2K algorithm
 
   1 octet  - S2K Usage: either 254 or 255.
@@ -1169,6 +1218,9 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 
 * Keyserver helper message format
 
+  *This information is obsolete*
+  (Keyserver helpers have been replaced by dirmngr)
+
   The keyserver may be contacted by a Unix Domain socket or via TCP.
 
   The format of a request is:
index ffbc269..944734b 100644 (file)
@@ -1840,25 +1840,6 @@ key signer (defaults to 3)
 The default TOFU policy (defaults to @code{auto}).  For more
 information about the meaning of this option, @xref{trust-model-tofu}.
 
-@item --tofu-db-format @code{auto|split|flat}
-@opindex tofu-default-policy
-The format for the TOFU DB.
-
-The split file format splits the data across many DBs under the
-@code{tofu.d} directory (one per email address and one per key).  This
-makes it easier to automatically synchronize the data using a tool
-such as Unison (@url{https://www.cis.upenn.edu/~bcpierce/unison/}),
-since the individual files change rarely.
-
-The flat file format keeps all of the data in the single file
-@code{tofu.db}.  This format results in better performance.
-
-If set to auto (which is the default), GnuPG will first check for the
-existence of @code{tofu.d} and @code{tofu.db}.  If one of these
-exists, the corresponding format is used.  If neither or both of these
-exist, then GnuPG defaults to the @code{split} format.  In the latter
-case, a warning is emitted.
-
 @item --max-cert-depth @code{n}
 @opindex max-cert-depth
 Maximum depth of a certification chain (default is 5).
index 91f3472..adc32f0 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -709,7 +709,6 @@ static ARGPARSE_OPTS opts[] = {
 #endif
   ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
   ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
-  ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
   ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
   ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"),
@@ -851,6 +850,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (opcscDriver, "pcsc-driver", "@"),
   ARGPARSE_s_n (oDisableCCID, "disable-ccid", "@"),
   ARGPARSE_s_n (oHonorHttpProxy, "honor-http-proxy", "@"),
+  ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
 
   /* Dummy options.  */
   ARGPARSE_s_n (oNoop, "sk-comments", "@"),
@@ -2020,32 +2020,6 @@ parse_tofu_policy (const char *policystr)
   g10_exit (1);
 }
 
-static int
-parse_tofu_db_format (const char *db_format)
-{
-#ifdef USE_TOFU
-  if (ascii_strcasecmp (db_format, "auto") == 0)
-    return TOFU_DB_AUTO;
-  else if (ascii_strcasecmp (db_format, "split") == 0)
-    return TOFU_DB_SPLIT;
-  else if (ascii_strcasecmp (db_format, "flat") == 0)
-    return TOFU_DB_FLAT;
-  else if (ascii_strcasecmp (db_format, "help") == 0)
-    {
-      log_info ("available TOFU DB fomats: auto, split, flat\n");
-      g10_exit (1);
-    }
-  else
-#endif /*USE_TOFU*/
-    {
-      log_error (_("unknown TOFU DB format '%s'\n"), db_format);
-      if (!opt.quiet)
-        log_info (_("(use \"help\" to list choices)\n"));
-      g10_exit (1);
-    }
-}
-
-
 /* This function called to initialized a new control object.  It is
    assumed that this object has been zeroed out before calling this
    function. */
@@ -2252,7 +2226,6 @@ main (int argc, char **argv)
     opt.trust_model = TM_AUTO;
 #endif
     opt.tofu_default_policy = TOFU_POLICY_AUTO;
-    opt.tofu_db_format = TOFU_DB_AUTO;
     opt.mangle_dos_filenames = 0;
     opt.min_cert_level = 2;
     set_screen_dimensions ();
@@ -2692,7 +2665,7 @@ main (int argc, char **argv)
            opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
            break;
          case oTOFUDBFormat:
-           opt.tofu_db_format = parse_tofu_db_format (pargs.r.ret_str);
+           obsolete_option (configname, configlineno, "tofu-db-format");
            break;
 
          case oForceOwnertrust:
index c0f0a2d..1aaff2f 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -82,6 +82,8 @@ struct server_control_s
   /* Local data for tofu.c  */
   struct {
     tofu_dbs_t dbs;
+    int    batch_update_ref;
+    time_t batch_update_started;
   } tofu;
 
 };
index 729fcf8..fd1090e 100644 (file)
@@ -680,11 +680,13 @@ tofu_policy_str (enum tofu_policy policy)
 }
 
 void
-tofu_begin_batch_update (void)
+tofu_begin_batch_update (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
 
 void
-tofu_end_batch_update (void)
+tofu_end_batch_update (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
index 60b8f23..59344b2 100644 (file)
@@ -134,7 +134,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
   check_trustdb_stale (ctrl);
 
 #ifdef USE_TOFU
-  tofu_begin_batch_update ();
+  tofu_begin_batch_update (ctrl);
 #endif
 
   if (locate_mode)
@@ -145,7 +145,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
     list_one (ctrl, list, 0, opt.with_secret);
 
 #ifdef USE_TOFU
-  tofu_end_batch_update ();
+  tofu_end_batch_update (ctrl);
 #endif
 }
 
index ccd8acb..d1c3634 100644 (file)
@@ -116,17 +116,13 @@ struct
   int skip_verify;
   int skip_hidden_recipients;
 
-  /* TM_CLASSIC must be zero to accommodate trustdbs generated before
+  /* TM_CLASSIC must be zero to accommodate trustdbsg generated before
      we started storing the trust model inside the trustdb. */
   enum
     {
       TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2,
       TM_ALWAYS, TM_DIRECT, TM_AUTO, TM_TOFU, TM_TOFU_PGP
     } trust_model;
-  enum
-    {
-      TOFU_DB_AUTO=0, TOFU_DB_SPLIT, TOFU_DB_FLAT
-    } tofu_db_format;
   enum tofu_policy tofu_default_policy;
   int force_ownertrust;
   enum
index 6cf43a3..c5f2f79 100644 (file)
@@ -493,11 +493,13 @@ tofu_policy_str (enum tofu_policy policy)
 }
 
 void
-tofu_begin_batch_update (void)
+tofu_begin_batch_update (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
 
 void
-tofu_end_batch_update (void)
+tofu_end_batch_update (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
index a2732ff..ef14e85 100644 (file)
 #define FULL_TRUST_THRESHOLD  100
 
 
-#define DEBUG_TOFU_CACHE 0
-#if DEBUG_TOFU_CACHE
-static int prepares_saved;
-static int queries;
-#endif
-
-/* The TOFU data can be saved in two different formats: either in a
-   single combined database (opt.tofu_db_format == TOFU_DB_FLAT) or in
-   a split file format (opt.tofu_db_format == TOFU_DB_SPLIT).  In the
-   split format, there is one database per normalized email address
-   (DB_EMAIL) and one per key (DB_KEY).  */
-enum db_type
-  {
-    DB_COMBINED,
-    DB_EMAIL,
-    DB_KEY
-  };
-
-/* A list of open DBs.
-
-   In the flat format, this consists of a single element with the type
-   DB_COMBINED and whose name is the empty string.
-
-   In the split format, the first element is a dummy element (DB is
-   NULL) whose type is DB_COMBINED and whose name is the empty string.
-   Any following elements describe either DB_EMAIL or DB_KEY DBs.  In
-   theis case, NAME is either the normalized email address or the
-   fingerprint.
+/* An struct with data pertaining to the tofu DB.
 
    To initialize this data structure, call opendbs().  Cleanup is done
    when the CTRL object is released.  To get a handle to a database,
    use the getdb() function.  This will either return an existing
    handle or open a new DB connection, as appropriate.  */
-struct db
+struct tofu_dbs_s
 {
-  struct db *next;
-  struct db **prevp;
-
-  enum db_type type;
-
   sqlite3 *db;
 
   struct
@@ -116,34 +84,9 @@ struct db
     sqlite3_stmt *register_insert;
   } s;
 
-#if DEBUG_TOFU_CACHE
-  int hits;
-#endif
-
   int batch_update;
-
-  /* If TYPE is DB_COMBINED, this is "".  Otherwise, it is either the
-     fingerprint (type == DB_KEY) or the normalized email address
-     (type == DB_EMAIL).  */
-  char name[1];
 };
 
-static struct db *db_cache;
-static int db_cache_count;
-#define DB_CACHE_ENTRIES 16
-
-static void tofu_cache_dump (struct db *db) GPGRT_ATTR_USED;
-
-static void
-tofu_cache_dump (struct db *db)
-{
-  log_info ("Connection %p:\n", db);
-  for (; db; db = db->next)
-    log_info ("  %s: %sbatch mode\n", db->name, db->batch_update ? "" : "NOT ");
-  log_info ("Cache:\n");
-  for (db = db_cache; db; db = db->next)
-    log_info ("  %s: %sbatch mode\n", db->name, db->batch_update ? "" : "NOT ");
-}
 
 #define STRINGIFY(s) STRINGIFY2(s)
 #define STRINGIFY2(s) #s
@@ -167,8 +110,11 @@ tofu_cache_dump (struct db *db)
 #  define TIME_AGO_UNIT_LARGE (30 * 24 * 60 * 60)
 #endif
 
-\f
+/* Local prototypes.  */
+static gpg_error_t end_transaction (ctrl_t ctrl, int only_batch);
 
+
+\f
 const char *
 tofu_policy_str (enum tofu_policy policy)
 {
@@ -213,83 +159,63 @@ tofu_policy_to_trust_level (enum tofu_policy policy)
       return 0;
     }
 }
-\f
-static int batch_update;
-static time_t batch_update_started;
 
-static gpg_error_t end_transaction (struct db *db, int only_batch);
 
+\f
 /* Start a transaction on DB.  */
 static gpg_error_t
-begin_transaction (struct db *db, int only_batch)
+begin_transaction (ctrl_t ctrl, int only_batch)
 {
+  tofu_dbs_t dbs = ctrl->tofu.dbs;
   int rc;
   char *err = NULL;
 
-  if (batch_update && batch_update_started != gnupg_get_time ())
-    /* We've been in batch update mode for a while (on average, more
-       than 500 ms).  To prevent starving other gpg processes, we drop
-       and retake the batch lock.
+  log_assert (dbs);
 
-       Note: if we wanted higher resolution, we could use
-       npth_clock_gettime.  */
+  if (ctrl->tofu.batch_update_ref
+      && ctrl->tofu.batch_update_started != gnupg_get_time ())
     {
-      struct db *t;
-
-      for (t = db_cache; t; t = t->next)
-        if (t->batch_update)
-          end_transaction (t, 1);
-      for (t = db; t; t = t->next)
-        if (t->batch_update)
-          end_transaction (t, 1);
+      /* We've been in batch update mode for a while (on average, more
+       * than 500 ms).  To prevent starving other gpg processes, we
+       * drop and retake the batch lock.
+       *
+       * Note: if we wanted higher resolution, we could use
+       * npth_clock_gettime.  */
+      if (dbs->batch_update)
+        end_transaction (ctrl, 1);
 
-      batch_update_started = gnupg_get_time ();
+      ctrl->tofu.batch_update_started = gnupg_get_time ();
 
       /* Yield to allow another process a chance to run.  */
       gpgrt_yield ();
     }
 
-  /* XXX: In split mode, this can end in deadlock.
-
-     Consider: we have two gpg processes running simultaneously and
-     they each want to lock DB A and B, but in different orders.  This
-     will be automatically resolved by causing one of them to return
-     EBUSY and aborting.
-
-     A more intelligent approach would be to commit and retake the
-     batch transaction.  This requires a list of all DBs that are
-     currently in batch mode.  */
-
-  if (batch_update && ! db->batch_update)
+  if (ctrl->tofu.batch_update_ref && !dbs->batch_update)
     {
-      rc = gpgsql_stepx (db->db, &db->s.savepoint_batch,
+      rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch,
                           NULL, NULL, &err,
                           "savepoint batch;", SQLITE_ARG_END);
       if (rc)
         {
           log_error (_("error beginning transaction on TOFU database: %s\n"),
                      err);
-          print_further_info ("batch, database '%s'",
-                              *db->name ? db->name : "[combined]");
           sqlite3_free (err);
           return gpg_error (GPG_ERR_GENERAL);
         }
 
-      db->batch_update = 1;
+      dbs->batch_update = 1;
     }
 
   if (only_batch)
     return 0;
 
-  rc = gpgsql_stepx (db->db, &db->s.savepoint_inner,
+  rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner,
                       NULL, NULL, &err,
                       "savepoint inner;", SQLITE_ARG_END);
   if (rc)
     {
       log_error (_("error beginning transaction on TOFU database: %s\n"),
                  err);
-      print_further_info ("inner, database '%s'",
-                          *db->name ? db->name : "[combined]");
       sqlite3_free (err);
       return gpg_error (GPG_ERR_GENERAL);
     }
@@ -297,34 +223,34 @@ begin_transaction (struct db *db, int only_batch)
   return 0;
 }
 
+
 /* Commit a transaction.  If ONLY_BATCH is 1, then this only ends the
  batch transaction if we have left batch mode.  If ONLY_BATCH is 2,
  this ends any open batch transaction even if we are still in batch
  mode.  */
* batch transaction if we have left batch mode.  If ONLY_BATCH is 2,
* this ends any open batch transaction even if we are still in batch
* mode.  */
 static gpg_error_t
-end_transaction (struct db *db, int only_batch)
+end_transaction (ctrl_t ctrl, int only_batch)
 {
+  tofu_dbs_t dbs = ctrl->tofu.dbs;
   int rc;
   char *err = NULL;
 
-  if (!db)
+  if (!dbs)
     return 0;  /* Shortcut to allow for easier cleanup code.  */
 
-  if ((! batch_update || only_batch == 2) && db->batch_update)
-    /* The batch transaction is still in open, but we left batch
-       mode.  */
+  if ((!ctrl->tofu.batch_update_ref || only_batch == 2) && dbs->batch_update)
     {
-      db->batch_update = 0;
+      /* The batch transaction is still in open, but we left batch
+       * mode.  */
+      dbs->batch_update = 0;
 
-      rc = gpgsql_stepx (db->db, &db->s.savepoint_batch_commit,
+      rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch_commit,
                           NULL, NULL, &err,
                           "release batch;", SQLITE_ARG_END);
       if (rc)
         {
           log_error (_("error committing transaction on TOFU database: %s\n"),
                      err);
-          print_further_info ("batch, database '%s'",
-                              *db->name ? db->name : "[combined]");
           sqlite3_free (err);
           return gpg_error (GPG_ERR_GENERAL);
         }
@@ -337,15 +263,13 @@ end_transaction (struct db *db, int only_batch)
   if (only_batch)
     return 0;
 
-  rc = gpgsql_stepx (db->db, &db->s.savepoint_inner_commit,
+  rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner_commit,
                       NULL, NULL, &err,
                       "release inner;", SQLITE_ARG_END);
   if (rc)
     {
       log_error (_("error committing transaction on TOFU database: %s\n"),
                  err);
-      print_further_info ("inner, database '%s'",
-                          *db->name ? db->name : "[combined]");
       sqlite3_free (err);
       return gpg_error (GPG_ERR_GENERAL);
     }
@@ -353,29 +277,33 @@ end_transaction (struct db *db, int only_batch)
   return 0;
 }
 
+
 static gpg_error_t
-rollback_transaction (struct db *db)
+rollback_transaction (ctrl_t ctrl)
 {
+  tofu_dbs_t dbs = ctrl->tofu.dbs;
   int rc;
   char *err = NULL;
 
-  if (!db)
+  if (!dbs)
     return 0;  /* Shortcut to allow for easier cleanup code.  */
 
-  if (db->batch_update)
-    /* Just undo the most recent update; don't revert any progress
-       made by the batch transaction.  */
-    rc = sqlite3_exec (db->db, "rollback to inner;", NULL, NULL, &err);
+  if (dbs->batch_update)
+    {
+      /* Just undo the most recent update; don't revert any progress
+         made by the batch transaction.  */
+      rc = sqlite3_exec (dbs->db, "rollback to inner;", NULL, NULL, &err);
+    }
   else
-    /* Rollback the whole she-bang.  */
-    rc = sqlite3_exec (db->db, "rollback;", NULL, NULL, &err);
+    {
+      /* Rollback the whole she-bang.  */
+      rc = sqlite3_exec (dbs->db, "rollback;", NULL, NULL, &err);
+    }
 
   if (rc)
     {
       log_error (_("error rolling back transaction on TOFU database: %s\n"),
                  err);
-      print_further_info ("inner, database '%s'",
-                          *db->name ? db->name : "[combined]");
       sqlite3_free (err);
       return gpg_error (GPG_ERR_GENERAL);
     }
@@ -384,27 +312,22 @@ rollback_transaction (struct db *db)
 }
 
 void
-tofu_begin_batch_update (void)
+tofu_begin_batch_update (ctrl_t ctrl)
 {
-  if (! batch_update)
-    batch_update_started = gnupg_get_time ();
+  if (!ctrl->tofu.batch_update_ref)
+    ctrl->tofu.batch_update_started = gnupg_get_time ();
 
-  batch_update ++;
+  ctrl->tofu.batch_update_ref ++;
 }
 
 void
-tofu_end_batch_update (void)
+tofu_end_batch_update (ctrl_t ctrl)
 {
-  log_assert (batch_update > 0);
-  batch_update --;
+  log_assert (ctrl->tofu.batch_update_ref > 0);
+  ctrl->tofu.batch_update_ref --;
 
-  if (batch_update == 0)
-    {
-      struct db *db;
-
-      for (db = db_cache; db; db = db->next)
-        end_transaction (db, 1);
-    }
+  if (!ctrl->tofu.batch_update_ref)
+    end_transaction (ctrl, 1);
 }
 
 
@@ -523,7 +446,7 @@ version_check_cb (void *cookie, int argc, char **argv, char **azColName)
 
    Return 0 if the database is okay and 1 otherwise.  */
 static int
-initdb (sqlite3 *db, enum db_type type)
+initdb (sqlite3 *db)
 {
   char *err = NULL;
   int rc;
@@ -639,8 +562,7 @@ initdb (sqlite3 *db, enum db_type type)
    *    the old binding's policy to ask if it was auto.  So that we
    *     know why this occurred, we also set conflict to 0xbaddecaf.
    */
-  if (type == DB_EMAIL || type == DB_COMBINED)
-    rc = gpgsql_exec_printf
+  rc = gpgsql_exec_printf
       (db, NULL, NULL, &err,
        "create table bindings\n"
        " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
@@ -653,20 +575,6 @@ initdb (sqlite3 *db, enum db_type type)
        "create index bindings_email on bindings (email);\n",
        TOFU_POLICY_AUTO, TOFU_POLICY_GOOD, TOFU_POLICY_UNKNOWN,
        TOFU_POLICY_BAD, TOFU_POLICY_ASK);
-  else
-    /* In the split DB case, the fingerprint DB only contains a subset
-       of the fields.  This reduces the amount of duplicated data.
-
-       Note: since the data is split on the email address, there is no
-       need to index the email column.  */
-    rc = gpgsql_exec_printf
-      (db, NULL, NULL, &err,
-       "create table bindings\n"
-       " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
-       "  fingerprint TEXT, email TEXT, user_id,\n"
-       "  unique (fingerprint, email));\n"
-       "create index bindings_fingerprint\n"
-       " on bindings (fingerprint);\n");
   if (rc)
     {
       log_error (_("error initializing TOFU database: %s\n"), err);
@@ -675,35 +583,32 @@ initdb (sqlite3 *db, enum db_type type)
       goto out;
     }
 
-  if (type != DB_KEY)
-    {
-      /* The signatures that we have observed.
-
-        BINDING refers to a record in the bindings table, which
-         describes the binding (i.e., this is a foreign key that
-         references bindings.oid).
-
-        SIG_DIGEST is the digest stored in the signature.
-
-        SIG_TIME is the timestamp stored in the signature.
-
-        ORIGIN is a free-form string that describes who fed this
-         signature to GnuPG (e.g., email:claws).
-
-        TIME is the time this signature was registered.  */
-      rc = sqlite3_exec (db,
+  /* The signatures that we have observed.
+   *
+   * BINDING refers to a record in the bindings table, which
+   * describes the binding (i.e., this is a foreign key that
+   * references bindings.oid).
+   *
+   * SIG_DIGEST is the digest stored in the signature.
+   *
+   * SIG_TIME is the timestamp stored in the signature.
+   *
+   * ORIGIN is a free-form string that describes who fed this
+   * signature to GnuPG (e.g., email:claws).
+   *
+   * TIME is the time this signature was registered.  */
+  rc = sqlite3_exec (db,
                         "create table signatures "
                         " (binding INTEGER NOT NULL, sig_digest TEXT,"
                         "  origin TEXT, sig_time INTEGER, time INTEGER,"
                         "  primary key (binding, sig_digest, origin));",
                         NULL, NULL, &err);
-      if (rc)
-       {
-          log_error (_("error initializing TOFU database: %s\n"), err);
-          print_further_info ("create signatures");
-         sqlite3_free (err);
-         goto out;
-       }
+  if (rc)
+    {
+      log_error (_("error initializing TOFU database: %s\n"), err);
+      print_further_info ("create signatures");
+      sqlite3_free (err);
+      goto out;
     }
 
  out:
@@ -732,408 +637,79 @@ initdb (sqlite3 *db, enum db_type type)
     }
 }
 
-/* Open and initialize a low-level TOFU database.  Returns NULL on
-   failure.  This function should not normally be directly called to
-   get a database handle.  Instead, use getdb().  */
-static sqlite3 *
-opendb (char *filename, enum db_type type)
+
+/* Create a new DB handle.  Returns NULL on error.  */
+/* FIXME: Change to return an error code for better reporting by the
+   caller.  */
+static tofu_dbs_t
+opendbs (ctrl_t ctrl)
 {
+  char *filename;
   sqlite3 *db;
-  int filename_free = 0;
   int rc;
 
-  if (opt.tofu_db_format == TOFU_DB_FLAT)
+  if (!ctrl->tofu.dbs)
     {
-      log_assert (! filename);
-      log_assert (type == DB_COMBINED);
-
       filename = make_filename (gnupg_homedir (), "tofu.db", NULL);
-      filename_free = 1;
-    }
-  else
-    log_assert (type == DB_EMAIL || type == DB_KEY);
-
-  log_assert (filename);
-
-  rc = sqlite3_open (filename, &db);
-  if (rc)
-    {
-      log_error (_("error opening TOFU database '%s': %s\n"),
-                 filename, sqlite3_errmsg (db));
-      /* Even if an error occurs, DB is guaranteed to be valid.  */
-      sqlite3_close (db);
-      db = NULL;
-    }
-
-  /* If a DB is locked wait up to 5 seconds for the lock to be cleared
-     before failing.  */
-  if (db)
-    sqlite3_busy_timeout (db, 5 * 1000);
-
-  if (filename_free)
-    xfree (filename);
-
-  if (db && initdb (db, type))
-    {
-      sqlite3_close (db);
-      db = NULL;
-    }
-
-  return db;
-}
-
-/* Definition of the Tofu dabase meta handle.  */
-struct tofu_dbs_s
-{
-  struct db *db;
-};
-
-static void
-unlink_db (struct db *db)
-{
-  *db->prevp = db->next;
-  if (db->next)
-    db->next->prevp = db->prevp;
-}
-
-static void
-link_db (struct db **head, struct db *db)
-{
-  db->next = *head;
-  if (db->next)
-    db->next->prevp = &db->next;
-  db->prevp = head;
-  *head = db;
-}
-
-/* Return a database handle.  <type, name> describes the required
-   database.  If there is a cached handle in DBS, that handle is
-   returned.  Otherwise, the database is opened and cached in DBS.
-
-   NAME is the name of the DB and may not be NULL.
 
-   TYPE must be either DB_MAIL or DB_KEY.  In the combined format, the
-   combined DB is always returned.  */
-static struct db *
-getdb (tofu_dbs_t dbs, const char *name, enum db_type type)
-{
-  struct db *t = NULL;
-  char *name_sanitized = NULL;
-  int count;
-  char *filename = NULL;
-  int need_link = 1;
-  sqlite3 *sqlitedb = NULL;
-  gpg_error_t rc;
-
-  log_assert (dbs);
-  log_assert (name);
-  log_assert (type == DB_EMAIL || type == DB_KEY);
-
-  if (opt.tofu_db_format == TOFU_DB_FLAT)
-    /* When using the flat format, we only have a single DB, the
-       combined DB.  */
-    {
-      if (dbs->db)
+      rc = sqlite3_open (filename, &db);
+      if (rc)
         {
-          log_assert (dbs->db->type == DB_COMBINED);
-          log_assert (! dbs->db->next);
-          return dbs->db;
+          log_error (_("error opening TOFU database '%s': %s\n"),
+                     filename, sqlite3_errmsg (db));
+          /* Even if an error occurs, DB is guaranteed to be valid.  */
+          sqlite3_close (db);
+          db = NULL;
         }
+      xfree (filename);
 
-      type = DB_COMBINED;
-    }
-
-  if (type != DB_COMBINED)
-    /* Only allow alpha-numeric characters in the name.  */
-    {
-      int i;
+      /* If a DB is locked wait up to 5 seconds for the lock to be cleared
+         before failing.  */
+      if (db)
+        sqlite3_busy_timeout (db, 5 * 1000);
 
-      name_sanitized = xstrdup (name);
-      for (i = 0; name[i]; i ++)
+      if (db && initdb (db))
         {
-          char c = name_sanitized[i];
-          if (! (('a' <= c && c <= 'z')
-                 || ('A' <= c && c <= 'Z')
-                 || ('0' <= c && c <= '9')))
-            name_sanitized[i] = '_';
+          sqlite3_close (db);
+          db = NULL;
         }
-    }
-
-  /* See if the DB is cached.  */
-  for (t = dbs->db; t; t = t->next)
-    if (t->type == type
-        && (type == DB_COMBINED || strcmp (t->name, name_sanitized) == 0))
-      {
-        need_link = 0;
-        goto out;
-      }
-
-  for (t = db_cache, count = 0; t; t = t->next, count ++)
-    if (type == t->type
-        && (type == DB_COMBINED || strcmp (t->name, name_sanitized) == 0))
-      {
-        unlink_db (t);
-        db_cache_count --;
-        goto out;
-      }
-
-  log_assert (db_cache_count == count);
-
-  if (type == DB_COMBINED)
-    filename = NULL;
-  else
-    {
-      /* Open the DB.  The filename has the form:
-
-         tofu.d/TYPE/PREFIX/NAME.db
-
-         We use a short prefix to try to avoid having many files in a
-         single directory.  */
-      {
-        char *type_str = type == DB_EMAIL ? "email" : "key";
-        char prefix[3] = { name_sanitized[0], name_sanitized[1], 0 };
-        char *name_db;
-
-        /* Make the directory.  */
-        rc = gnupg_mkdir_p (gnupg_homedir (), "tofu.d", type_str, prefix, NULL);
-        if (rc)
-          {
-            name_db = xstrconcat (gnupg_homedir (), "tofu.d",
-                                  type_str, prefix, NULL);
-            log_error (_("can't create directory '%s': %s\n"),
-                       name_db, gpg_strerror (rc));
-            xfree (name_db);
-            goto out;
-          }
-
-        name_db = xstrconcat (name_sanitized, ".db", NULL);
-        filename = make_filename
-          (gnupg_homedir (), "tofu.d", type_str, prefix, name_db, NULL);
-        xfree (name_db);
-      }
-    }
-
-  sqlitedb = opendb (filename, type);
-  if (! sqlitedb)
-    goto out;
-
-  t = xmalloc_clear (sizeof (struct db)
-                     + (name_sanitized ? strlen (name_sanitized) : 0));
-  t->type = type;
-  t->db = sqlitedb;
-  if (name_sanitized)
-    strcpy (t->name, name_sanitized);
-
- out:
-  if (t && need_link)
-    link_db (&dbs->db, t);
-
-#if DEBUG_TOFU_CACHE
-  if (t)
-    t->hits ++;
-#endif
-
-  xfree (filename);
-  xfree (name_sanitized);
-  return t;
-}
-
-static void
-closedb (struct db *db)
-{
-  sqlite3_stmt **statements;
 
-  if (opt.tofu_db_format == TOFU_DB_FLAT)
-    /* If we are using the flat format, then there is only ever the
-       combined DB.  */
-    log_assert (! db->next);
-
-  if (db->type == DB_COMBINED)
-    {
-      log_assert (opt.tofu_db_format == TOFU_DB_FLAT);
-      log_assert (! db->name[0]);
+      if (db)
+        {
+          ctrl->tofu.dbs = xmalloc_clear (sizeof *ctrl->tofu.dbs);
+          ctrl->tofu.dbs->db = db;
+        }
     }
   else
-    {
-      log_assert (opt.tofu_db_format == TOFU_DB_SPLIT);
-      log_assert (db->type != DB_COMBINED);
-      log_assert (db->name[0]);
-    }
-
-  if (db->batch_update)
-    end_transaction (db, 2);
-
-  for (statements = (void *) &db->s;
-       (void *) statements < (void *) &(&db->s)[1];
-       statements ++)
-    sqlite3_finalize (*statements);
-
-  sqlite3_close (db->db);
-
-#if DEBUG_TOFU_CACHE
-  log_debug ("Freeing db.  Used %d times.\n", db->hits);
-#endif
-
-  xfree (db);
-}
-
-
-/* Create a new DB meta-handle.  Returns NULL on error.  */
-/* FIXME: Change to return an error code for better reporting by the
-   caller.  */
-static tofu_dbs_t
-opendbs (ctrl_t ctrl)
-{
-  if (ctrl->tofu.dbs)
-    return ctrl->tofu.dbs;
-
-  if (opt.tofu_db_format == TOFU_DB_AUTO)
-    {
-      char *filename = make_filename (gnupg_homedir (), "tofu.db", NULL);
-      struct stat s;
-      int have_tofu_db = 0;
-      int have_tofu_d = 0;
-
-      if (stat (filename, &s) == 0)
-       {
-         have_tofu_db = 1;
-         if (DBG_TRUST)
-           log_debug ("%s exists.\n", filename);
-       }
-      else
-       {
-         if (DBG_TRUST)
-           log_debug ("%s does not exist.\n", filename);
-       }
-
-      /* We now have tofu.d.  */
-      filename[strlen (filename) - 1] = '\0';
-      if (stat (filename, &s) == 0)
-       {
-         have_tofu_d = 1;
-         if (DBG_TRUST)
-           log_debug ("%s exists.\n", filename);
-       }
-      else
-       {
-         if (DBG_TRUST)
-           log_debug ("%s does not exist.\n", filename);
-       }
-
-      xfree (filename);
-
-      if (have_tofu_db && have_tofu_d)
-       {
-         log_info (_("Warning: Home directory contains both tofu.db"
-                      " and tofu.d.\n"));
-          log_info (_("Using split format for TOFU database\n"));
-         opt.tofu_db_format = TOFU_DB_SPLIT;
-       }
-      else if (have_tofu_db)
-       {
-         opt.tofu_db_format = TOFU_DB_FLAT;
-         if (DBG_TRUST)
-           log_debug ("Using flat format for TOFU database.\n");
-       }
-      else if (have_tofu_d)
-       {
-         opt.tofu_db_format = TOFU_DB_SPLIT;
-         if (DBG_TRUST)
-           log_debug ("Using split format for TOFU database.\n");
-       }
-      else
-       {
-         opt.tofu_db_format = TOFU_DB_FLAT;
-         if (DBG_TRUST)
-           log_debug ("Using flat format for TOFU database.\n");
-       }
-    }
+    log_assert (ctrl->tofu.dbs->db);
 
-  ctrl->tofu.dbs = xmalloc_clear (sizeof (struct tofu_dbs_s));
   return ctrl->tofu.dbs;
 }
 
 
-/* Release all of the resources associated with a DB meta-handle.  */
+/* Release all of the resources associated with the DB handle.  */
 void
 tofu_closedbs (ctrl_t ctrl)
 {
-  tofu_dbs_t dbs = ctrl->tofu.dbs;
+  tofu_dbs_t dbs;
+  sqlite3_stmt **statements;
 
+  dbs = ctrl->tofu.dbs;
   if (!dbs)
     return;  /* Not initialized.  */
 
-  if (dbs->db && dbs->db->type == DB_COMBINED)
-    {
-      log_assert (!dbs->db->next);
-      closedb (dbs->db);
-    }
-  else if (dbs->db)
-    {
-      struct db *old_head = db_cache;
-      struct db *db;
-      int count;
-
-      /* Find the last DB.  */
-      for (db = dbs->db, count = 1; db->next; db = db->next, count ++)
-        {
-          /* When we leave batch mode we leave batch mode on any
-             cached connections.  */
-          if (! batch_update)
-            log_assert (! db->batch_update);
-        }
-      if (! batch_update)
-        log_assert (! db->batch_update);
+  if (dbs->batch_update)
+    end_transaction (ctrl, 2);
 
-      /* Join the two lists.  */
-      db->next = db_cache;
-      if (db_cache)
-        db_cache->prevp = &db->next;
-
-      /* Update the (new) first element.  */
-      db_cache = dbs->db;
-      dbs->db->prevp = &db_cache;
-
-      db_cache_count += count;
-
-      /* Make sure that we don't have too many DBs on DB_CACHE.  If
-         so, free some.  */
-      if (db_cache_count > DB_CACHE_ENTRIES)
-        {
-          /* We need to find the (DB_CACHE_ENTRIES + 1)th entry.  It
-             is easy to skip the first COUNT entries since we still
-             have a handle on the old head.  */
-          int skip = DB_CACHE_ENTRIES - count;
-          if (skip < 0)
-            for (old_head = db_cache, skip = DB_CACHE_ENTRIES;
-                 skip > 0;
-                 old_head = old_head->next, skip--)
-              { /* Do nothing.  */ }
-          else
-            while (-- skip > 0)
-              old_head = old_head->next;
-
-          *old_head->prevp = NULL;
-
-          while (old_head)
-            {
-              db = old_head->next;
-              closedb (old_head);
-              old_head = db;
-              db_cache_count --;
-            }
-
-          log_assert (db_cache_count == DB_CACHE_ENTRIES);
-        }
-    }
+  /* Arghh, that is asurprising use of the struct.  */
+  for (statements = (void *) &dbs->s;
+       (void *) statements < (void *) &(&dbs->s)[1];
+       statements ++)
+    sqlite3_finalize (*statements);
 
-  xfree (ctrl->tofu.dbs);
+  sqlite3_close (dbs->db);
+  xfree (dbs);
   ctrl->tofu.dbs = NULL;
-
-#if DEBUG_TOFU_CACHE
-  log_debug ("Queries: %d (prepares saved: %d)\n",
-             queries, prepares_saved);
-#endif
 }
 
 
@@ -1171,7 +747,6 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
                const char *user_id, enum tofu_policy policy, int show_old)
 {
   char *fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
-  struct db *db_email = NULL, *db_key = NULL;
   gpg_error_t rc;
   char *err = NULL;
   /* policy_old needs to be a long and not an enum tofu_policy,
@@ -1186,44 +761,14 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
         || policy == TOFU_POLICY_ASK))
     log_bug ("%s: Bad value for policy (%d)!\n", __func__, policy);
 
-  db_email = getdb (dbs, email, DB_EMAIL);
-  if (! db_email)
-    {
-      rc = gpg_error (GPG_ERR_GENERAL);
-      goto leave;
-    }
-
-  if (opt.tofu_db_format == TOFU_DB_SPLIT)
-    /* In the split format, we need to update two DBs.  To keep them
-       consistent, we start a transaction on each.  Note: this is the
-       only place where we start two transaction and we always start
-       transaction on the DB_KEY DB first, thus deadlock is not
-       possible.  */
-    /* We only need a transaction for the split format.  */
-    {
-      db_key = getdb (dbs, fingerprint, DB_KEY);
-      if (! db_key)
-        {
-          rc = gpg_error (GPG_ERR_GENERAL);
-          goto leave;
-        }
-
-      rc = begin_transaction (db_email, 0);
-      if (rc)
-        goto leave;
-
-      rc = begin_transaction (db_key, 0);
-      if (rc)
-        goto out_revert_one;
-    }
 
   if (show_old)
-    /* Get the old policy.  Since this is just for informational
-       purposes, there is no need to start a transaction or to die if
-       there is a failure.  */
     {
+      /* Get the old policy.  Since this is just for informational
+       * purposes, there is no need to start a transaction or to die
+       * if there is a failure.  */
       rc = gpgsql_stepx
-       (db_email->db, &db_email->s.record_binding_get_old_policy,
+       (dbs->db, &dbs->s.record_binding_get_old_policy,
          get_single_long_cb2, &policy_old, &err,
         "select policy from bindings where fingerprint = ? and email = ?",
         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
@@ -1252,17 +797,20 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
     }
 
   if (policy_old == policy)
-    /* Nothing to do.  */
-    goto out;
+    {
+      rc = 0;
+      goto leave; /* Nothing to do.  */
+    }
 
   if (opt.dry_run)
     {
       log_info ("TOFU database update skipped due to --dry-run\n");
-      goto out;
+      rc = 0;
+      goto leave;
     }
 
   rc = gpgsql_stepx
-    (db_email->db, &db_email->s.record_binding_update, NULL, NULL, &err,
+    (dbs->db, &dbs->s.record_binding_update, NULL, NULL, &err,
      "insert or replace into bindings\n"
      " (oid, fingerprint, email, user_id, time, policy)\n"
      " values (\n"
@@ -1281,64 +829,11 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
       print_further_info (" insert bindings <%s, %s> = %s",
                           fingerprint, email, tofu_policy_str (policy));
       sqlite3_free (err);
-      goto out;
-    }
-
-  if (db_key)
-    /* We also need to update the key DB.  */
-    {
-      log_assert (opt.tofu_db_format == TOFU_DB_SPLIT);
-
-      rc = gpgsql_stepx
-       (db_key->db, &db_key->s.record_binding_update2, NULL, NULL, &err,
-        "insert or replace into bindings\n"
-        " (oid, fingerprint, email, user_id)\n"
-        " values (\n"
-        /* If we don't explicitly reuse the OID, then SQLite will
-           reallocate a new one.  We just need to search for the OID
-           based on the fingerprint and email since they are unique.  */
-        "  (select oid from bindings where fingerprint = ? and email = ?),\n"
-        "  ?, ?, ?);",
-        SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
-         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
-         SQLITE_ARG_STRING, user_id, SQLITE_ARG_END);
-      if (rc)
-       {
-         log_error (_("error updating TOFU database: %s\n"), err);
-          print_further_info ("insert bindings <%s, %s>",
-                              fingerprint, email);
-         sqlite3_free (err);
-         goto out;
-       }
-    }
-  else
-    log_assert (opt.tofu_db_format == TOFU_DB_FLAT);
-
- out:
-  if (opt.tofu_db_format == TOFU_DB_SPLIT)
-    /* We only need a transaction for the split format.  */
-    {
-      gpg_error_t rc2;
-
-      if (rc)
-        rc2 = rollback_transaction (db_key);
-      else
-        rc2 = end_transaction (db_key, 0);
-      if (rc2)
-        sqlite3_free (err);
-
-    out_revert_one:
-      if (rc)
-        rc2 = rollback_transaction (db_email);
-      else
-        rc2 = end_transaction (db_email, 0);
-      if (rc2)
-        sqlite3_free (err);
+      goto leave;
     }
 
  leave:
   xfree (fingerprint_pp);
-
   return rc;
 }
 
@@ -1507,22 +1002,17 @@ static enum tofu_policy
 get_policy (tofu_dbs_t dbs, const char *fingerprint, const char *email,
            char **conflict)
 {
-  struct db *db;
   int rc;
   char *err = NULL;
   strlist_t strlist = NULL;
   enum tofu_policy policy = _tofu_GET_POLICY_ERROR;
   long along;
 
-  db = getdb (dbs, email, DB_EMAIL);
-  if (! db)
-    return _tofu_GET_POLICY_ERROR;
-
   /* Check if the <FINGERPRINT, EMAIL> binding is known
      (TOFU_POLICY_NONE cannot appear in the DB.  Thus, if POLICY is
      still TOFU_POLICY_NONE after executing the query, then the
      result set was empty.)  */
-  rc = gpgsql_stepx (db->db, &db->s.get_policy_select_policy_and_conflict,
+  rc = gpgsql_stepx (dbs->db, &dbs->s.get_policy_select_policy_and_conflict,
                       strings_collect_cb2, &strlist, &err,
                       "select policy, conflict from bindings\n"
                       " where fingerprint = ? and email = ?",
@@ -1681,7 +1171,6 @@ format_conflict_msg_part1 (int policy, const char *conflict,
  */
 static void
 ask_about_binding (tofu_dbs_t dbs,
-                   struct db *db,
                    enum tofu_policy *policy,
                    int *trust_level,
                    int bindings_with_this_email_count,
@@ -1699,7 +1188,6 @@ ask_about_binding (tofu_dbs_t dbs,
   struct signature_stats *stats_iter = NULL;
   char *prompt;
   char *choices;
-  struct db *db_key;
 
   fp = es_fopenmem (0, "rw,samethread");
   if (!fp)
@@ -1716,30 +1204,16 @@ ask_about_binding (tofu_dbs_t dbs,
 
   /* Find other user ids associated with this key and whether the
    * bindings are marked as good or bad.  */
-  if (opt.tofu_db_format == TOFU_DB_SPLIT)
-    {
-      /* In the split format, we need to search in the fingerprint DB
-       * for all the emails associated with this key, not the email DB.  */
-      db_key = getdb (dbs, fingerprint, DB_KEY);
-    }
-  else
-    db_key = db;
-
-  if (db_key)
+  rc = gpgsql_stepx
+    (dbs->db, &dbs->s.get_trust_gather_other_user_ids,
+     strings_collect_cb2, &other_user_ids, &sqerr,
+     "select user_id, policy from bindings where fingerprint = ?;",
+     SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_END);
+  if (rc)
     {
-      rc = gpgsql_stepx
-        (db_key->db, &db_key->s.get_trust_gather_other_user_ids,
-         strings_collect_cb2, &other_user_ids, &sqerr,
-         opt.tofu_db_format == TOFU_DB_SPLIT
-         ? "select user_id, email from bindings where fingerprint = ?;"
-         : "select user_id, policy from bindings where fingerprint = ?;",
-         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_END);
-      if (rc)
-        {
-          log_error (_("error gathering other user IDs: %s\n"), sqerr);
-          sqlite3_free (sqerr);
-          sqerr = NULL;
-        }
+      log_error (_("error gathering other user IDs: %s\n"), sqerr);
+      sqlite3_free (sqerr);
+      sqerr = NULL;
     }
 
   if (other_user_ids)
@@ -1759,10 +1233,7 @@ ask_about_binding (tofu_dbs_t dbs,
           strlist_iter = strlist_iter->next;
           other_thing = strlist_iter->d;
 
-          if (opt.tofu_db_format == TOFU_DB_SPLIT)
-            other_policy = get_policy (dbs, fingerprint, other_thing, NULL);
-          else
-            other_policy = atoi (other_thing);
+          other_policy = atoi (other_thing);
 
           es_fprintf (fp, "  %s (", other_user_id);
           es_fprintf (fp, _("policy: %s"), tofu_policy_str (other_policy));
@@ -1778,7 +1249,7 @@ ask_about_binding (tofu_dbs_t dbs,
      embedded in the signature (column 'sig_time') or the time that
      we first verified the signature (column 'time').  */
   rc = gpgsql_stepx
-    (db->db, &db->s.get_trust_gather_other_keys,
+    (dbs->db, &dbs->s.get_trust_gather_other_keys,
      signature_stats_collect_cb, &stats, &sqerr,
      "select fingerprint, policy, time_ago, count(*)\n"
      " from (select bindings.*,\n"
@@ -2028,7 +1499,6 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
            const char *fingerprint, const char *email,
           const char *user_id, int may_ask)
 {
-  struct db *db;
   enum tofu_policy policy;
   char *conflict = NULL;
   int rc;
@@ -2051,10 +1521,6 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
               && _tofu_GET_TRUST_ERROR != TRUST_FULLY
               && _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
 
-  db = getdb (dbs, email, DB_EMAIL);
-  if (! db)
-    return _tofu_GET_TRUST_ERROR;
-
   policy = get_policy (dbs, fingerprint, email, &conflict);
   if (policy == TOFU_POLICY_AUTO || policy == TOFU_POLICY_NONE)
     { /* See if the key is ultimately trusted.  If so, we're done.  */
@@ -2149,7 +1615,7 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
    * also be returned.  Thus, if the result set is empty, then this is
    * a new binding.  */
   rc = gpgsql_stepx
-    (db->db, &db->s.get_trust_bindings_with_this_email,
+    (dbs->db, &dbs->s.get_trust_bindings_with_this_email,
      strings_collect_cb2, &bindings_with_this_email, &sqerr,
      "select distinct fingerprint from bindings where email = ?;",
      SQLITE_ARG_STRING, email, SQLITE_ARG_END);
@@ -2221,7 +1687,7 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
     }
 
   /* If we get here, we need to ask the user about the binding.  */
-  ask_about_binding (dbs, db,
+  ask_about_binding (dbs,
                      &policy,
                      &trust_level,
                      bindings_with_this_email_count,
@@ -2239,7 +1705,7 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
           /* If we weren't allowed to ask, also update this key as
              conflicting with itself.  */
           rc = gpgsql_exec_printf
-            (db->db, NULL, NULL, &sqerr,
+            (dbs->db, NULL, NULL, &sqerr,
              "update bindings set policy = %d, conflict = %Q"
              " where email = %Q"
              "  and (policy = %d or (policy = %d and fingerprint = %Q));",
@@ -2249,7 +1715,7 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
       else
         {
           rc = gpgsql_exec_printf
-            (db->db, NULL, NULL, &sqerr,
+            (dbs->db, NULL, NULL, &sqerr,
              "update bindings set policy = %d, conflict = %Q"
              " where email = %Q and fingerprint != %Q and policy = %d;",
              TOFU_POLICY_ASK, fingerprint, email, fingerprint,
@@ -2445,20 +1911,15 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
                 const char *email, const char *user_id,
                 const char *sig_exclude)
 {
-  struct db *db;
   char *fingerprint_pp;
   int rc;
   strlist_t strlist = NULL;
   char *err = NULL;
 
-  db = getdb (dbs, email, DB_EMAIL);
-  if (! db)
-    return;
-
   fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
 
   rc = gpgsql_exec_printf
-    (db->db, strings_collect_cb, &strlist, &err,
+    (dbs->db, strings_collect_cb, &strlist, &err,
      "select count (*), strftime('%%s','now') - min (signatures.time),\n"
      "  strftime('%%s','now') - max (signatures.time)\n"
      " from signatures\n"
@@ -2687,7 +2148,6 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
               time_t sig_time, const char *origin, int may_ask)
 {
   tofu_dbs_t dbs;
-  struct db *db;
   char *fingerprint = NULL;
   char *email = NULL;
   char *err = NULL;
@@ -2731,25 +2191,16 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
       goto die;
     }
 
-  /* Save the observed signature in the DB.  */
-  db = getdb (dbs, email, DB_EMAIL);
-  if (! db)
-    {
-      log_error (_("error opening TOFU database: %s\n"),
-                 gpg_strerror (GPG_ERR_GENERAL));
-      goto die;
-    }
-
   /* We do a query and then an insert.  Make sure they are atomic
      by wrapping them in a transaction.  */
-  rc = begin_transaction (db, 0);
+  rc = begin_transaction (ctrl, 0);
   if (rc)
     goto die;
 
   /* If we've already seen this signature before, then don't add
      it again.  */
   rc = gpgsql_stepx
-    (db->db, &db->s.register_already_seen,
+    (dbs->db, &dbs->s.register_already_seen,
      get_single_unsigned_long_cb2, &c, &err,
      "select count (*)\n"
      " from signatures left join bindings\n"
@@ -2799,7 +2250,7 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
       log_assert (c == 0);
 
       rc = gpgsql_stepx
-       (db->db, &db->s.register_insert, NULL, NULL, &err,
+       (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
         "insert into signatures\n"
         " (binding, sig_digest, origin, sig_time, time)\n"
         " values\n"
@@ -2821,9 +2272,9 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
   /* It only matters whether we abort or commit the transaction
      (so long as we do something) if we execute the insert.  */
   if (rc)
-    rc = rollback_transaction (db);
+    rc = rollback_transaction (ctrl);
   else
-    rc = end_transaction (db, 0);
+    rc = end_transaction (ctrl, 0);
   if (rc)
     {
       sqlite3_free (err);
index d3448b9..e3ec819 100644 (file)
@@ -112,8 +112,8 @@ gpg_error_t tofu_get_policy (ctrl_t ctrl,
 /* When doing a lot of DB activities (in particular, when listing
    keys), this causes the DB to enter batch mode, which can
    significantly speed up operations.  */
-void tofu_begin_batch_update (void);
-void tofu_end_batch_update (void);
+void tofu_begin_batch_update (ctrl_t ctrl);
+void tofu_end_batch_update (ctrl_t ctrl);
 
 /* Release all of the resources associated with a DB meta-handle.  */
 void tofu_closedbs (ctrl_t ctrl);
index 38b6a0f..2b302ba 100755 (executable)
    (checkpolicy "BC15C85A" format "ask")
    (checkpolicy "2183839A" format "bad")
    (checkpolicy "EE37CF96" format "ask"))
- '("split" "flat"))
+ '("flat"))