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.
10 #pragma ident "%Z%%M% %I% %E% SMI"
13 SM_RCSID("@(#)$Id: smndbm.c,v 8.52 2002/05/21 22:30:30 gshapiro Exp $")
19 #include <sendmail/sendmail.h>
20 #include <libsmdb/smdb.h>
24 # define SMNDB_DIR_FILE_EXTENSION "dir"
25 # define SMNDB_PAG_FILE_EXTENSION "pag"
27 struct smdb_dbm_database_struct
31 bool smndbm_cursor_in_use
;
33 typedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE
;
35 struct smdb_dbm_cursor_struct
37 SMDB_DBM_DATABASE
*smndbmc_db
;
38 datum smndbmc_current_key
;
40 typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR
;
43 ** SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
46 ** flags -- The flags to translate.
49 ** The ndbm flags that are equivalent to the smdb flags.
52 ** Any invalid flags are ignored.
57 smdb_put_flags_to_ndbm_flags(flags
)
63 if (bitset(SMDBF_NO_OVERWRITE
, flags
))
64 return_flags
= DBM_INSERT
;
66 return_flags
= DBM_REPLACE
;
72 ** Except for smdb_ndbm_open, the rest of these function correspond to the
73 ** interface laid out in smdb.h.
77 smdbm_malloc_database()
79 SMDB_DBM_DATABASE
*db
;
81 db
= (SMDB_DBM_DATABASE
*) malloc(sizeof(SMDB_DBM_DATABASE
));
84 db
->smndbm_dbm
= NULL
;
85 db
->smndbm_lock_fd
= -1;
86 db
->smndbm_cursor_in_use
= false;
94 SMDB_DATABASE
*database
;
96 SMDB_DBM_DATABASE
*db
= (SMDB_DBM_DATABASE
*) database
->smdb_impl
;
97 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
100 if (db
->smndbm_lock_fd
!= -1)
101 close(db
->smndbm_lock_fd
);
104 database
->smdb_impl
= NULL
;
110 smdbm_del(database
, key
, flags
)
111 SMDB_DATABASE
*database
;
116 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
119 (void) memset(&dbkey
, '\0', sizeof dbkey
);
120 dbkey
.dptr
= key
->data
;
121 dbkey
.dsize
= key
->size
;
124 result
= dbm_delete(dbm
, dbkey
);
127 int save_errno
= errno
;
130 return SMDBE_IO_ERROR
;
135 return SMDBE_NOT_FOUND
;
141 smdbm_fd(database
, fd
)
142 SMDB_DATABASE
*database
;
145 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
147 *fd
= dbm_dirfno(dbm
);
155 smdbm_lockfd(database
)
156 SMDB_DATABASE
*database
;
158 SMDB_DBM_DATABASE
*db
= (SMDB_DBM_DATABASE
*) database
->smdb_impl
;
160 return db
->smndbm_lock_fd
;
164 smdbm_get(database
, key
, data
, flags
)
165 SMDB_DATABASE
*database
;
170 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
173 (void) memset(&dbkey
, '\0', sizeof dbkey
);
174 (void) memset(&dbdata
, '\0', sizeof dbdata
);
175 dbkey
.dptr
= key
->data
;
176 dbkey
.dsize
= key
->size
;
179 dbdata
= dbm_fetch(dbm
, dbkey
);
180 if (dbdata
.dptr
== NULL
)
182 int save_errno
= errno
;
185 return SMDBE_IO_ERROR
;
190 return SMDBE_NOT_FOUND
;
192 data
->data
= dbdata
.dptr
;
193 data
->size
= dbdata
.dsize
;
198 smdbm_put(database
, key
, data
, flags
)
199 SMDB_DATABASE
*database
;
206 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
209 (void) memset(&dbkey
, '\0', sizeof dbkey
);
210 (void) memset(&dbdata
, '\0', sizeof dbdata
);
211 dbkey
.dptr
= key
->data
;
212 dbkey
.dsize
= key
->size
;
213 dbdata
.dptr
= data
->data
;
214 dbdata
.dsize
= data
->size
;
217 result
= dbm_store(dbm
, dbkey
, dbdata
,
218 smdb_put_flags_to_ndbm_flags(flags
));
222 return SMDBE_DUPLICATE
;
231 return SMDBE_IO_ERROR
;
236 return SMDBE_IO_ERROR
;
242 smndbm_set_owner(database
, uid
, gid
)
243 SMDB_DATABASE
*database
;
250 DBM
*dbm
= ((SMDB_DBM_DATABASE
*) database
->smdb_impl
)->smndbm_dbm
;
252 fd
= dbm_dirfno(dbm
);
256 result
= fchown(fd
, uid
, gid
);
260 fd
= dbm_pagfno(dbm
);
264 result
= fchown(fd
, uid
, gid
);
267 # endif /* HASFCHOWN */
273 smdbm_sync(database
, flags
)
274 SMDB_DATABASE
*database
;
277 return SMDBE_UNSUPPORTED
;
281 smdbm_cursor_close(cursor
)
284 SMDB_DBM_CURSOR
*dbm_cursor
= (SMDB_DBM_CURSOR
*) cursor
->smdbc_impl
;
285 SMDB_DBM_DATABASE
*db
= dbm_cursor
->smndbmc_db
;
287 if (!db
->smndbm_cursor_in_use
)
288 return SMDBE_NOT_A_VALID_CURSOR
;
290 db
->smndbm_cursor_in_use
= false;
298 smdbm_cursor_del(cursor
, flags
)
303 SMDB_DBM_CURSOR
*dbm_cursor
= (SMDB_DBM_CURSOR
*) cursor
->smdbc_impl
;
304 SMDB_DBM_DATABASE
*db
= dbm_cursor
->smndbmc_db
;
305 DBM
*dbm
= db
->smndbm_dbm
;
308 result
= dbm_delete(dbm
, dbm_cursor
->smndbmc_current_key
);
311 int save_errno
= errno
;
314 return SMDBE_IO_ERROR
;
319 return SMDBE_NOT_FOUND
;
325 smdbm_cursor_get(cursor
, key
, value
, flags
)
331 SMDB_DBM_CURSOR
*dbm_cursor
= (SMDB_DBM_CURSOR
*) cursor
->smdbc_impl
;
332 SMDB_DBM_DATABASE
*db
= dbm_cursor
->smndbmc_db
;
333 DBM
*dbm
= db
->smndbm_dbm
;
336 (void) memset(&dbkey
, '\0', sizeof dbkey
);
337 (void) memset(&dbdata
, '\0', sizeof dbdata
);
339 if (flags
== SMDB_CURSOR_GET_RANGE
)
340 return SMDBE_UNSUPPORTED
;
342 if (dbm_cursor
->smndbmc_current_key
.dptr
== NULL
)
344 dbm_cursor
->smndbmc_current_key
= dbm_firstkey(dbm
);
345 if (dbm_cursor
->smndbmc_current_key
.dptr
== NULL
)
348 return SMDBE_IO_ERROR
;
349 return SMDBE_LAST_ENTRY
;
354 dbm_cursor
->smndbmc_current_key
= dbm_nextkey(dbm
);
355 if (dbm_cursor
->smndbmc_current_key
.dptr
== NULL
)
358 return SMDBE_IO_ERROR
;
359 return SMDBE_LAST_ENTRY
;
364 dbdata
= dbm_fetch(dbm
, dbm_cursor
->smndbmc_current_key
);
365 if (dbdata
.dptr
== NULL
)
367 int save_errno
= errno
;
370 return SMDBE_IO_ERROR
;
375 return SMDBE_NOT_FOUND
;
377 value
->data
= dbdata
.dptr
;
378 value
->size
= dbdata
.dsize
;
379 key
->data
= dbm_cursor
->smndbmc_current_key
.dptr
;
380 key
->size
= dbm_cursor
->smndbmc_current_key
.dsize
;
386 smdbm_cursor_put(cursor
, key
, value
, flags
)
394 SMDB_DBM_CURSOR
*dbm_cursor
= (SMDB_DBM_CURSOR
*) cursor
->smdbc_impl
;
395 SMDB_DBM_DATABASE
*db
= dbm_cursor
->smndbmc_db
;
396 DBM
*dbm
= db
->smndbm_dbm
;
399 (void) memset(&dbdata
, '\0', sizeof dbdata
);
400 dbdata
.dptr
= value
->data
;
401 dbdata
.dsize
= value
->size
;
404 result
= dbm_store(dbm
, dbm_cursor
->smndbmc_current_key
, dbdata
,
405 smdb_put_flags_to_ndbm_flags(flags
));
409 return SMDBE_DUPLICATE
;
418 return SMDBE_IO_ERROR
;
423 return SMDBE_IO_ERROR
;
429 smdbm_cursor(database
, cursor
, flags
)
430 SMDB_DATABASE
*database
;
431 SMDB_CURSOR
**cursor
;
434 SMDB_DBM_DATABASE
*db
= (SMDB_DBM_DATABASE
*) database
->smdb_impl
;
436 SMDB_DBM_CURSOR
*dbm_cursor
;
438 if (db
->smndbm_cursor_in_use
)
439 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR
;
441 db
->smndbm_cursor_in_use
= true;
442 dbm_cursor
= (SMDB_DBM_CURSOR
*) malloc(sizeof(SMDB_DBM_CURSOR
));
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
));
451 cur
->smdbc_impl
= dbm_cursor
;
452 cur
->smdbc_close
= smdbm_cursor_close
;
453 cur
->smdbc_del
= smdbm_cursor_del
;
454 cur
->smdbc_get
= smdbm_cursor_get
;
455 cur
->smdbc_put
= smdbm_cursor_put
;
461 ** SMDB_NDBM_OPEN -- Opens a ndbm database.
464 ** database -- An unallocated database pointer to a pointer.
465 ** db_name -- The name of the database without extension.
466 ** mode -- File permisions on a created database.
467 ** mode_mask -- Mode bits that much match on an opened database.
468 ** sff -- Flags to safefile.
469 ** type -- The type of database to open.
470 ** Only SMDB_NDBM is supported.
471 ** user_info -- Information on the user to use for file
473 ** db_params -- No params are supported.
476 ** SMDBE_OK -- Success, otherwise errno:
477 ** SMDBE_MALLOC -- Cannot allocate memory.
478 ** SMDBE_UNSUPPORTED -- The type is not supported.
479 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
481 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
482 ** Anything else: errno
486 smdb_ndbm_open(database
, db_name
, mode
, mode_mask
, sff
, type
, user_info
,
488 SMDB_DATABASE
**database
;
494 SMDB_USER_INFO
*user_info
;
495 SMDB_DBPARAMS
*db_params
;
497 bool lockcreated
= false;
500 SMDB_DATABASE
*smdb_db
;
501 SMDB_DBM_DATABASE
*db
;
503 struct stat dir_stat_info
;
504 struct stat pag_stat_info
;
510 return SMDBE_UNKNOWN_DB_TYPE
;
512 result
= smdb_setup_file(db_name
, SMNDB_DIR_FILE_EXTENSION
, mode_mask
,
513 sff
, user_info
, &dir_stat_info
);
514 if (result
!= SMDBE_OK
)
517 result
= smdb_setup_file(db_name
, SMNDB_PAG_FILE_EXTENSION
, mode_mask
,
518 sff
, user_info
, &pag_stat_info
);
519 if (result
!= SMDBE_OK
)
522 if ((dir_stat_info
.st_mode
== ST_MODE_NOFILE
||
523 pag_stat_info
.st_mode
== ST_MODE_NOFILE
) &&
524 bitset(mode
, O_CREAT
))
528 result
= smdb_lock_file(&lock_fd
, db_name
, mode
, sff
,
529 SMNDB_DIR_FILE_EXTENSION
);
530 if (result
!= SMDBE_OK
)
537 /* Need to pre-open the .pag file as well with O_EXCL */
538 result
= smdb_lock_file(&pag_fd
, db_name
, mode
, sff
,
539 SMNDB_PAG_FILE_EXTENSION
);
540 if (result
!= SMDBE_OK
)
542 (void) close(lock_fd
);
545 (void) close(pag_fd
);
548 mode
&= ~(O_CREAT
|O_EXCL
);
551 smdb_db
= smdb_malloc_database();
553 result
= SMDBE_MALLOC
;
555 db
= smdbm_malloc_database();
557 result
= SMDBE_MALLOC
;
559 /* Try to open database */
560 if (result
== SMDBE_OK
)
562 db
->smndbm_lock_fd
= lock_fd
;
565 dbm
= dbm_open(db_name
, mode
, DBMMODE
);
569 result
= SMDBE_BAD_OPEN
;
573 db
->smndbm_dbm
= dbm
;
577 if (result
== SMDBE_OK
)
579 if (dbm_dirfno(dbm
) == dbm_pagfno(dbm
))
580 result
= SMDBE_GDBM_IS_BAD
;
583 /* Check for filechanged */
584 if (result
== SMDBE_OK
)
586 result
= smdb_filechanged(db_name
, SMNDB_DIR_FILE_EXTENSION
,
587 dbm_dirfno(dbm
), &dir_stat_info
);
588 if (result
== SMDBE_OK
)
590 result
= smdb_filechanged(db_name
,
591 SMNDB_PAG_FILE_EXTENSION
,
597 /* XXX Got to get fchown stuff in here */
599 /* Setup driver if everything is ok */
600 if (result
== SMDBE_OK
)
604 smdb_db
->smdb_close
= smdbm_close
;
605 smdb_db
->smdb_del
= smdbm_del
;
606 smdb_db
->smdb_fd
= smdbm_fd
;
607 smdb_db
->smdb_lockfd
= smdbm_lockfd
;
608 smdb_db
->smdb_get
= smdbm_get
;
609 smdb_db
->smdb_put
= smdbm_put
;
610 smdb_db
->smdb_set_owner
= smndbm_set_owner
;
611 smdb_db
->smdb_sync
= smdbm_sync
;
612 smdb_db
->smdb_cursor
= smdbm_cursor
;
614 smdb_db
->smdb_impl
= db
;
619 /* If we're here, something bad happened, clean up */
623 smdb_unlock_file(db
->smndbm_lock_fd
);
625 smdb_free_database(smdb_db
);