2 ** Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers.
3 ** All rights reserved.
5 ** By using this file, you agree to the terms and conditions set
6 ** forth in the LICENSE file which can be found at the top level of
7 ** the sendmail distribution.
11 SM_RCSID("@(#)$Id: smdb2.c,v 8.79 2003/06/13 21:33:11 ca Exp $")
18 #include <sendmail/sendmail.h>
19 #include <libsmdb/smdb.h>
21 #if (DB_VERSION_MAJOR >= 2)
23 # define SMDB2_FILE_EXTENSION "db"
25 struct smdb_db2_database
30 typedef struct smdb_db2_database SMDB_DB2_DATABASE;
33 ** SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
36 ** type -- The type to translate.
39 ** The DB2 type that corresponsds to the passed in SMDB type.
40 ** Returns -1 if there is no equivalent type.
45 smdb_type_to_db2_type(type)
48 if (type == SMDB_TYPE_DEFAULT)
51 if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
54 if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
60 ** DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
63 ** error -- The error to translate.
66 ** The SMDBE error corresponding to the db2 error.
67 ** If we don't have a corresponding error, it returs errno.
72 db2_error_to_smdb(error)
81 result = SMDBE_INCOMPLETE;
83 # endif /* DB_INCOMPLETE */
87 result = SMDBE_NOT_FOUND;
89 # endif /* DB_NOTFOUND */
93 result = SMDBE_KEY_EMPTY;
95 # endif /* DB_KEYEMPTY */
99 result = SMDBE_KEY_EXIST;
101 # endif /* DB_KEYEXIST */
103 # ifdef DB_LOCK_DEADLOCK
104 case DB_LOCK_DEADLOCK:
105 result = SMDBE_LOCK_DEADLOCK;
107 # endif /* DB_LOCK_DEADLOCK */
109 # ifdef DB_LOCK_NOTGRANTED
110 case DB_LOCK_NOTGRANTED:
111 result = SMDBE_LOCK_NOT_GRANTED;
113 # endif /* DB_LOCK_NOTGRANTED */
115 # ifdef DB_LOCK_NOTHELD
116 case DB_LOCK_NOTHELD:
117 result = SMDBE_LOCK_NOT_HELD;
119 # endif /* DB_LOCK_NOTHELD */
121 # ifdef DB_RUNRECOVERY
123 result = SMDBE_RUN_RECOVERY;
125 # endif /* DB_RUNRECOVERY */
127 # ifdef DB_OLD_VERSION
129 result = SMDBE_OLD_VERSION;
131 # endif /* DB_OLD_VERSION */
143 ** SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
146 ** flags -- The flags to translate.
149 ** The db2 flags that are equivalent to the smdb flags.
152 ** Any invalid flags are ignored.
157 smdb_put_flags_to_db2_flags(flags)
164 if (bitset(SMDBF_NO_OVERWRITE, flags))
165 return_flags |= DB_NOOVERWRITE;
170 ** SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
174 ** flags -- The flags to translate.
177 ** The db2 flags that are equivalent to the smdb flags.
180 ** -1 is returned if flag is unknown.
185 smdb_cursor_get_flags_to_db2(flags)
190 case SMDB_CURSOR_GET_FIRST:
193 case SMDB_CURSOR_GET_LAST:
196 case SMDB_CURSOR_GET_NEXT:
199 case SMDB_CURSOR_GET_RANGE:
208 ** Except for smdb_db_open, the rest of these functions correspond to the
209 ** interface laid out in smdb.h.
213 smdb2_malloc_database()
215 SMDB_DB2_DATABASE *db2;
217 db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE));
219 db2->smdb2_lock_fd = -1;
225 smdb2_close(database)
226 SMDB_DATABASE *database;
229 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
230 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
232 result = db2_error_to_smdb(db->close(db, 0));
233 if (db2->smdb2_lock_fd != -1)
234 close(db2->smdb2_lock_fd);
237 database->smdb_impl = NULL;
243 smdb2_del(database, key, flags)
244 SMDB_DATABASE *database;
248 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
251 (void) memset(&dbkey, '\0', sizeof dbkey);
252 dbkey.data = key->data;
253 dbkey.size = key->size;
254 return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
258 smdb2_fd(database, fd)
259 SMDB_DATABASE *database;
262 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
264 return db2_error_to_smdb(db->fd(db, fd));
268 smdb2_lockfd(database)
269 SMDB_DATABASE *database;
271 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
273 return db2->smdb2_lock_fd;
277 smdb2_get(database, key, data, flags)
278 SMDB_DATABASE *database;
284 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
287 (void) memset(&dbdata, '\0', sizeof dbdata);
288 (void) memset(&dbkey, '\0', sizeof dbkey);
289 dbkey.data = key->data;
290 dbkey.size = key->size;
292 result = db->get(db, NULL, &dbkey, &dbdata, flags);
293 data->data = dbdata.data;
294 data->size = dbdata.size;
295 return db2_error_to_smdb(result);
299 smdb2_put(database, key, data, flags)
300 SMDB_DATABASE *database;
305 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
308 (void) memset(&dbdata, '\0', sizeof dbdata);
309 (void) memset(&dbkey, '\0', sizeof dbkey);
310 dbkey.data = key->data;
311 dbkey.size = key->size;
312 dbdata.data = data->data;
313 dbdata.size = data->size;
315 return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata,
316 smdb_put_flags_to_db2_flags(flags)));
321 smdb2_set_owner(database, uid, gid)
322 SMDB_DATABASE *database;
329 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
331 result = db->fd(db, &fd);
335 result = fchown(fd, uid, gid);
338 # endif /* HASFCHOWN */
344 smdb2_sync(database, flags)
345 SMDB_DATABASE *database;
348 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
350 return db2_error_to_smdb(db->sync(db, flags));
354 smdb2_cursor_close(cursor)
358 DBC *dbc = (DBC *) cursor->smdbc_impl;
360 ret = db2_error_to_smdb(dbc->c_close(dbc));
366 smdb2_cursor_del(cursor, flags)
370 DBC *dbc = (DBC *) cursor->smdbc_impl;
372 return db2_error_to_smdb(dbc->c_del(dbc, 0));
376 smdb2_cursor_get(cursor, key, value, flags)
384 DBC *dbc = (DBC *) cursor->smdbc_impl;
387 (void) memset(&dbdata, '\0', sizeof dbdata);
388 (void) memset(&dbkey, '\0', sizeof dbkey);
390 db2_flags = smdb_cursor_get_flags_to_db2(flags);
391 result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
392 if (result == DB_NOTFOUND)
393 return SMDBE_LAST_ENTRY;
394 key->data = dbkey.data;
395 key->size = dbkey.size;
396 value->data = dbdata.data;
397 value->size = dbdata.size;
398 return db2_error_to_smdb(result);
402 smdb2_cursor_put(cursor, key, value, flags)
408 DBC *dbc = (DBC *) cursor->smdbc_impl;
411 (void) memset(&dbdata, '\0', sizeof dbdata);
412 (void) memset(&dbkey, '\0', sizeof dbkey);
413 dbkey.data = key->data;
414 dbkey.size = key->size;
415 dbdata.data = value->data;
416 dbdata.size = value->size;
418 return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0));
422 smdb2_cursor(database, cursor, flags)
423 SMDB_DATABASE *database;
424 SMDB_CURSOR **cursor;
428 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
431 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
432 result = db->cursor(db, NULL, &db2_cursor, 0);
433 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
434 result = db->cursor(db, NULL, &db2_cursor);
435 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
437 return db2_error_to_smdb(result);
439 *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
443 (*cursor)->smdbc_close = smdb2_cursor_close;
444 (*cursor)->smdbc_del = smdb2_cursor_del;
445 (*cursor)->smdbc_get = smdb2_cursor_get;
446 (*cursor)->smdbc_put = smdb2_cursor_put;
447 (*cursor)->smdbc_impl = db2_cursor;
452 # if DB_VERSION_MAJOR == 2
454 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
458 SMDB_DBPARAMS *db_params;
465 (void) memset(&db_info, '\0', sizeof db_info);
466 if (db_params != NULL)
468 db_info.db_cachesize = db_params->smdbp_cache_size;
469 if (db_type == DB_HASH)
470 db_info.h_nelem = db_params->smdbp_num_elements;
471 if (db_params->smdbp_allow_dup)
472 db_info.flags |= DB_DUP;
475 return db_open(db_name, db_type, db_flags, DBMMODE, NULL, params, db);
477 # endif /* DB_VERSION_MAJOR == 2 */
479 # if DB_VERSION_MAJOR > 2
481 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
485 SMDB_DBPARAMS *db_params;
490 result = db_create(db, NULL, 0);
491 if (result != 0 || *db == NULL)
494 if (db_params != NULL)
496 result = (*db)->set_cachesize(*db, 0,
497 db_params->smdbp_cache_size, 0);
500 (void) (*db)->close((*db), 0);
502 return db2_error_to_smdb(result);
504 if (db_type == DB_HASH)
506 result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements);
509 (void) (*db)->close(*db, 0);
511 return db2_error_to_smdb(result);
514 if (db_params->smdbp_allow_dup)
516 result = (*db)->set_flags(*db, DB_DUP);
519 (void) (*db)->close(*db, 0);
521 return db2_error_to_smdb(result);
526 result = (*db)->open(*db,
527 DBTXN /* transaction for DB 4.1 */
528 db_name, NULL, db_type, db_flags, DBMMODE);
531 (void) (*db)->close(*db, 0);
534 return db2_error_to_smdb(result);
536 # endif /* DB_VERSION_MAJOR > 2 */
538 ** SMDB_DB_OPEN -- Opens a db database.
541 ** database -- An unallocated database pointer to a pointer.
542 ** db_name -- The name of the database without extension.
543 ** mode -- File permisions for a created database.
544 ** mode_mask -- Mode bits that must match on an opened database.
545 ** sff -- Flags for safefile.
546 ** type -- The type of database to open
547 ** See smdb_type_to_db2_type for valid types.
548 ** user_info -- User information for file permissions.
550 ** An SMDB_DBPARAMS struct including params. These
551 ** are processed according to the type of the
552 ** database. Currently supported params (only for
558 ** SMDBE_OK -- Success, other errno:
559 ** SMDBE_MALLOC -- Cannot allocate memory.
560 ** SMDBE_BAD_OPEN -- db_open didn't return an error, but
561 ** somehow the DB pointer is NULL.
562 ** Anything else: translated error from db2
566 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
567 SMDB_DATABASE **database;
573 SMDB_USER_INFO *user_info;
574 SMDB_DBPARAMS *db_params;
576 bool lockcreated = false;
581 int major_v, minor_v, patch_v;
582 SMDB_DATABASE *smdb_db;
583 SMDB_DB2_DATABASE *db2;
586 struct stat stat_info;
587 char db_file_name[MAXPATHLEN];
589 (void) db_version(&major_v, &minor_v, &patch_v);
590 if (major_v != DB_VERSION_MAJOR || minor_v != DB_VERSION_MINOR)
591 return SMDBE_VERSION_MISMATCH;
595 result = smdb_add_extension(db_file_name, sizeof db_file_name,
596 db_name, SMDB2_FILE_EXTENSION);
597 if (result != SMDBE_OK)
600 result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION,
601 mode_mask, sff, user_info, &stat_info);
602 if (result != SMDBE_OK)
607 if (stat_info.st_mode == ST_MODE_NOFILE &&
608 bitset(mode, O_CREAT))
611 result = smdb_lock_file(&lock_fd, db_name, mode, sff,
612 SMDB2_FILE_EXTENSION);
613 if (result != SMDBE_OK)
619 mode &= ~(O_CREAT|O_EXCL);
622 smdb_db = smdb_malloc_database();
626 db2 = smdb2_malloc_database();
630 db2->smdb2_lock_fd = lock_fd;
632 db_type = smdb_type_to_db2_type(type);
637 if (bitset(O_CREAT, mode))
638 db_flags |= DB_CREATE;
639 if (bitset(O_TRUNC, mode))
640 db_flags |= DB_TRUNCATE;
641 if (mode == O_RDONLY)
642 db_flags |= DB_RDONLY;
643 SM_DB_FLAG_ADD(db_flags);
645 result = smdb_db_open_internal(db_file_name, db_type,
646 db_flags, db_params, &db);
648 if (result == 0 && db != NULL)
650 result = db->fd(db, &db_fd);
656 /* Try and narrow down on the problem */
658 result = db2_error_to_smdb(result);
660 result = SMDBE_BAD_OPEN;
663 if (result == SMDBE_OK)
664 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd,
667 if (result == SMDBE_OK)
669 /* Everything is ok. Setup driver */
672 smdb_db->smdb_close = smdb2_close;
673 smdb_db->smdb_del = smdb2_del;
674 smdb_db->smdb_fd = smdb2_fd;
675 smdb_db->smdb_lockfd = smdb2_lockfd;
676 smdb_db->smdb_get = smdb2_get;
677 smdb_db->smdb_put = smdb2_put;
678 smdb_db->smdb_set_owner = smdb2_set_owner;
679 smdb_db->smdb_sync = smdb2_sync;
680 smdb_db->smdb_cursor = smdb2_cursor;
681 smdb_db->smdb_impl = db2;
691 smdb_unlock_file(db2->smdb2_lock_fd);
693 smdb_free_database(smdb_db);
698 #endif /* (DB_VERSION_MAJOR >= 2) */