2 ** Copyright (c) 1999-2002 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: smndbm.c,v 8.52 2002/05/21 22:30:30 gshapiro 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 dbm_cursor
->smndbmc_db
= db
;
442 dbm_cursor
->smndbmc_current_key
.dptr
= NULL
;
443 dbm_cursor
->smndbmc_current_key
.dsize
= 0;
445 cur
= (SMDB_CURSOR
*) malloc(sizeof(SMDB_CURSOR
));
449 cur
->smdbc_impl
= dbm_cursor
;
450 cur
->smdbc_close
= smdbm_cursor_close
;
451 cur
->smdbc_del
= smdbm_cursor_del
;
452 cur
->smdbc_get
= smdbm_cursor_get
;
453 cur
->smdbc_put
= smdbm_cursor_put
;
459 ** SMDB_NDBM_OPEN -- Opens a ndbm database.
462 ** database -- An unallocated database pointer to a pointer.
463 ** db_name -- The name of the database without extension.
464 ** mode -- File permisions on a created database.
465 ** mode_mask -- Mode bits that much match on an opened database.
466 ** sff -- Flags to safefile.
467 ** type -- The type of database to open.
468 ** Only SMDB_NDBM is supported.
469 ** user_info -- Information on the user to use for file
471 ** db_params -- No params are supported.
474 ** SMDBE_OK -- Success, otherwise errno:
475 ** SMDBE_MALLOC -- Cannot allocate memory.
476 ** SMDBE_UNSUPPORTED -- The type is not supported.
477 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
479 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
480 ** Anything else: errno
484 smdb_ndbm_open(database
, db_name
, mode
, mode_mask
, sff
, type
, user_info
,
486 SMDB_DATABASE
**database
;
492 SMDB_USER_INFO
*user_info
;
493 SMDB_DBPARAMS
*db_params
;
495 bool lockcreated
= false;
498 SMDB_DATABASE
*smdb_db
;
499 SMDB_DBM_DATABASE
*db
;
501 struct stat dir_stat_info
;
502 struct stat pag_stat_info
;
508 return SMDBE_UNKNOWN_DB_TYPE
;
510 result
= smdb_setup_file(db_name
, SMNDB_DIR_FILE_EXTENSION
, mode_mask
,
511 sff
, user_info
, &dir_stat_info
);
512 if (result
!= SMDBE_OK
)
515 result
= smdb_setup_file(db_name
, SMNDB_PAG_FILE_EXTENSION
, mode_mask
,
516 sff
, user_info
, &pag_stat_info
);
517 if (result
!= SMDBE_OK
)
520 if ((dir_stat_info
.st_mode
== ST_MODE_NOFILE
||
521 pag_stat_info
.st_mode
== ST_MODE_NOFILE
) &&
522 bitset(mode
, O_CREAT
))
526 result
= smdb_lock_file(&lock_fd
, db_name
, mode
, sff
,
527 SMNDB_DIR_FILE_EXTENSION
);
528 if (result
!= SMDBE_OK
)
535 /* Need to pre-open the .pag file as well with O_EXCL */
536 result
= smdb_lock_file(&pag_fd
, db_name
, mode
, sff
,
537 SMNDB_PAG_FILE_EXTENSION
);
538 if (result
!= SMDBE_OK
)
540 (void) close(lock_fd
);
543 (void) close(pag_fd
);
546 mode
&= ~(O_CREAT
|O_EXCL
);
549 smdb_db
= smdb_malloc_database();
551 result
= SMDBE_MALLOC
;
553 db
= smdbm_malloc_database();
555 result
= SMDBE_MALLOC
;
557 /* Try to open database */
558 if (result
== SMDBE_OK
)
560 db
->smndbm_lock_fd
= lock_fd
;
563 dbm
= dbm_open(db_name
, mode
, DBMMODE
);
567 result
= SMDBE_BAD_OPEN
;
571 db
->smndbm_dbm
= dbm
;
575 if (result
== SMDBE_OK
)
577 if (dbm_dirfno(dbm
) == dbm_pagfno(dbm
))
578 result
= SMDBE_GDBM_IS_BAD
;
581 /* Check for filechanged */
582 if (result
== SMDBE_OK
)
584 result
= smdb_filechanged(db_name
, SMNDB_DIR_FILE_EXTENSION
,
585 dbm_dirfno(dbm
), &dir_stat_info
);
586 if (result
== SMDBE_OK
)
588 result
= smdb_filechanged(db_name
,
589 SMNDB_PAG_FILE_EXTENSION
,
595 /* XXX Got to get fchown stuff in here */
597 /* Setup driver if everything is ok */
598 if (result
== SMDBE_OK
)
602 smdb_db
->smdb_close
= smdbm_close
;
603 smdb_db
->smdb_del
= smdbm_del
;
604 smdb_db
->smdb_fd
= smdbm_fd
;
605 smdb_db
->smdb_lockfd
= smdbm_lockfd
;
606 smdb_db
->smdb_get
= smdbm_get
;
607 smdb_db
->smdb_put
= smdbm_put
;
608 smdb_db
->smdb_set_owner
= smndbm_set_owner
;
609 smdb_db
->smdb_sync
= smdbm_sync
;
610 smdb_db
->smdb_cursor
= smdbm_cursor
;
612 smdb_db
->smdb_impl
= db
;
617 /* If we're here, something bad happened, clean up */
621 smdb_unlock_file(db
->smndbm_lock_fd
);
623 smdb_free_database(smdb_db
);