X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/799253d6a75db70c631716a190736c285a97155c..9bf74b9c298f6968417fe88a68ccdf2179db1403:/src/src/hintsdb.h diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index 545c83dbd..a6555ed25 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -23,18 +23,19 @@ binary blobs. The API is: Functions: + exim_lockfile_needed API semantics predicate exim_dbopen exim_dbclose exim_dbget exim_dbput - exim_dbputb (non-overwriting put) + exim_dbputb non-overwriting put exim_dbdel exim_dbcreate_cursor - exim_dbscan (get, and bump cursor) + exim_dbscan get, and bump cursor exim_dbdelete_cursor exim_datum_init - exim_datum_size_get - exim_datum_data_get + exim_datum_size_get/set + exim_datum_data_get/set exim_datum_free Defines: EXIM_DB access handle @@ -49,6 +50,17 @@ The users of this API are: 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 +layer, in some way, for the open-handle caching (since that manages closes +required by Exim's process transisitions)? */ #ifndef HINTSDB_H @@ -56,6 +68,9 @@ The users of this API are: #ifdef USE_SQLITE +# if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB) +# error USE_SQLITE conflict with alternate definition +# endif /* ********************* sqlite3 interface ************************ */ @@ -74,6 +89,12 @@ The users of this API are: # /* Access functions */ +static inline BOOL +exim_lockfile_needed(void) +{ +return FALSE; /* We do transaction; no extra locking needed */ +} + /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */ static inline EXIM_DB * exim_dbopen__(const uschar * name, const uschar * dirname, int flags, @@ -85,9 +106,13 @@ if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE; if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK) { sqlite3_busy_timeout(dbp, 5000); - if (flags & O_CREAT) - ret == sqlite3_exec(dbp, - "CREATE TABLE tbl (ky TEXT PRIMARY KEY, dat BLOB);", NULL, NULL, NULL); + ret = sqlite3_exec(dbp, "BEGIN TRANSACTION;", NULL, NULL, NULL); + if (ret == SQLITE_OK && flags & O_CREAT) + ret = sqlite3_exec(dbp, + "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);", + NULL, NULL, NULL); + if (ret != SQLITE_OK) + sqlite3_close(dbp); } //else // fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp)); @@ -119,7 +144,12 @@ if (sqlite3_step(statement) != SQLITE_ROW) } res->len = sqlite3_column_bytes(statement, 0); -res->data = store_get(res->len + 1, GET_TAINTED); +# ifdef COMPILE_UTILITY +if (!(res->data = malloc(res->len +1))) + { sqlite3_finalize(statement); return FALSE; } +# else +res->data = store_get(res->len +1, GET_TAINTED); +# endif memcpy(res->data, sqlite3_column_blob(statement, 0), res->len); res->data[res->len] = '\0'; /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */ @@ -137,7 +167,9 @@ BOOL ret; # ifdef COMPILE_UTILITY /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */ -qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data)); +i = snprintf(NULL, 0, FMT, (int) key->len, key->data)+1; +if (!(qry = malloc(i))) + return FALSE; snprintf(CS qry, i, FMT, (int) key->len, key->data); ret = exim_dbget__(dbp, qry, res); free(qry); @@ -158,23 +190,29 @@ return ret; static inline int exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt) { +int hlen = data->len * 2, off = 0, res; # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');" -uschar * hex = store_get(data->len * 2, data->data), * qry; -int res; +uschar * qry; +# ifdef COMPILE_UTILITY +uschar * hex = malloc(hlen+1); +if (!hex) return EXIM_DBPUTB_DUP; /* best we can do */ +# else +uschar * hex = store_get(hlen+1, data->data); +# endif -for (const uschar * s = data->data, * t = s + data->len; s < t; s++) - sprintf(CS hex + 2 * (s - data->data), "%02X", *s); +for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2) + sprintf(CS hex + off, "%02X", *s); # ifdef COMPILE_UTILITY -res = snprintf(NULL, 0, FMT, - alt, (int) key->len, key->data, (int)data->len * 2, hex); -qry = malloc(res); -snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex); +res = snprintf(CS hex, 0, FMT, alt, (int) key->len, key->data, hlen, hex) +1; +if (!(qry = malloc(res))) return EXIM_DBPUTB_DUP; +snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, hlen, hex); /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */ res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); free(qry); +free(hex); # else -qry = string_sprintf(FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex); +qry = string_sprintf(FMT, alt, (int) key->len, key->data, hlen, hex); /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */ res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); /* fprintf(stderr, "exim_s_dbp res %d\n", res); */ @@ -216,8 +254,8 @@ uschar * qry; int res; # ifdef COMPILE_UTILITY -res = snprintf(NULL, 0, FMT, (int) key->len, key->data); -qry = malloc(res); +res = snprintf(NULL, 0, FMT, (int) key->len, key->data) +1; /* res includes nul */ +if (!(qry = malloc(res))) return SQLITE_NOMEM; snprintf(CS qry, res, FMT, (int) key->len, key->data); res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); free(qry); @@ -237,7 +275,12 @@ return res; static inline EXIM_CURSOR * exim_dbcreate_cursor(EXIM_DB * dbp) { +# ifdef COMPILE_UTILITY +EXIM_CURSOR * c = malloc(sizeof(int)); +if (!c) return NULL; +# else EXIM_CURSOR * c = store_malloc(sizeof(int)); +# endif *c = 0; return c; } @@ -254,7 +297,8 @@ int i; BOOL ret; # ifdef COMPILE_UTILITY -qry = malloc(i = snprintf(NULL, 0, FMT, *cursor)); +i = snprintf(NULL, 0, FMT, *cursor)+1; +if (!(qry = malloc(i))) return FALSE; snprintf(CS qry, i, FMT, *cursor); /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */ ret = exim_dbget__(dbp, qry, key); @@ -274,13 +318,22 @@ return ret; /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */ static inline void exim_dbdelete_cursor(EXIM_CURSOR * cursor) -{ store_free(cursor); } +{ +# ifdef COMPILE_UTILITY +free(cursor); +# else +store_free(cursor); +# endif +} /* EXIM_DBCLOSE */ static void -exim_dbclose__(EXIM_DB * db) -{ sqlite3_close(db); } +exim_dbclose__(EXIM_DB * dbp) +{ +(void) sqlite3_exec(dbp, "COMMIT TRANSACTION;", NULL, NULL, NULL); +sqlite3_close(dbp); +} /* Datum access */ @@ -322,7 +375,7 @@ exim_datum_free(EXIM_DATUM * dp) #elif defined(USE_TDB) -# if defined(USE_DB) || defined(USE_GDBM) +# if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE) # error USE_TDB conflict with alternate definition # endif @@ -347,6 +400,12 @@ tdb_traverse to be called) */ /* Access functions */ +static inline BOOL +exim_lockfile_needed(void) +{ +return TRUE; +} + /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */ static inline EXIM_DB * exim_dbopen__(const uschar * name, const uschar * dirname, int flags, @@ -387,7 +446,11 @@ exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key) static inline EXIM_CURSOR * exim_dbcreate_cursor(EXIM_DB * dbp) { +# ifdef COMPILE_UTILITY +EXIM_CURSOR * c = malloc(sizeof(TDB_DATA)); +# else EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA)); +# endif c->dptr = NULL; return c; } @@ -426,7 +489,7 @@ exim_datum_data_set(EXIM_DATUM * dp, void * s) static inline unsigned exim_datum_size_get(EXIM_DATUM * dp) -{ return dp->len; } +{ return dp->dsize; } static inline void exim_datum_size_set(EXIM_DATUM * dp, unsigned n) { dp->dsize = n; } @@ -459,7 +522,7 @@ d->dptr = NULL; #elif defined USE_DB -# if defined(USE_TDB) || defined(USE_GDBM) +# if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE) # error USE_DB conflict with alternate definition # endif @@ -518,7 +581,13 @@ log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); -/* Access functions */ +/* Access functions (BDB 4.1+) */ + +static inline BOOL +exim_lockfile_needed(void) +{ +return TRUE; +} /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */ /* The API changed for DB 4.1. - and we also starting using the "env" with a @@ -541,8 +610,9 @@ if (db_create(&b, dbp, 0) == 0) { dbp->app_private = b; if (b->open(b, NULL, CS name, NULL, - flags == O_RDONLY ? DB_UNKNOWN : DB_HASH, - flags == O_RDONLY ? DB_RDONLY : DB_CREATE, + flags & O_CREAT ? DB_HASH : DB_UNKNOWN, + flags & O_CREAT ? DB_CREATE + : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY, mode) == 0 ) return dbp; @@ -664,7 +734,13 @@ exim_datum_free(EXIM_DATUM * d) /* Some text for messages */ # define EXIM_DBTYPE "db (v3/4)" -/* Access functions */ +/* Access functions (BDB 3/4) */ + +static inline BOOL +exim_lockfile_needed(void) +{ +return TRUE; +} /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */ static inline EXIM_DB * @@ -675,8 +751,9 @@ EXIM_DB * dbp; return db_create(&dbp, NULL, 0) == 0 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback), dbp->open(dbp, CS name, NULL, - flags == O_RDONLY ? DB_UNKNOWN : DB_HASH, - flags == O_RDONLY ? DB_RDONLY : DB_CREATE, + flags & O_CREAT ? DB_HASH : DB_UNKNOWN, + flags & O_CREAT ? DB_CREATE + : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY, mode) ) == 0 ? dbp : NULL; @@ -786,9 +863,9 @@ exim_datum_free(EXIM_DATUM * d) /********************* gdbm interface definitions **********************/ #elif defined USE_GDBM -/*XXX TODO: exim's locfile not needed */ +/*XXX TODO: exim's lockfile not needed? */ -# if defined(USE_TDB) || defined(USE_DB) +# if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE) # error USE_GDBM conflict with alternate definition # endif @@ -810,7 +887,13 @@ typedef struct { # define EXIM_DBTYPE "gdbm" -/* Access functions */ +/* Access functions (gdbm) */ + +static inline BOOL +exim_lockfile_needed(void) +{ +return TRUE; +} /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */ static inline EXIM_DB * @@ -823,8 +906,7 @@ if (dbp) dbp->lkey.dptr = NULL; dbp->gdbm = gdbm_open(CS name, 0, flags & O_CREAT ? GDBM_WRCREAT - : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER - : GDBM_READER, + : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER : GDBM_READER, mode, 0); if (dbp->gdbm) return dbp; free(dbp); @@ -930,8 +1012,8 @@ exim_datum_free(EXIM_DATUM * d) -/* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM -interface (which seems to be a wrapper for GDBM) */ +/* If none of USE_DB, USG_GDBM, USE_SQLITE or USE_TDB are set, +the default is the NDBM interface (which seems to be a wrapper for GDBM) */ /********************* ndbm interface definitions **********************/ @@ -951,7 +1033,13 @@ interface (which seems to be a wrapper for GDBM) */ # define EXIM_DBTYPE "ndbm" -/* Access functions */ +/* Access functions (ndbm) */ + +static inline BOOL +exim_lockfile_needed(void) +{ +return TRUE; +} /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */ /* Check that the name given is not present. This catches