1 /* ldbm.c - ldap dbm compatibility routines */
4 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
8 /* Patched for Berkeley DB version 2.0; /KSp; 98/02/23
10 * - DB version 2.6.4b ; 1998/12/28, /KSp
11 * - DB_DBT_MALLOC ; 1998/03/22, /KSp
12 * - basic implementation; 1998/02/23, /KSp
21 #include <ac/stdlib.h>
22 #include <ac/string.h>
26 #include "ldap_pvt_thread.h"
29 ldbm_datum_free( LDBM ldbm, Datum data )
33 memset( &data, 0, sizeof( Datum ));
40 ldbm_datum_dup( LDBM ldbm, Datum data )
44 ldbm_datum_init( dup );
46 if ( data.dsize == 0 ) {
52 dup.dsize = data.dsize;
53 if ( (dup.dptr = (char *) malloc( data.dsize )) != NULL )
54 memcpy( dup.dptr, data.dptr, data.dsize );
59 static int ldbm_initialized = 0;
61 #if defined( HAVE_BERKELEY_DB_THREAD ) || defined( HAVE_BERKELEY_DB_THREAD )
62 #define LDBM_LOCK ((void)0)
63 #define LDBM_UNLOCK ((void)0)
66 /* Only DB2 or DB3 with DB_THREAD is thread-free */
67 static ldap_pvt_thread_mutex_t ldbm_big_mutex;
68 #define LDBM_LOCK (ldap_pvt_thread_mutex_lock(&ldbm_big_mutex))
69 #define LDBM_UNLOCK (ldap_pvt_thread_mutex_unlock(&ldbm_big_mutex))
75 /*******************************************************************
77 * Create some special functions to initialize Berkeley DB for *
78 * versions greater than 2. *
80 *******************************************************************/
81 #if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 2)
85 ldbm_malloc( size_t size )
87 return( calloc( 1, size ));
91 #include <ac/syslog.h>
95 ldbm_db_errcall( const char *prefix, char *message )
98 syslog( LOG_INFO, "ldbm_db_errcall(): %s %s", prefix, message );
102 /* a dbEnv for BERKELEYv2 */
103 static DB_ENV ldbm_Env_internal;
104 DB_ENV *ldbm_Env = NULL;
106 int ldbm_initialize( void )
111 if(ldbm_initialized++) return 1;
113 memset( &ldbm_Env_internal, 0, sizeof( DB_ENV ));
114 ldbm_Env = &ldbm_Env_internal;
116 ldbm_Env->db_errcall = ldbm_db_errcall;
117 ldbm_Env->db_errpfx = "==>";
120 #if defined( HAVE_BERKELEY_DB_THREAD )
126 #if DB_VERSION_MAJOR >= 3
127 ( err = db_env_create( &ldbm_Env, 0))
128 #elif DB_VERSION_MAJOR >= 2
129 ( err = db_appinit( NULL, NULL, ldbm_Env, envFlags ))
136 sprintf( error, "%ld\n", (long) err );
138 sprintf( error, "%s\n", strerror( err ));
142 "ldbm_initialize(): FATAL error in db_appinit() : %s\n",
147 #if DB_VERSION_MAJOR >= 3
148 envFlags |= DB_INIT_MPOOL;
149 err = ldbm_Env->open( ldbm_Env, NULL, NULL, envFlags, 0 );
155 sprintf( error, "%ld\n", (long) err );
157 sprintf( error, "%s\n", strerror( err ));
161 "ldbm_initialize(): FATAL error in db_appinit() : %s\n",
171 int ldbm_shutdown( void )
173 if( !ldbm_initialized ) return 1;
175 #if DB_VERSION_MAJOR >= 3
176 ldbm_Env->close( ldbm_Env, 0 );
178 db_appexit( ldbm_Env );
184 #else /* some DB other than Berkeley V2 or greater */
186 int ldbm_initialize( void )
188 if(ldbm_initialized++) return 1;
190 ldap_pvt_thread_mutex_init( &ldbm_big_mutex );
195 int ldbm_shutdown( void )
197 if( !ldbm_initialized ) return 1;
199 ldap_pvt_thread_mutex_destroy( &ldbm_big_mutex );
204 #endif /* ifdef HAVE_BERKELEY_DB */
207 #if defined( LDBM_USE_DBHASH ) || defined( LDBM_USE_DBBTREE )
209 /*****************************************************************
211 * use berkeley db hash or btree package *
213 *****************************************************************/
216 ldbm_open( char *name, int rw, int mode, int dbcachesize )
220 #if DB_VERSION_MAJOR >= 3
223 err = db_create( &ret, ldbm_Env, 0 );
229 sprintf( error, "%ld\n", (long) err );
231 sprintf( error, "%s\n", strerror( err ));
233 (void)ret->close(ret, 0);
237 ret->set_pagesize( ret, DEFAULT_DB_PAGE_SIZE );
238 ret->set_malloc( ret, ldbm_malloc );
239 ret->set_cachesize( ret, 0, dbcachesize, 0 );
240 err = ret->open( ret, name, NULL, DB_TYPE, rw, mode);
247 sprintf( error, "%ld\n", (long) err );
249 sprintf( error, "%s\n", strerror( err ));
251 (void)ret->close(ret, 0);
255 #elif DB_VERSION_MAJOR >= 2
258 memset( &dbinfo, 0, sizeof( dbinfo ));
260 #if defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
261 DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 4
263 * BerkeleyDB 2.4 do not allow db_cachesize
264 * to be specified if an DB_ENV is.
267 /* set db_cachesize of MPOOL is NOT being used. */
268 if (( ldbm_Env == NULL ) || ( ldbm_Env->mp_info == NULL ))
269 dbinfo.db_cachesize = dbcachesize;
272 dbinfo.db_pagesize = DEFAULT_DB_PAGE_SIZE;
273 dbinfo.db_malloc = ldbm_malloc;
276 (void) db_open( name, DB_TYPE, rw, mode, ldbm_Env, &dbinfo, &ret );
284 if ( DB_TYPE == DB_HASH ) {
285 memset( (char *) &hinfo, '\0', sizeof(hinfo) );
286 hinfo.cachesize = dbcachesize;
288 } else if ( DB_TYPE == DB_BTREE ) {
289 memset( (char *) &binfo, '\0', sizeof(binfo) );
290 binfo.cachesize = dbcachesize;
297 ret = dbopen( name, rw, mode, DB_TYPE, info );
306 ldbm_close( LDBM ldbm )
309 #if DB_VERSION_MAJOR >= 3
310 ldbm->close( ldbm, 0 );
311 #elif DB_VERSION_MAJOR >= 2
312 (*ldbm->close)( ldbm, 0 );
314 (*ldbm->close)( ldbm );
320 ldbm_sync( LDBM ldbm )
323 (*ldbm->sync)( ldbm, 0 );
328 ldbm_fetch( LDBM ldbm, Datum key )
334 #if DB_VERSION_MAJOR >= 3
335 ldbm_datum_init( data );
337 data.flags = DB_DBT_MALLOC;
339 if ( (rc = ldbm->get( ldbm, NULL, &key, &data, 0 )) != 0 ) {
340 ldbm_datum_free( ldbm, data );
342 #elif DB_VERSION_MAJOR >= 2
343 ldbm_datum_init( data );
345 data.flags = DB_DBT_MALLOC;
347 if ( (rc = (*ldbm->get)( ldbm, NULL, &key, &data, 0 )) != 0 ) {
348 ldbm_datum_free( ldbm, data );
350 if ( (rc = (*ldbm->get)( ldbm, &key, &data, 0 )) == 0 ) {
351 /* Berkeley DB 1.85 don't malloc the data for us */
352 /* duplicate it for to ensure reentrancy */
353 data = ldbm_datum_dup( ldbm, data );
366 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
372 #if DB_VERSION_MAJOR >= 3
373 rc = ldbm->put( ldbm, NULL, &key, &data, flags & ~LDBM_SYNC );
379 sprintf( error, "%ld\n", (long) rc );
381 sprintf( error, "%s\n", strerror( rc ));
386 #elif DB_VERSION_MAJOR >= 2
387 rc = (*ldbm->put)( ldbm, NULL, &key, &data, flags & ~LDBM_SYNC );
390 rc = (*ldbm->put)( ldbm, &key, &data, flags & ~LDBM_SYNC );
393 if ( flags & LDBM_SYNC )
394 (*ldbm->sync)( ldbm, 0 );
402 ldbm_delete( LDBM ldbm, Datum key )
408 #if DB_VERSION_MAJOR >= 3
409 rc = ldbm->del( ldbm, NULL, &key, 0 );
411 #elif DB_VERSION_MAJOR >= 2
412 rc = (*ldbm->del)( ldbm, NULL, &key, 0 );
415 rc = (*ldbm->del)( ldbm, &key, 0 );
417 (*ldbm->sync)( ldbm, 0 );
425 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbch )
429 #if DB_VERSION_MAJOR >= 2
432 ldbm_datum_init( key );
433 ldbm_datum_init( data );
435 key.flags = data.flags = DB_DBT_MALLOC;
439 /* acquire a cursor for the DB */
440 # if DB_VERSION_MAJOR >= 3
441 if ( ldbm->cursor( ldbm, NULL, &dbci, 0 ) )
442 # elif defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
443 (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6)
445 if ( (*ldbm->cursor)( ldbm, NULL, &dbci ))
448 if ( (*ldbm->cursor)( ldbm, NULL, &dbci, 0 ))
455 if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
456 ldbm_datum_free( ldbm, data );
464 if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_FIRST )) == 0 ) {
465 key = ldbm_datum_dup( ldbm, key );
473 #if DB_VERSION_MAJOR >= 2
483 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
487 #if DB_VERSION_MAJOR >= 2
488 ldbm_datum_init( data );
490 ldbm_datum_free( ldbm, key );
491 key.flags = data.flags = DB_DBT_MALLOC;
495 if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
496 ldbm_datum_free( ldbm, data );
504 if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_NEXT )) == 0 ) {
505 key = ldbm_datum_dup( ldbm, key );
519 ldbm_errno( LDBM ldbm )
524 /******************************************************************
526 * END Berkeley section *
528 ******************************************************************/
530 #elif defined( HAVE_GDBM )
532 #ifdef HAVE_ST_BLKSIZE
533 #include <sys/stat.h>
536 /*****************************************************************
540 *****************************************************************/
543 ldbm_open( char *name, int rw, int mode, int dbcachesize )
546 #ifdef HAVE_ST_BLKSIZE
552 if ( (db = gdbm_open( name, 0, rw | GDBM_FAST, mode, 0 )) == NULL ) {
557 #ifdef HAVE_ST_BLKSIZE
558 if ( dbcachesize > 0 && stat( name, &st ) == 0 ) {
559 dbcachesize /= st.st_blksize;
560 if( dbcachesize == 0 ) dbcachesize = 1;
561 gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
564 if ( dbcachesize > 0 ) {
566 if( dbcachesize == 0 ) dbcachesize = 1;
567 gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
577 ldbm_close( LDBM ldbm )
585 ldbm_sync( LDBM ldbm )
593 ldbm_fetch( LDBM ldbm, Datum key )
598 d = gdbm_fetch( ldbm, key );
605 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
610 rc = gdbm_store( ldbm, key, data, flags & ~LDBM_SYNC );
611 if ( flags & LDBM_SYNC )
619 ldbm_delete( LDBM ldbm, Datum key )
624 rc = gdbm_delete( ldbm, key );
632 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
637 d = gdbm_firstkey( ldbm );
640 if ( d.dptr != NULL ) {
641 *dbcp = (Datum *) malloc( sizeof( Datum ) );
642 **dbcp = ldbm_datum_dup( ldbm, d );
649 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
654 d = gdbm_nextkey( ldbm, *dbcp );
657 ldbm_datum_free( ldbm, *dbcp );
659 if ( d.dptr != NULL ) {
660 *dbcp = ldbm_datum_dup( ldbm, d );
669 ldbm_errno( LDBM ldbm )
682 /* MMAPED DBM HASHING DATABASE */
684 #include <ac/string.h>
686 /* #define MDBM_DEBUG */
693 /* #define MDBM_CHAIN */
700 #define mdbm_store mdbm_chain_store
701 #define mdbm_fetch mdbm_chain_fetch
702 #define mdbm_delete mdbm_chain_delete
703 #define mdbm_first mdbm_chain_first
704 #define mdbm_next mdbm_chain_next
708 #define MDBM_PG_SZ (4*1024)
710 /*****************************************************************
714 *****************************************************************/
717 ldbm_open( char *name, int rw, int mode, int dbcachesize )
723 "==>(mdbm)ldbm_open(name=%s,rw=%x,mode=%x,cachesize=%d)\n",
724 name ? name : "NULL", rw, mode, dbcachesize );
728 LDBM_LOCK; /* We need locking here, this is the only non-thread
729 * safe function we have.
732 if ( (db = mdbm_open( name, rw, mode, MDBM_PG_SZ )) == NULL ) {
736 fprintf( stdout, "<==(mdbm)ldbm_open(db=NULL)\n" );
744 (void)mdbm_set_chain(db);
750 fprintf( stdout, "<==(mdbm)ldbm_open(db=%p)\n", db );
762 ldbm_close( LDBM ldbm )
765 /* Open and close are not reentrant so we need to use locks here */
769 "==>(mdbm)ldbm_close(db=%p)\n", ldbm );
778 fprintf( stdout, "<==(mdbm)ldbm_close()\n" );
788 ldbm_sync( LDBM ldbm )
791 /* XXX: Not sure if this is re-entrant need to check code, if so
792 * you can leave LOCKS out.
802 #define MAX_MDBM_RETRY 5
805 ldbm_fetch( LDBM ldbm, Datum key )
811 /* This hack is needed because MDBM does not take keys
812 * which begin with NULL when working in the chaining
819 k.key.dsize = key.dsize + 1;
820 k.key.dptr = malloc(k.key.dsize);
822 memcpy( (void *)(k.key.dptr + 1), key.dptr, key.dsize );
832 d = mdbm_fetch( ldbm, k );
836 if ( k.val.dptr != NULL ) {
842 if ( (k.val.dptr = malloc( d.dsize )) != NULL ) {
844 k.val.dsize = d.dsize;
845 d = mdbm_fetch( ldbm, k );
854 }/* if ( d.dsize > 0 ) */
856 } while ((d.dsize > k.val.dsize) && (++retry < MAX_MDBM_RETRY));
872 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
875 Datum int_key; /* Internal key */
879 "==>(mdbm)ldbm_store(db=%p, key(dptr=%p,sz=%d), data(dptr=%p,sz=%d), flags=%x)\n",
880 ldbm, key.dptr, key.dsize, data.dptr, data.dsize, flags );
887 int_key.dsize = key.dsize + 1;
888 int_key.dptr = malloc( int_key.dsize );
889 *(int_key.dptr) = 'l'; /* Must not be NULL !*/
890 memcpy( (void *)(int_key.dptr + 1), key.dptr, key.dsize );
895 rc = mdbm_store( ldbm, int_key, data, flags );
896 if ( flags & LDBM_SYNC ) {
903 fprintf( stdout, "<==(mdbm)ldbm_store(rc=%d)\n", rc );
918 ldbm_delete( LDBM ldbm, Datum key )
926 int_key.dsize = key.dsize + 1;
927 int_key.dptr = malloc(int_key.dsize);
928 *(int_key.dptr) = 'l';
929 memcpy( (void *)(int_key.dptr + 1), key.dptr, key.dsize );
934 rc = mdbm_delete( ldbm, int_key );
949 ldbm_get_next( LDBM ldbm, kvpair (*fptr)(MDBM *, kvpair) )
955 size_t sz = MDBM_PAGE_SIZE(ldbm);
964 in.key.dsize = sz; /* Assume first key in one pg */
965 in.key.dptr = malloc(sz);
967 in.val.dptr = NULL; /* Don't need data just key */
973 out = fptr( ldbm, in );
975 if (out.key.dsize > 0) {
977 ret.dsize = out.key.dsize - delta;
978 if ((ret.dptr = (char *)malloc(ret.dsize)) == NULL) {
985 memcpy(ret.dptr, (void *)(out.key.dptr + delta),
1004 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
1007 return ldbm_get_next( ldbm, mdbm_first );
1015 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
1019 * don't know if this will affect the LDAP server opertaion
1020 * but mdbm cannot take and input key.
1023 return ldbm_get_next( ldbm, mdbm_next );
1028 ldbm_errno( LDBM ldbm )
1030 /* XXX: best we can do with current mdbm interface */
1038 #elif defined( HAVE_NDBM )
1040 /*****************************************************************
1042 * if no gdbm or mdbm, fall back to using ndbm, the standard unix thing *
1044 *****************************************************************/
1048 ldbm_open( char *name, int rw, int mode, int dbcachesize )
1053 ldbm = dbm_open( name, rw, mode );
1060 ldbm_close( LDBM ldbm )
1069 ldbm_sync( LDBM ldbm )
1075 ldbm_fetch( LDBM ldbm, Datum key )
1080 d = ldbm_datum_dup( ldbm, dbm_fetch( ldbm, key ) );
1087 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
1092 rc = dbm_store( ldbm, key, data, flags );
1099 ldbm_delete( LDBM ldbm, Datum key )
1104 rc = dbm_delete( ldbm, key );
1111 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
1116 d = dbm_firstkey( ldbm );
1123 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
1128 d = dbm_nextkey( ldbm );
1135 ldbm_errno( LDBM ldbm )
1140 err = dbm_error( ldbm );