2 ** Copyright (c) 1999-2002 Proofpoint, 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: smndbm.c,v 8.55 2013-11-22 20:51:49 ca Exp $")
17 #include <sendmail/sendmail.h>
18 #include <libsmdb/smdb.h>
22 # define SMNDB_DIR_FILE_EXTENSION "dir"
23 # define SMNDB_PAG_FILE_EXTENSION "pag"
25 struct smdb_dbm_database_struct
29 bool smndbm_cursor_in_use;
31 typedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE;
33 struct smdb_dbm_cursor_struct
35 SMDB_DBM_DATABASE *smndbmc_db;
36 datum smndbmc_current_key;
38 typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR;
41 ** SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
44 ** flags -- The flags to translate.
47 ** The ndbm flags that are equivalent to the smdb flags.
50 ** Any invalid flags are ignored.
55 smdb_put_flags_to_ndbm_flags(flags)
61 if (bitset(SMDBF_NO_OVERWRITE, flags))
62 return_flags = DBM_INSERT;
64 return_flags = DBM_REPLACE;
70 ** Except for smdb_ndbm_open, the rest of these function correspond to the
71 ** interface laid out in smdb.h.
75 smdbm_malloc_database()
77 SMDB_DBM_DATABASE *db;
79 db = (SMDB_DBM_DATABASE *) malloc(sizeof(SMDB_DBM_DATABASE));
82 db->smndbm_dbm = NULL;
83 db->smndbm_lock_fd = -1;
84 db->smndbm_cursor_in_use = false;
92 SMDB_DATABASE *database;
94 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
95 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
98 if (db->smndbm_lock_fd != -1)
99 close(db->smndbm_lock_fd);
102 database->smdb_impl = NULL;
108 smdbm_del(database, key, flags)
109 SMDB_DATABASE *database;
114 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
117 (void) memset(&dbkey, '\0', sizeof dbkey);
118 dbkey.dptr = key->data;
119 dbkey.dsize = key->size;
122 result = dbm_delete(dbm, dbkey);
125 int save_errno = errno;
128 return SMDBE_IO_ERROR;
133 return SMDBE_NOT_FOUND;
139 smdbm_fd(database, fd)
140 SMDB_DATABASE *database;
143 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
145 *fd = dbm_dirfno(dbm);
153 smdbm_lockfd(database)
154 SMDB_DATABASE *database;
156 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
158 return db->smndbm_lock_fd;
162 smdbm_get(database, key, data, flags)
163 SMDB_DATABASE *database;
168 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
171 (void) memset(&dbkey, '\0', sizeof dbkey);
172 (void) memset(&dbdata, '\0', sizeof dbdata);
173 dbkey.dptr = key->data;
174 dbkey.dsize = key->size;
177 dbdata = dbm_fetch(dbm, dbkey);
178 if (dbdata.dptr == NULL)
180 int save_errno = errno;
183 return SMDBE_IO_ERROR;
188 return SMDBE_NOT_FOUND;
190 data->data = dbdata.dptr;
191 data->size = dbdata.dsize;
196 smdbm_put(database, key, data, flags)
197 SMDB_DATABASE *database;
204 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
207 (void) memset(&dbkey, '\0', sizeof dbkey);
208 (void) memset(&dbdata, '\0', sizeof dbdata);
209 dbkey.dptr = key->data;
210 dbkey.dsize = key->size;
211 dbdata.dptr = data->data;
212 dbdata.dsize = data->size;
215 result = dbm_store(dbm, dbkey, dbdata,
216 smdb_put_flags_to_ndbm_flags(flags));
220 return SMDBE_DUPLICATE;
229 return SMDBE_IO_ERROR;
234 return SMDBE_IO_ERROR;
240 smndbm_set_owner(database, uid, gid)
241 SMDB_DATABASE *database;
248 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
250 fd = dbm_dirfno(dbm);
254 result = fchown(fd, uid, gid);
258 fd = dbm_pagfno(dbm);
262 result = fchown(fd, uid, gid);
265 # endif /* HASFCHOWN */
271 smdbm_sync(database, flags)
272 SMDB_DATABASE *database;
275 return SMDBE_UNSUPPORTED;
279 smdbm_cursor_close(cursor)
282 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
283 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
285 if (!db->smndbm_cursor_in_use)
286 return SMDBE_NOT_A_VALID_CURSOR;
288 db->smndbm_cursor_in_use = false;
296 smdbm_cursor_del(cursor, flags)
301 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
302 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
303 DBM *dbm = db->smndbm_dbm;
306 result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key);
309 int save_errno = errno;
312 return SMDBE_IO_ERROR;
317 return SMDBE_NOT_FOUND;
323 smdbm_cursor_get(cursor, key, value, flags)
329 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
330 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
331 DBM *dbm = db->smndbm_dbm;
334 (void) memset(&dbkey, '\0', sizeof dbkey);
335 (void) memset(&dbdata, '\0', sizeof dbdata);
337 if (flags == SMDB_CURSOR_GET_RANGE)
338 return SMDBE_UNSUPPORTED;
340 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
342 dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm);
343 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
346 return SMDBE_IO_ERROR;
347 return SMDBE_LAST_ENTRY;
352 dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm);
353 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
356 return SMDBE_IO_ERROR;
357 return SMDBE_LAST_ENTRY;
362 dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key);
363 if (dbdata.dptr == NULL)
365 int save_errno = errno;
368 return SMDBE_IO_ERROR;
373 return SMDBE_NOT_FOUND;
375 value->data = dbdata.dptr;
376 value->size = dbdata.dsize;
377 key->data = dbm_cursor->smndbmc_current_key.dptr;
378 key->size = dbm_cursor->smndbmc_current_key.dsize;
384 smdbm_cursor_put(cursor, key, value, flags)
392 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
393 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
394 DBM *dbm = db->smndbm_dbm;
397 (void) memset(&dbdata, '\0', sizeof dbdata);
398 dbdata.dptr = value->data;
399 dbdata.dsize = value->size;
402 result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata,
403 smdb_put_flags_to_ndbm_flags(flags));
407 return SMDBE_DUPLICATE;
416 return SMDBE_IO_ERROR;
421 return SMDBE_IO_ERROR;
427 smdbm_cursor(database, cursor, flags)
428 SMDB_DATABASE *database;
429 SMDB_CURSOR **cursor;
432 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
434 SMDB_DBM_CURSOR *dbm_cursor;
436 if (db->smndbm_cursor_in_use)
437 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
439 db->smndbm_cursor_in_use = true;
440 dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR));
441 if (dbm_cursor == NULL)
443 dbm_cursor->smndbmc_db = db;
444 dbm_cursor->smndbmc_current_key.dptr = NULL;
445 dbm_cursor->smndbmc_current_key.dsize = 0;
447 cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR));
454 cur->smdbc_impl = dbm_cursor;
455 cur->smdbc_close = smdbm_cursor_close;
456 cur->smdbc_del = smdbm_cursor_del;
457 cur->smdbc_get = smdbm_cursor_get;
458 cur->smdbc_put = smdbm_cursor_put;
464 ** SMDB_NDBM_OPEN -- Opens a ndbm database.
467 ** database -- An unallocated database pointer to a pointer.
468 ** db_name -- The name of the database without extension.
469 ** mode -- File permisions on a created database.
470 ** mode_mask -- Mode bits that much match on an opened database.
471 ** sff -- Flags to safefile.
472 ** type -- The type of database to open.
473 ** Only SMDB_NDBM is supported.
474 ** user_info -- Information on the user to use for file
476 ** db_params -- No params are supported.
479 ** SMDBE_OK -- Success, otherwise errno:
480 ** SMDBE_MALLOC -- Cannot allocate memory.
481 ** SMDBE_UNSUPPORTED -- The type is not supported.
482 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
484 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
485 ** Anything else: errno
489 smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
491 SMDB_DATABASE **database;
497 SMDB_USER_INFO *user_info;
498 SMDB_DBPARAMS *db_params;
500 bool lockcreated = false;
503 SMDB_DATABASE *smdb_db;
504 SMDB_DBM_DATABASE *db;
506 struct stat dir_stat_info;
507 struct stat pag_stat_info;
513 return SMDBE_UNKNOWN_DB_TYPE;
515 result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask,
516 sff, user_info, &dir_stat_info);
517 if (result != SMDBE_OK)
520 result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask,
521 sff, user_info, &pag_stat_info);
522 if (result != SMDBE_OK)
525 if ((dir_stat_info.st_mode == ST_MODE_NOFILE ||
526 pag_stat_info.st_mode == ST_MODE_NOFILE) &&
527 bitset(mode, O_CREAT))
531 result = smdb_lock_file(&lock_fd, db_name, mode, sff,
532 SMNDB_DIR_FILE_EXTENSION);
533 if (result != SMDBE_OK)
540 /* Need to pre-open the .pag file as well with O_EXCL */
541 result = smdb_lock_file(&pag_fd, db_name, mode, sff,
542 SMNDB_PAG_FILE_EXTENSION);
543 if (result != SMDBE_OK)
545 (void) close(lock_fd);
548 (void) close(pag_fd);
551 mode &= ~(O_CREAT|O_EXCL);
554 smdb_db = smdb_malloc_database();
556 result = SMDBE_MALLOC;
558 db = smdbm_malloc_database();
560 result = SMDBE_MALLOC;
562 /* Try to open database */
563 if (result == SMDBE_OK)
565 db->smndbm_lock_fd = lock_fd;
568 dbm = dbm_open(db_name, mode, DBMMODE);
572 result = SMDBE_BAD_OPEN;
576 db->smndbm_dbm = dbm;
580 if (result == SMDBE_OK)
582 if (dbm_dirfno(dbm) == dbm_pagfno(dbm))
583 result = SMDBE_GDBM_IS_BAD;
586 /* Check for filechanged */
587 if (result == SMDBE_OK)
589 result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION,
590 dbm_dirfno(dbm), &dir_stat_info);
591 if (result == SMDBE_OK)
593 result = smdb_filechanged(db_name,
594 SMNDB_PAG_FILE_EXTENSION,
600 /* XXX Got to get fchown stuff in here */
602 /* Setup driver if everything is ok */
603 if (result == SMDBE_OK)
607 smdb_db->smdb_close = smdbm_close;
608 smdb_db->smdb_del = smdbm_del;
609 smdb_db->smdb_fd = smdbm_fd;
610 smdb_db->smdb_lockfd = smdbm_lockfd;
611 smdb_db->smdb_get = smdbm_get;
612 smdb_db->smdb_put = smdbm_put;
613 smdb_db->smdb_set_owner = smndbm_set_owner;
614 smdb_db->smdb_sync = smdbm_sync;
615 smdb_db->smdb_cursor = smdbm_cursor;
617 smdb_db->smdb_impl = db;
622 /* If we're here, something bad happened, clean up */
626 smdb_unlock_file(db->smndbm_lock_fd);
628 smdb_free_database(smdb_db);