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_PAG_FILE_EXTENSION "pag"
24 struct smdb_dbm_database_struct
28 bool smndbm_cursor_in_use;
30 typedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE;
32 struct smdb_dbm_cursor_struct
34 SMDB_DBM_DATABASE *smndbmc_db;
35 datum smndbmc_current_key;
37 typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR;
40 ** SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
43 ** flags -- The flags to translate.
46 ** The ndbm flags that are equivalent to the smdb flags.
49 ** Any invalid flags are ignored.
54 smdb_put_flags_to_ndbm_flags(flags)
60 if (bitset(SMDBF_NO_OVERWRITE, flags))
61 return_flags = DBM_INSERT;
63 return_flags = DBM_REPLACE;
69 ** Except for smdb_ndbm_open, the rest of these function correspond to the
70 ** interface laid out in smdb.h.
74 smdbm_malloc_database()
76 SMDB_DBM_DATABASE *db;
78 db = (SMDB_DBM_DATABASE *) malloc(sizeof(SMDB_DBM_DATABASE));
81 db->smndbm_dbm = NULL;
82 db->smndbm_lock_fd = -1;
83 db->smndbm_cursor_in_use = false;
91 SMDB_DATABASE *database;
93 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
94 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
97 if (db->smndbm_lock_fd != -1)
98 close(db->smndbm_lock_fd);
101 database->smdb_impl = NULL;
107 smdbm_del(database, key, flags)
108 SMDB_DATABASE *database;
113 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
116 (void) memset(&dbkey, '\0', sizeof dbkey);
117 dbkey.dptr = key->data;
118 dbkey.dsize = key->size;
121 result = dbm_delete(dbm, dbkey);
124 int save_errno = errno;
127 return SMDBE_IO_ERROR;
132 return SMDBE_NOT_FOUND;
138 smdbm_fd(database, fd)
139 SMDB_DATABASE *database;
142 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
144 *fd = dbm_dirfno(dbm);
152 smdbm_lockfd(database)
153 SMDB_DATABASE *database;
155 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
157 return db->smndbm_lock_fd;
161 smdbm_get(database, key, data, flags)
162 SMDB_DATABASE *database;
167 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
170 (void) memset(&dbkey, '\0', sizeof dbkey);
171 (void) memset(&dbdata, '\0', sizeof dbdata);
172 dbkey.dptr = key->data;
173 dbkey.dsize = key->size;
176 dbdata = dbm_fetch(dbm, dbkey);
177 if (dbdata.dptr == NULL)
179 int save_errno = errno;
182 return SMDBE_IO_ERROR;
187 return SMDBE_NOT_FOUND;
189 data->data = dbdata.dptr;
190 data->size = dbdata.dsize;
195 smdbm_put(database, key, data, flags)
196 SMDB_DATABASE *database;
203 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
206 (void) memset(&dbkey, '\0', sizeof dbkey);
207 (void) memset(&dbdata, '\0', sizeof dbdata);
208 dbkey.dptr = key->data;
209 dbkey.dsize = key->size;
210 dbdata.dptr = data->data;
211 dbdata.dsize = data->size;
214 result = dbm_store(dbm, dbkey, dbdata,
215 smdb_put_flags_to_ndbm_flags(flags));
219 return SMDBE_DUPLICATE;
228 return SMDBE_IO_ERROR;
233 return SMDBE_IO_ERROR;
239 smndbm_set_owner(database, uid, gid)
240 SMDB_DATABASE *database;
247 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
249 fd = dbm_dirfno(dbm);
253 result = fchown(fd, uid, gid);
257 fd = dbm_pagfno(dbm);
261 result = fchown(fd, uid, gid);
264 # endif /* HASFCHOWN */
270 smdbm_sync(database, flags)
271 SMDB_DATABASE *database;
274 return SMDBE_UNSUPPORTED;
278 smdbm_cursor_close(cursor)
281 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
282 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
284 if (!db->smndbm_cursor_in_use)
285 return SMDBE_NOT_A_VALID_CURSOR;
287 db->smndbm_cursor_in_use = false;
295 smdbm_cursor_del(cursor, flags)
300 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
301 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
302 DBM *dbm = db->smndbm_dbm;
305 result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key);
308 int save_errno = errno;
311 return SMDBE_IO_ERROR;
316 return SMDBE_NOT_FOUND;
322 smdbm_cursor_get(cursor, key, value, flags)
328 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
329 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
330 DBM *dbm = db->smndbm_dbm;
333 (void) memset(&dbkey, '\0', sizeof dbkey);
334 (void) memset(&dbdata, '\0', sizeof dbdata);
336 if (flags == SMDB_CURSOR_GET_RANGE)
337 return SMDBE_UNSUPPORTED;
339 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
341 dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm);
342 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
345 return SMDBE_IO_ERROR;
346 return SMDBE_LAST_ENTRY;
351 dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm);
352 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
355 return SMDBE_IO_ERROR;
356 return SMDBE_LAST_ENTRY;
361 dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key);
362 if (dbdata.dptr == NULL)
364 int save_errno = errno;
367 return SMDBE_IO_ERROR;
372 return SMDBE_NOT_FOUND;
374 value->data = dbdata.dptr;
375 value->size = dbdata.dsize;
376 key->data = dbm_cursor->smndbmc_current_key.dptr;
377 key->size = dbm_cursor->smndbmc_current_key.dsize;
383 smdbm_cursor_put(cursor, key, value, flags)
391 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
392 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
393 DBM *dbm = db->smndbm_dbm;
396 (void) memset(&dbdata, '\0', sizeof dbdata);
397 dbdata.dptr = value->data;
398 dbdata.dsize = value->size;
401 result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata,
402 smdb_put_flags_to_ndbm_flags(flags));
406 return SMDBE_DUPLICATE;
415 return SMDBE_IO_ERROR;
420 return SMDBE_IO_ERROR;
426 smdbm_cursor(database, cursor, flags)
427 SMDB_DATABASE *database;
428 SMDB_CURSOR **cursor;
431 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
433 SMDB_DBM_CURSOR *dbm_cursor;
435 if (db->smndbm_cursor_in_use)
436 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
438 db->smndbm_cursor_in_use = true;
439 dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR));
440 if (dbm_cursor == NULL)
442 dbm_cursor->smndbmc_db = db;
443 dbm_cursor->smndbmc_current_key.dptr = NULL;
444 dbm_cursor->smndbmc_current_key.dsize = 0;
446 cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR));
453 cur->smdbc_impl = dbm_cursor;
454 cur->smdbc_close = smdbm_cursor_close;
455 cur->smdbc_del = smdbm_cursor_del;
456 cur->smdbc_get = smdbm_cursor_get;
457 cur->smdbc_put = smdbm_cursor_put;
463 ** SMDB_NDBM_OPEN -- Opens a ndbm database.
466 ** database -- An unallocated database pointer to a pointer.
467 ** db_name -- The name of the database without extension.
468 ** mode -- File permisions on a created database.
469 ** mode_mask -- Mode bits that much match on an opened database.
470 ** sff -- Flags to safefile.
471 ** type -- The type of database to open.
472 ** Only SMDB_NDBM is supported.
473 ** user_info -- Information on the user to use for file
475 ** db_params -- No params are supported.
478 ** SMDBE_OK -- Success, otherwise errno:
479 ** SMDBE_MALLOC -- Cannot allocate memory.
480 ** SMDBE_UNSUPPORTED -- The type is not supported.
481 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
483 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
484 ** Anything else: errno
488 smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
490 SMDB_DATABASE **database;
496 SMDB_USER_INFO *user_info;
497 SMDB_DBPARAMS *db_params;
499 bool lockcreated = false;
502 SMDB_DATABASE *smdb_db;
503 SMDB_DBM_DATABASE *db;
505 struct stat dir_stat_info;
506 struct stat pag_stat_info;
512 return SMDBE_UNKNOWN_DB_TYPE;
514 result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask,
515 sff, user_info, &dir_stat_info);
516 if (result != SMDBE_OK)
519 result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask,
520 sff, user_info, &pag_stat_info);
521 if (result != SMDBE_OK)
524 if ((dir_stat_info.st_mode == ST_MODE_NOFILE ||
525 pag_stat_info.st_mode == ST_MODE_NOFILE) &&
526 bitset(mode, O_CREAT))
530 result = smdb_lock_file(&lock_fd, db_name, mode, sff,
531 SMNDB_DIR_FILE_EXTENSION);
532 if (result != SMDBE_OK)
539 /* Need to pre-open the .pag file as well with O_EXCL */
540 result = smdb_lock_file(&pag_fd, db_name, mode, sff,
541 SMNDB_PAG_FILE_EXTENSION);
542 if (result != SMDBE_OK)
544 (void) close(lock_fd);
547 (void) close(pag_fd);
550 mode &= ~(O_CREAT|O_EXCL);
553 smdb_db = smdb_malloc_database();
555 result = SMDBE_MALLOC;
557 db = smdbm_malloc_database();
559 result = SMDBE_MALLOC;
561 /* Try to open database */
562 if (result == SMDBE_OK)
564 db->smndbm_lock_fd = lock_fd;
567 dbm = dbm_open(db_name, mode, DBMMODE);
571 result = SMDBE_BAD_OPEN;
575 db->smndbm_dbm = dbm;
579 if (result == SMDBE_OK)
581 if (dbm_dirfno(dbm) == dbm_pagfno(dbm))
582 result = SMDBE_GDBM_IS_BAD;
585 /* Check for filechanged */
586 if (result == SMDBE_OK)
588 result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION,
589 dbm_dirfno(dbm), &dir_stat_info);
590 if (result == SMDBE_OK)
592 result = smdb_filechanged(db_name,
593 SMNDB_PAG_FILE_EXTENSION,
599 /* XXX Got to get fchown stuff in here */
601 /* Setup driver if everything is ok */
602 if (result == SMDBE_OK)
606 smdb_db->smdb_close = smdbm_close;
607 smdb_db->smdb_del = smdbm_del;
608 smdb_db->smdb_fd = smdbm_fd;
609 smdb_db->smdb_lockfd = smdbm_lockfd;
610 smdb_db->smdb_get = smdbm_get;
611 smdb_db->smdb_put = smdbm_put;
612 smdb_db->smdb_set_owner = smndbm_set_owner;
613 smdb_db->smdb_sync = smdbm_sync;
614 smdb_db->smdb_cursor = smdbm_cursor;
616 smdb_db->smdb_impl = db;
621 /* If we're here, something bad happened, clean up */
625 smdb_unlock_file(db->smndbm_lock_fd);
627 smdb_free_database(smdb_db);