DBM lookups: use dbfn layer interface
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 21 Jul 2024 10:01:56 +0000 (11:01 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 21 Jul 2024 10:01:56 +0000 (11:01 +0100)
src/src/dbfn.c
src/src/dbfunctions.h
src/src/hintsdb.h
src/src/lookups/dbmdb.c

index 27bd9e56c23ee161eb45a5b73c4e10c01fef834b..16b300180b17e0ae6cb30f9fc0cd3cc42b6b49d2 100644 (file)
@@ -39,6 +39,7 @@ arrange to hold the locks for the bare minimum of time.
 
 API:
   exim_lockfile_needed                 facilities predicate
+  dbfn_open_path                       full pathname; no lock taken, readonly
   dbfn_open                            takes lockfile or opens transaction
   dbfn_open_multi                      only if transactions supported;
                                        no lock or transaction taken
@@ -46,6 +47,7 @@ API:
   dbfn_close_multi
   dbfn_transaction_start               only if transactions supported
   dbfn_transaction_commit
+  dbfn_read_klen                       explicit key length; embedded NUL ok
   dbfn_read_with_length
   dbfn_read_enforce_length
   dbfn_write
@@ -59,6 +61,7 @@ Users:
   TLS session resumption
   peer capability cache
   callout & quota cache
+  DBM lookup type
 */
 
 
@@ -67,6 +70,22 @@ Users:
 *          Open and lock a database file         *
 *************************************************/
 
+/* Used by DBM lookups:
+full pathname for DB file rather than hintsdb name, readonly, no locking. */
+
+open_db *
+dbfn_open_path(const uschar * path, open_db * dbblock)
+{
+uschar * dirname = string_copy(path);
+
+dbblock->readonly = TRUE;
+dbblock->lockfd = -1;
+dbblock->dbptr = !exim_lockfile_needed()
+  ? exim_dbopen_multi(path, dirname, O_RDONLY, 0)
+  : exim_dbopen(path, dirname, O_RDONLY, 0);
+return dbblock->dbptr ? dbblock : NULL;;
+}
+
 /* Ensure the directory for the DB is present */
 
 static inline void
@@ -368,6 +387,7 @@ has two arguments; it calls this function adding NULL as the third.
 Arguments:
   dbblock   a pointer to an open database block
   key       the key of the record to be read
+  klen     length of key including a terminating NUL (if present)
   length    a pointer to an int into which to return the length, if not NULL
 
 Returns: a pointer to the retrieved record, or
@@ -375,17 +395,16 @@ Returns: a pointer to the retrieved record, or
 */
 
 void *
-dbfn_read_with_length(open_db * dbblock, const uschar * key, int * length)
+dbfn_read_klen(open_db * dbblock, const uschar * key, int klen, int * length)
 {
 void * yield;
 EXIM_DATUM key_datum, result_datum;
-int klen = Ustrlen(key) + 1;
 uschar * key_copy = store_get(klen, key);
 unsigned dlen;
 
 memcpy(key_copy, key, klen);
 
-DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%s\n", key);
+DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%.*s\n", klen, key);
 
 exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
 exim_datum_init(&result_datum);      /* to be cleared before use. */
@@ -412,6 +431,25 @@ return yield;
 }
 
 
+/*
+Arguments:
+  dbblock   a pointer to an open database block
+  key       the key of the record to be read (NUL-terminated)
+  lenp      a pointer to an int into which to return the data length,
+           if not NULL
+
+Returns: a pointer to the retrieved record, or
+         NULL if the record is not found
+*/
+
+void *
+dbfn_read_with_length(open_db * dbblock, const uschar * key, int * lenp)
+{
+return dbfn_read_klen(dbblock, key, Ustrlen(key)+1, lenp);
+}
+
+
+
 /* Read a record.  If the length is not as expected then delete it, write
 an error log line, delete the record and return NULL.
 Use this for fixed-size records (so not retry or wait records).
@@ -440,7 +478,6 @@ if (yield)
 return NULL;
 }
 
-
 /*************************************************
 *             Write to database file             *
 *************************************************/
index 08f8c23113628de495876a47684e1e64a1498a6c..9d0e75623c9e49e5be8419a2bc0c1b0fd8db5925 100644 (file)
@@ -16,7 +16,9 @@ void     dbfn_close(open_db *);
 void     dbfn_close_multi(open_db *);
 int      dbfn_delete(open_db *, const uschar *);
 open_db *dbfn_open(const uschar *, int, open_db *, BOOL, BOOL);
+open_db * dbfn_open_path(const uschar *, open_db *);
 open_db *dbfn_open_multi(const uschar *, int, open_db *);
+void    *dbfn_read_klen(open_db *, const uschar *, int, int *);
 void    *dbfn_read_with_length(open_db *, const uschar *, int *);
 void    *dbfn_read_enforce_length(open_db *, const uschar *, size_t);
 uschar  *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
index a357914093a0b33b2969f43cbb7ec4fe5e6c68d3..abf5f01230b2e394f4cfa03224bebc4840587795 100644 (file)
@@ -11,8 +11,9 @@
 libraries can be used by Exim. Nigel Metheringham provided the original set for
 Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
 2.x and 3.x were added. Later still, support for tdb was added, courtesy of
-James Antill. Most recently, support for native mode gdbm was added, with code
+James Antill. More recently, support for native mode gdbm was added, with code
 from Pierre A. Humblet, so Exim could be made to work with Cygwin.
+Most recently, sqlite3 was added.
 
 For convenience, the definitions of the structures used in the various hints
 databases are also kept in this file, which is used by the maintenance
@@ -52,14 +53,8 @@ Selection of the shim layer implementation, and backend, is by #defines.
 The users of this API are:
   hintsdb interface    dbfn.c
   hintsdb utilities    exim_dbutil.c and exim_dbmvuild.c
-  dbmdb lookup         lookups/dbmdb,c
   autoreply transport  transports/autoreply.c
 
-Note that the dbmdb lookup use, bypassing the dbfn.c layer,
-means that no file-locking is done.
-XXX This feels like a layering violation; I don't see it commented on
-anywhere.
-
 Future: consider re-architecting to support caching of the open-handle
 for hintsdb uses (the dbmdb use gets that already).  This would need APIs
 for transaction locks.  Perhaps merge the implementation with the lookups
index d68110b126dd21cb4b835aa119113bcc319e43e2..8c7b576f25fd400ac6c2146f77de0fecea2c6e7f 100644 (file)
@@ -7,6 +7,9 @@
 /* See the file NOTICE for conditions of use and distribution. */
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
+/* The "dbm" lookup uses whichever provider that is
+compiled in for supporting hintsdbs. */
+
 #include "../exim.h"
 #include "lf_functions.h"
 
 static void *
 dbmdb_open(const uschar * filename, uschar ** errmsg)
 {
-uschar * dirname = string_copy(filename);
-uschar * s;
-EXIM_DB * yield = NULL;
+open_db * yield = store_get(sizeof(open_db), GET_UNTAINTED);
 
-if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
-if (!(yield = exim_dbopen(filename, dirname, O_RDONLY, 0)))
+if (!(yield = dbfn_open_path(filename, yield)))
   *errmsg = string_open_failed("%s as a %s file", filename, EXIM_DBTYPE);
 return yield;
 }
@@ -90,24 +90,8 @@ dbmdb_find(void * handle, const uschar * filename, const uschar * keystring,
   int length, uschar ** result, uschar ** errmsg, uint * do_cache,
   const uschar * opts)
 {
-EXIM_DB *d = (EXIM_DB *)handle;
-EXIM_DATUM key, data;
-
-exim_datum_init(&key);               /* Some DBM libraries require datums to */
-exim_datum_init(&data);              /* be cleared before use. */
-length++;
-exim_datum_data_set(&key,
-  memcpy(store_get(length, keystring), keystring, length)); /* key can have embedded NUL */
-exim_datum_size_set(&key, length);
-
-if (exim_dbget(d, &key, &data))
-  {
-  unsigned len = exim_datum_size_get(&data);
-  *result = len > 0 ? string_copyn(exim_datum_data_get(&data), len) : US"";
-  exim_datum_free(&data);            /* Some DBM libraries need a free() call */
-  return OK;
-  }
-return FAIL;
+open_db * d = (open_db *)handle;
+return (*result = dbfn_read_klen(d, keystring, length+1, NULL)) ? OK : FAIL;
 }
 
 
@@ -217,7 +201,7 @@ return dbmdb_find(handle, filename, key_buffer, key_item_len - 1,
 void
 static dbmdb_close(void *handle)
 {
-exim_dbclose((EXIM_DB *)handle);
+dbfn_close((open_db *)handle);
 }