From: Jeremy Harris Date: Sun, 21 Jul 2024 10:01:56 +0000 (+0100) Subject: DBM lookups: use dbfn layer interface X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/c66a6edf7ba81ab9615cf3e31af1eb8cc48066eb DBM lookups: use dbfn layer interface --- diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 27bd9e56c..16b300180 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -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 * *************************************************/ diff --git a/src/src/dbfunctions.h b/src/src/dbfunctions.h index 08f8c2311..9d0e75623 100644 --- a/src/src/dbfunctions.h +++ b/src/src/dbfunctions.h @@ -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 **); diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index a35791409..abf5f0123 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -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 diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c index d68110b12..8c7b576f2 100644 --- a/src/src/lookups/dbmdb.c +++ b/src/src/lookups/dbmdb.c @@ -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" @@ -20,12 +23,9 @@ 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); }