]> git.sur5r.net Git - openldap/blob - libraries/libldbm/ldbm.c
Fix lock leak.
[openldap] / libraries / libldbm / ldbm.c
1 /* ldbm.c - ldap dbm compatibility routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 /* Patched for Berkeley DB version 2.0; /KSp; 98/02/23
9  *
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
13  */
14
15 #include "portable.h"
16
17 #ifdef SLAPD_LDBM
18
19 #include <stdio.h>
20
21 #include <ac/stdlib.h>
22 #include <ac/string.h>
23 #include <ac/errno.h>
24
25 #include "ldbm.h"
26 #include "ldap_pvt_thread.h"
27
28 void
29 ldbm_datum_free( LDBM ldbm, Datum data )
30 {
31         if ( data.dptr ) {
32                 free( data.dptr );
33                 memset( &data, '\0', sizeof( Datum ));
34                 data.dptr = NULL;
35         }
36 }
37
38 Datum
39 ldbm_datum_dup( LDBM ldbm, Datum data )
40 {
41         Datum   dup;
42
43         ldbm_datum_init( dup );
44
45         if ( data.dsize == 0 ) {
46                 dup.dsize = 0;
47                 dup.dptr = NULL;
48
49                 return( dup );
50         }
51         dup.dsize = data.dsize;
52
53         if ( (dup.dptr = (char *) malloc( data.dsize )) != NULL ) {
54                 AC_MEMCPY( dup.dptr, data.dptr, data.dsize );
55         }
56
57         return( dup );
58 }
59
60 static int ldbm_initialized = 0;
61
62 #ifdef USE_BERKELEY_CDB
63         /* not currently supported */
64 #define LDBM_LOCK       ((void) 0)
65 #define LDBM_UNLOCK     ((void) 0)
66 #else
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))
70 #endif
71
72 #if !defined( HAVE_BERKELEY_DB ) || (DB_VERSION_MAJOR < 3)
73         /*  a dbEnv for BERKELEYv2  */
74 DB_ENV *ldbm_Env = NULL;        /* real or fake, depending on db and version */
75 #endif
76
77
78 /*******************************************************************
79  *                                                                 *
80  *  Create some special functions to initialize Berkeley DB for    *
81  *  versions greater than 2.                                       *
82  *                                                                 *
83  *******************************************************************/
84 #if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 2)
85
86 void *
87 ldbm_malloc( size_t size )
88 {
89         /* likely should use ber_mem* routines */
90         return( calloc( 1, size ) );
91 }
92
93 #ifdef LDAP_SYSLOG
94 #include <ac/syslog.h>
95 #endif
96
97 static void
98 ldbm_db_errcall( const char *prefix, char *message )
99 {
100 #ifdef LDAP_SYSLOG
101         syslog( LOG_INFO, "ldbm: %s %s", prefix, message );
102 #endif
103 }
104
105 int ldbm_initialize( const char* home )
106 {
107         int     err;
108         u_int32_t       envFlags;
109
110         if(ldbm_initialized++) return 1;
111
112         {
113                 char *version;
114                 int major, minor, patch;
115                 version = db_version( &major, &minor, &patch );
116
117                 if( major != DB_VERSION_MAJOR ||
118                         minor < DB_VERSION_MINOR )
119                 {
120 #ifdef LDAP_SYSLOG
121                         syslog( LOG_INFO,
122                                 "ldbm_initialize(): version mismatch\nexpected: %s\ngot: %s\n",
123                                 DB_VERSION_STRING, version );
124 #endif
125                         return 1;
126                 }
127         }
128
129 #ifndef USE_BERKELEY_CDB
130         ldap_pvt_thread_mutex_init( &ldbm_big_mutex );
131 #endif
132
133
134 #if DB_VERSION_MAJOR < 3
135         ldbm_Env = calloc( 1, sizeof( DB_ENV ));
136
137         if( ldbm_Env == NULL ) return 1;
138
139         ldbm_Env->db_errcall    = ldbm_db_errcall;
140         ldbm_Env->db_errpfx             = "==>";
141
142         envFlags = DB_CREATE | DB_USE_ENVIRON;
143
144         /* add optional flags */
145 #ifdef DB_PRIVATE
146         envFlags |= DB_PRIVATE;
147 #endif
148 #ifdef HAVE_BERKELEY_DB_THREAD
149         envFlags |= DB_THREAD; 
150 #endif
151
152         err = db_appinit( home, NULL, ldbm_Env, envFlags );
153
154         if ( err ) {
155 #ifdef LDAP_SYSLOG
156                 syslog( LOG_INFO, "ldbm_initialize(): "
157                         "FATAL error in db_appinit() : %s (%d)\n",
158                         db_strerror( err ), err );
159 #endif
160                 return( 1 );
161         }
162 #endif
163
164         return 0;
165 }
166
167 int ldbm_shutdown( void )
168 {
169         if( !ldbm_initialized ) return 1;
170
171 #if DB_VERSION_MAJOR < 3
172         db_appexit( ldbm_Env );
173 #endif
174
175 #ifndef USE_BERKELEY_CDB
176         ldap_pvt_thread_mutex_destroy( &ldbm_big_mutex );
177 #endif
178         return 0;
179 }
180
181 #else  /* some DB other than Berkeley V2 or greater */
182
183 int ldbm_initialize( const char * home )
184 {
185         if(ldbm_initialized++) return 1;
186
187         ldap_pvt_thread_mutex_init( &ldbm_big_mutex );
188
189         return 0;
190 }
191
192 int ldbm_shutdown( void )
193 {
194         if( !ldbm_initialized ) return 1;
195
196         ldap_pvt_thread_mutex_destroy( &ldbm_big_mutex );
197
198         return 0;
199 }
200
201 #endif /* HAVE_BERKELEY_DB */
202
203
204 #if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 3)
205
206 DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
207 {
208         DB_ENV *env = NULL;    
209         int     err;
210         u_int32_t       envFlags;
211
212         err = db_env_create( &env, 0 );
213
214         if ( err ) {
215 #ifdef LDAP_SYSLOG
216                 syslog( LOG_INFO, "ldbm_initialize_env(): "
217                         "FATAL error in db_env_create() : %s (%d)\n",
218                         db_strerror( err ), err );
219 #endif
220                 return NULL;
221         }
222
223         env->set_errcall( env, ldbm_db_errcall );
224         env->set_errpfx( env, "==>" );
225         if (dbcachesize) {
226                 env->set_cachesize( env, 0, dbcachesize, 0 );
227         }
228
229         envFlags = DB_CREATE | DB_INIT_MPOOL | DB_USE_ENVIRON;
230 #ifdef DB_PRIVATE
231         envFlags |= DB_PRIVATE;
232 #endif
233 #ifdef DB_MPOOL_PRIVATE
234         envFlags |= DB_MPOOL_PRIVATE;
235 #endif
236 #ifdef HAVE_BERKELEY_DB_THREAD
237         envFlags |= DB_THREAD;
238 #endif
239
240 #if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 0
241         err = env->open( env, home, envFlags, 0 );
242 #else
243         /* 3.0.x requires an extra argument */
244         err = env->open( env, home, NULL, envFlags, 0 );
245 #endif
246
247         if ( err != 0 ) {
248 #ifdef LDAP_SYSLOG
249                 syslog( LOG_INFO, "ldbm_initialize_env(): "
250                         "FATAL error in dbEnv->open() : %s (%d)\n",
251                         db_strerror( err ), err );
252 #endif
253                 env->close( env, 0 );
254                 return NULL;
255         }
256
257         *envdirok = 1;
258         return env;
259 }
260
261 void ldbm_shutdown_env(DB_ENV *env)
262 {
263         env->close( env, 0 );
264 }
265
266
267 #else
268
269 DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
270 {
271         return ldbm_Env;
272 }
273
274 void ldbm_shutdown_env(DB_ENV *env)
275 {
276 }
277
278 #endif
279
280
281 #if defined( LDBM_USE_DBHASH ) || defined( LDBM_USE_DBBTREE )
282
283 /*****************************************************************
284  *                                                               *
285  * use berkeley db hash or btree package                         *
286  *                                                               *
287  *****************************************************************/
288
289 LDBM
290 ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
291 {
292         LDBM            ret = NULL;
293
294 #if DB_VERSION_MAJOR >= 3
295         int err;
296
297         LDBM_LOCK;
298
299         err = db_create( &ret, env, 0 );
300         if ( err != 0 ) {
301                 (void)ret->close(ret, 0);
302                 LDBM_UNLOCK;
303
304                 return NULL;
305         }
306
307         ret->set_pagesize( ret, DEFAULT_DB_PAGE_SIZE );
308
309         /* likely should use ber_mem* routines */
310 #if DB_VERSION_MINOR >= 3
311         ret->set_alloc( ret, ldbm_malloc, NULL, NULL );
312 #else
313         ret->set_malloc( ret, ldbm_malloc );
314 #endif
315
316         /* ret->set_cachesize( ret, 0, dbcachesize, 0 ); */
317
318         err = ret->open( ret, name, NULL, DB_TYPE, rw, mode);
319
320         if ( err != 0 ) {
321                 int tmp = errno;
322                 (void)ret->close(ret, 0);
323                 errno = tmp;
324
325                 LDBM_UNLOCK;
326                 return NULL;
327         }
328
329         LDBM_UNLOCK;
330  
331 #elif DB_VERSION_MAJOR >= 2
332         DB_INFO dbinfo;
333
334         memset( &dbinfo, '\0', sizeof( dbinfo ));
335
336 #if     DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 4
337         /*
338          * BerkeleyDB 2.4 do not allow db_cachesize
339          * to be specified if an DB_ENV is.
340          */
341 #else
342         /* set db_cachesize of MPOOL is NOT being used. */
343         if (( ldbm_Env == NULL ) || ( ldbm_Env->mp_info == NULL )) {
344                 dbinfo.db_cachesize = dbcachesize;
345         }
346 #endif
347
348         dbinfo.db_pagesize      = DEFAULT_DB_PAGE_SIZE;
349         dbinfo.db_malloc        = ldbm_malloc;
350
351         LDBM_LOCK;
352         (void) db_open( name, DB_TYPE, rw, mode, ldbm_Env, &dbinfo, &ret );
353         LDBM_UNLOCK;
354
355 #else
356         void            *info;
357         BTREEINFO       binfo;
358         HASHINFO        hinfo;
359
360         if ( DB_TYPE == DB_HASH ) {
361                 memset( (char *) &hinfo, '\0', sizeof(hinfo) );
362                 hinfo.cachesize = dbcachesize;
363                 info = &hinfo;
364         } else if ( DB_TYPE == DB_BTREE ) {
365                 memset( (char *) &binfo, '\0', sizeof(binfo) );
366                 binfo.cachesize = dbcachesize;
367                 info = &binfo;
368         } else {
369                 info = NULL;
370         }
371
372         LDBM_LOCK;
373         ret = dbopen( name, rw, mode, DB_TYPE, info );
374         LDBM_UNLOCK;
375 #endif
376
377         return ret;
378 }
379
380 void
381 ldbm_close( LDBM ldbm )
382 {
383         LDBM_LOCK;
384 #if DB_VERSION_MAJOR >= 3
385         ldbm->close( ldbm, 0 );
386 #elif DB_VERSION_MAJOR >= 2
387         (*ldbm->close)( ldbm, 0 );
388 #else
389         (*ldbm->close)( ldbm );
390 #endif
391         LDBM_UNLOCK;
392 }
393
394 void
395 ldbm_sync( LDBM ldbm )
396 {
397         LDBM_LOCK;
398         (*ldbm->sync)( ldbm, 0 );
399         LDBM_UNLOCK;
400 }
401
402 Datum
403 ldbm_fetch( LDBM ldbm, Datum key )
404 {
405         Datum   data;
406         int     rc;
407
408         LDBM_LOCK;
409
410 #if DB_VERSION_MAJOR >= 3
411         ldbm_datum_init( data );
412
413         data.flags = DB_DBT_MALLOC;
414
415         if ( (rc = ldbm->get( ldbm, NULL, &key, &data, 0 )) != 0 ) {
416                 ldbm_datum_free( ldbm, data );
417                 data.dptr = NULL;
418                 data.dsize = 0;
419         }
420
421 #elif DB_VERSION_MAJOR >= 2
422         ldbm_datum_init( data );
423
424         data.flags = DB_DBT_MALLOC;
425
426         if ( (rc = (*ldbm->get)( ldbm, NULL, &key, &data, 0 )) != 0 ) {
427                 ldbm_datum_free( ldbm, data );
428                 data.dptr = NULL;
429                 data.dsize = 0;
430         }
431 #else
432
433         if ( (rc = (*ldbm->get)( ldbm, &key, &data, 0 )) == 0 ) {
434                 /* Berkeley DB 1.85 don't malloc the data for us */
435                 /* duplicate it for to ensure reentrancy */
436                 data = ldbm_datum_dup( ldbm, data );
437         } else {
438                 data.dptr = NULL;
439                 data.dsize = 0;
440         }
441 #endif
442
443         LDBM_UNLOCK;
444
445         return( data );
446 }
447
448 int
449 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
450 {
451         int     rc;
452
453         LDBM_LOCK;
454
455 #if DB_VERSION_MAJOR >= 3
456         rc = ldbm->put( ldbm, NULL, &key, &data, flags & ~LDBM_SYNC );
457         rc = (-1) * rc;
458
459 #elif DB_VERSION_MAJOR >= 2
460         rc = (*ldbm->put)( ldbm, NULL, &key, &data, flags & ~LDBM_SYNC );
461         rc = (-1) * rc;
462 #else
463         rc = (*ldbm->put)( ldbm, &key, &data, flags & ~LDBM_SYNC );
464 #endif
465
466         if ( flags & LDBM_SYNC )
467                 (*ldbm->sync)( ldbm, 0 );
468
469         LDBM_UNLOCK;
470
471         return( rc );
472 }
473
474 int
475 ldbm_delete( LDBM ldbm, Datum key )
476 {
477         int     rc;
478
479         LDBM_LOCK;
480
481 #if DB_VERSION_MAJOR >= 3
482         rc = ldbm->del( ldbm, NULL, &key, 0 );
483         rc = (-1) * rc;
484 #elif DB_VERSION_MAJOR >= 2
485         rc = (*ldbm->del)( ldbm, NULL, &key, 0 );
486         rc = (-1) * rc;
487 #else
488         rc = (*ldbm->del)( ldbm, &key, 0 );
489 #endif
490         (*ldbm->sync)( ldbm, 0 );
491
492         LDBM_UNLOCK;
493
494         return( rc );
495 }
496
497 Datum
498 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbch )
499 {
500         Datum   key, data;
501
502 #if DB_VERSION_MAJOR >= 2
503         LDBMCursor  *dbci;
504
505         ldbm_datum_init( key );
506         ldbm_datum_init( data );
507
508         key.flags = data.flags = DB_DBT_MALLOC;
509
510         LDBM_LOCK;
511
512         /* acquire a cursor for the DB */
513 # if DB_VERSION_MAJOR >= 3
514         if ( ldbm->cursor( ldbm, NULL, &dbci, 0 ) )
515 # elif defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
516         (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6)
517
518         if ( (*ldbm->cursor)( ldbm, NULL, &dbci ))
519
520 #  else
521         if ( (*ldbm->cursor)( ldbm, NULL, &dbci, 0 ))
522 #  endif
523         {
524                 key.dptr = NULL;
525                 LDBM_UNLOCK;
526                 return( key );
527         } else {
528                 *dbch = dbci;
529                 if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
530                         ldbm_datum_free( ldbm, data );
531                 }
532         else {
533 #else
534         int     rc;
535
536         LDBM_LOCK;
537
538         if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_FIRST )) == 0 ) {
539                 key = ldbm_datum_dup( ldbm, key );
540         }
541         else {
542 #endif
543                 key.dptr = NULL;
544                 key.dsize = 0;
545         }
546
547 #if DB_VERSION_MAJOR >= 2
548         }
549 #endif
550
551         LDBM_UNLOCK;
552
553         return( key );
554 }
555
556 Datum
557 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
558 {
559         Datum   data;
560
561 #if DB_VERSION_MAJOR >= 2
562         ldbm_datum_init( data );
563
564         ldbm_datum_free( ldbm, key );
565         key.flags = data.flags = DB_DBT_MALLOC;
566
567         LDBM_LOCK;
568
569         if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
570                 ldbm_datum_free( ldbm, data );
571         }
572         else {
573 #else
574         int     rc;
575
576         LDBM_LOCK;
577
578         if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_NEXT )) == 0 ) {
579                 key = ldbm_datum_dup( ldbm, key );
580         }
581         else {
582 #endif
583                 key.dptr = NULL;
584                 key.dsize = 0;
585         }
586
587         LDBM_UNLOCK;
588
589         return( key );
590 }
591
592 int
593 ldbm_errno( LDBM ldbm )
594 {
595         return( errno );
596 }
597
598 /******************************************************************
599  *                                                                *
600  *         END Berkeley section                                   *
601  *                                                                *
602  ******************************************************************/
603
604 #elif defined( HAVE_GDBM )
605
606 #ifdef HAVE_ST_BLKSIZE
607 #include <sys/stat.h>
608 #endif
609
610 /*****************************************************************
611  *                                                               *
612  * use gdbm                                                      *
613  *                                                               *
614  *****************************************************************/
615
616 LDBM
617 ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
618 {
619         LDBM            db;
620 #ifdef HAVE_ST_BLKSIZE
621                 struct stat     st;
622 #endif
623
624         LDBM_LOCK;
625
626         if ( (db =  gdbm_open( name, 0, rw | GDBM_FAST, mode, 0 )) == NULL ) {
627                 LDBM_UNLOCK;
628                 return( NULL );
629         }
630
631 #ifdef HAVE_ST_BLKSIZE
632         if ( dbcachesize > 0 && stat( name, &st ) == 0 ) {
633                 dbcachesize /= st.st_blksize;
634                 if( dbcachesize == 0 ) dbcachesize = 1;
635                 gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
636         }
637 #else
638         if ( dbcachesize > 0 ) {
639                 dbcachesize /= 4096;
640                 if( dbcachesize == 0 ) dbcachesize = 1;
641                 gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
642         }
643 #endif
644
645         LDBM_UNLOCK;
646
647         return( db );
648 }
649
650 void
651 ldbm_close( LDBM ldbm )
652 {
653         LDBM_LOCK;
654         gdbm_close( ldbm );
655         LDBM_UNLOCK;
656 }
657
658 void
659 ldbm_sync( LDBM ldbm )
660 {
661         LDBM_LOCK;
662         gdbm_sync( ldbm );
663         LDBM_UNLOCK;
664 }
665
666 Datum
667 ldbm_fetch( LDBM ldbm, Datum key )
668 {
669         Datum d;
670
671         LDBM_LOCK;
672         d = gdbm_fetch( ldbm, key );
673         LDBM_UNLOCK;
674
675         return d;
676 }
677
678 int
679 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
680 {
681         int     rc;
682
683         LDBM_LOCK;
684         rc = gdbm_store( ldbm, key, data, flags & ~LDBM_SYNC );
685         if ( flags & LDBM_SYNC )
686                 gdbm_sync( ldbm );
687         LDBM_UNLOCK;
688
689         return( rc );
690 }
691
692 int
693 ldbm_delete( LDBM ldbm, Datum key )
694 {
695         int     rc;
696
697         LDBM_LOCK;
698         rc = gdbm_delete( ldbm, key );
699         gdbm_sync( ldbm );
700         LDBM_UNLOCK;
701
702         return( rc );
703 }
704
705 Datum
706 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
707 {
708         Datum d;
709
710         LDBM_LOCK;
711         d = gdbm_firstkey( ldbm );
712         LDBM_UNLOCK;
713
714         if ( d.dptr != NULL ) {
715                 *dbcp = (Datum *) malloc( sizeof( Datum ) );
716                 **dbcp = ldbm_datum_dup( ldbm, d );
717         }
718
719         return d;
720 }
721
722 Datum
723 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
724 {
725         Datum d;
726
727         LDBM_LOCK;
728         d = gdbm_nextkey( ldbm, *dbcp );
729         LDBM_UNLOCK;
730
731         ldbm_datum_free( ldbm, *dbcp );
732
733         if ( d.dptr != NULL ) {
734                 *dbcp = ldbm_datum_dup( ldbm, d );
735         } else {
736                 free( dbcp );
737         }
738
739         return d;
740 }
741
742 int
743 ldbm_errno( LDBM ldbm )
744 {
745         int err;
746
747         LDBM_LOCK;
748         err = gdbm_errno;
749         LDBM_UNLOCK;
750
751         return( err );
752 }
753
754 #elif HAVE_MDBM
755
756 /* MMAPED DBM HASHING DATABASE */
757
758 #include <ac/string.h>
759
760 /* #define MDBM_DEBUG */
761
762 #ifdef MDBM_DEBUG
763 #include <stdio.h>
764 #endif
765
766 #define NO_NULL_KEY
767 /* #define MDBM_CHAIN */
768
769 #ifdef MDBM_CHAIN
770
771 /* Use chaining */
772
773
774 #define mdbm_store      mdbm_chain_store
775 #define mdbm_fetch      mdbm_chain_fetch
776 #define mdbm_delete     mdbm_chain_delete
777 #define mdbm_first      mdbm_chain_first
778 #define mdbm_next       mdbm_chain_next
779
780 #endif
781
782 #define MDBM_PG_SZ      (4*1024)
783
784 /*****************************************************************
785  *                                                               *
786  * use mdbm                                                      *
787  *                                                               *
788  *****************************************************************/
789
790 LDBM
791 ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
792 {
793         LDBM            db;
794
795 #ifdef MDBM_DEBUG
796         fprintf( stdout,
797                  "==>(mdbm)ldbm_open(name=%s,rw=%x,mode=%x,cachesize=%d)\n",
798                  name ? name : "NULL", rw, mode, dbcachesize );
799         fflush( stdout );
800 #endif
801
802         LDBM_LOCK;      /* We need locking here, this is the only non-thread
803                          * safe function we have.
804                          */
805
806         if ( (db =  mdbm_open( name, rw, mode, MDBM_PG_SZ )) == NULL ) {
807
808                 LDBM_UNLOCK;
809 #ifdef MDBM_DEBUG
810                 fprintf( stdout, "<==(mdbm)ldbm_open(db=NULL)\n" );
811                 fflush( stdout );
812 #endif
813                 return( NULL );
814
815         }
816
817 #ifdef MDBM_CHAIN
818         (void)mdbm_set_chain(db);
819 #endif
820
821         LDBM_UNLOCK;
822
823 #ifdef MDBM_DEBUG
824         fprintf( stdout, "<==(mdbm)ldbm_open(db=%p)\n", db );
825         fflush( stdout );
826 #endif
827
828         return( db );
829
830 }
831
832
833
834
835 void
836 ldbm_close( LDBM ldbm )
837 {
838
839         /* Open and close are not reentrant so we need to use locks here */
840
841 #ifdef MDBM_DEBUG
842         fprintf( stdout,
843                  "==>(mdbm)ldbm_close(db=%p)\n", ldbm );
844         fflush( stdout );
845 #endif
846
847         LDBM_LOCK;
848         mdbm_close( ldbm );
849         LDBM_UNLOCK;
850
851 #ifdef MDBM_DEBUG
852         fprintf( stdout, "<==(mdbm)ldbm_close()\n" );
853         fflush( stdout );
854 #endif
855
856 }
857
858
859
860
861 void
862 ldbm_sync( LDBM ldbm )
863 {
864         /* XXX: Not sure if this is re-entrant need to check code, if so
865          * you can leave LOCKS out.
866          */
867
868         LDBM_LOCK;
869         mdbm_sync( ldbm );
870         LDBM_UNLOCK;
871 }
872
873
874 #define MAX_MDBM_RETRY  5
875
876 Datum
877 ldbm_fetch( LDBM ldbm, Datum key )
878 {
879         Datum   d;
880         kvpair  k;
881         int     retry = 0;
882
883         /* This hack is needed because MDBM does not take keys
884          * which begin with NULL when working in the chaining
885          * mode.
886          */
887
888         /* LDBM_LOCK; */
889
890 #ifdef NO_NULL_KEY
891         k.key.dsize = key.dsize + 1;                    
892         k.key.dptr = malloc(k.key.dsize);
893         *(k.key.dptr) = 'l';
894         AC_MEMCPY( (void *)(k.key.dptr + 1), key.dptr, key.dsize );     
895 #else
896         k.key = key;
897 #endif  
898
899         k.val.dptr = NULL;
900         k.val.dsize = 0;
901
902         do {
903
904                 d = mdbm_fetch( ldbm, k );
905
906                 if ( d.dsize > 0 ) {
907
908                         if ( k.val.dptr != NULL ) {
909                                 free( k.val.dptr );
910                         }
911
912                         if ( (k.val.dptr = malloc( d.dsize )) != NULL ) {
913                 
914                                 k.val.dsize = d.dsize;
915                                 d = mdbm_fetch( ldbm, k );
916
917                         } else { 
918
919                                 d.dsize = 0;
920                                 break;
921                         
922                         }
923
924                 }/* if ( d.dsize > 0 ) */
925
926         } while ((d.dsize > k.val.dsize) && (++retry < MAX_MDBM_RETRY));
927
928         /* LDBM_UNLOCK; */
929
930 #ifdef NO_NULL_KEY
931         free(k.key.dptr);
932 #endif
933
934         return d;
935
936 }
937
938
939
940
941 int
942 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
943 {
944         int     rc;
945         Datum   int_key;        /* Internal key */
946
947 #ifdef MDBM_DEBUG
948         fprintf( stdout,
949                  "==>(mdbm)ldbm_store(db=%p, key(dptr=%p,sz=%d), data(dptr=%p,sz=%d), flags=%x)\n",
950                  ldbm, key.dptr, key.dsize, data.dptr, data.dsize, flags );
951         fflush( stdout );
952 #endif
953
954         /* LDBM_LOCK; */
955
956 #ifdef NO_NULL_KEY
957         int_key.dsize = key.dsize + 1;
958         int_key.dptr = malloc( int_key.dsize );
959         *(int_key.dptr) = 'l';  /* Must not be NULL !*/
960         AC_MEMCPY( (void *)(int_key.dptr + 1), key.dptr, key.dsize );
961 #else
962         int_key = key;
963 #endif
964
965         rc = mdbm_store( ldbm, int_key, data, flags );
966         if ( flags & LDBM_SYNC ) {
967                 mdbm_sync( ldbm );
968         }
969
970         /* LDBM_UNLOCK; */
971
972 #ifdef MDBM_DEBUG
973         fprintf( stdout, "<==(mdbm)ldbm_store(rc=%d)\n", rc );
974         fflush( stdout );
975 #endif
976
977 #ifdef NO_NULL_KEY
978         free(int_key.dptr);
979 #endif
980
981         return( rc );
982
983 }
984
985
986
987 int
988 ldbm_delete( LDBM ldbm, Datum key )
989 {
990         int     rc;
991         Datum   int_key;
992
993         /* LDBM_LOCK; */
994
995 #ifdef NO_NULL_KEY
996         int_key.dsize = key.dsize + 1;
997         int_key.dptr = malloc(int_key.dsize);
998         *(int_key.dptr) = 'l';
999         AC_MEMCPY( (void *)(int_key.dptr + 1), key.dptr, key.dsize );   
1000 #else
1001         int_key = key;
1002 #endif
1003         
1004         rc = mdbm_delete( ldbm, int_key );
1005
1006         /* LDBM_UNLOCK; */
1007 #ifdef NO_NULL_KEY
1008         free(int_key.dptr);
1009 #endif
1010
1011         return( rc );
1012 }
1013
1014
1015
1016
1017 static Datum
1018 ldbm_get_next( LDBM ldbm, kvpair (*fptr)(MDBM *, kvpair) ) 
1019 {
1020         kvpair  out;
1021         kvpair  in;
1022         Datum   ret;
1023         size_t  sz = MDBM_PAGE_SIZE(ldbm);
1024 #ifdef NO_NULL_KEY
1025         int     delta = 1;
1026 #else
1027         int     delta = 0;
1028 #endif
1029
1030         /* LDBM_LOCK; */
1031
1032         in.key.dsize = sz;      /* Assume first key in one pg */
1033         in.key.dptr = malloc(sz);
1034         
1035         in.val.dptr = NULL;     /* Don't need data just key */ 
1036         in.val.dsize = 0;
1037
1038         ret.dptr = NULL;
1039         ret.dsize = NULL;
1040
1041         out = fptr( ldbm, in );
1042
1043         if (out.key.dsize > 0) {
1044                 ret.dsize = out.key.dsize - delta;
1045
1046                 if ((ret.dptr = (char *)malloc(ret.dsize)) == NULL) { 
1047                         ret.dsize = 0;
1048                         ret.dptr = NULL;
1049
1050                 } else {
1051                         AC_MEMCPY(ret.dptr, (void *)(out.key.dptr + delta),
1052                                 ret.dsize );
1053             }
1054         }
1055
1056         /* LDBM_UNLOCK; */
1057         
1058         free(in.key.dptr);
1059         return ret;
1060 }
1061
1062 Datum
1063 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
1064 {
1065         return ldbm_get_next( ldbm, mdbm_first );
1066 }
1067
1068 Datum
1069 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
1070 {
1071         /* XXX:
1072          * don't know if this will affect the LDAP server operation 
1073          * but mdbm cannot take and input key.
1074          */
1075
1076         return ldbm_get_next( ldbm, mdbm_next );
1077 }
1078
1079 int
1080 ldbm_errno( LDBM ldbm )
1081 {
1082         /* XXX: best we can do with current  mdbm interface */
1083         return( errno );
1084 }
1085
1086
1087
1088
1089 #elif defined( HAVE_NDBM )
1090
1091 /*****************************************************************
1092  *                                                               *
1093  * if no gdbm or mdbm, fall back to using ndbm, the standard unix thing  *
1094  *                                                               *
1095  *****************************************************************/
1096
1097 /* ARGSUSED */
1098 LDBM
1099 ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
1100 {
1101         LDBM ldbm;
1102
1103         LDBM_LOCK;
1104         ldbm = dbm_open( name, rw, mode );
1105         LDBM_UNLOCK;
1106
1107         return( ldbm );
1108 }
1109
1110 void
1111 ldbm_close( LDBM ldbm )
1112 {
1113         LDBM_LOCK;
1114         dbm_close( ldbm );
1115         LDBM_UNLOCK;
1116 }
1117
1118 /* ARGSUSED */
1119 void
1120 ldbm_sync( LDBM ldbm )
1121 {
1122         return;
1123 }
1124
1125 Datum
1126 ldbm_fetch( LDBM ldbm, Datum key )
1127 {
1128         Datum d;
1129
1130         LDBM_LOCK;
1131         d = ldbm_datum_dup( ldbm, dbm_fetch( ldbm, key ) );
1132         LDBM_UNLOCK;
1133
1134         return d;
1135 }
1136
1137 int
1138 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
1139 {
1140         int rc;
1141
1142         LDBM_LOCK;
1143         rc = dbm_store( ldbm, key, data, flags );
1144         LDBM_UNLOCK;
1145
1146         return rc;
1147 }
1148
1149 int
1150 ldbm_delete( LDBM ldbm, Datum key )
1151 {
1152         int rc;
1153
1154         LDBM_LOCK;
1155         rc = dbm_delete( ldbm, key );
1156         LDBM_UNLOCK;
1157
1158         return rc;
1159 }
1160
1161 Datum
1162 ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
1163 {
1164         Datum d;
1165
1166         LDBM_LOCK;
1167         d = dbm_firstkey( ldbm );
1168         LDBM_UNLOCK;
1169
1170         return d;
1171 }
1172
1173 Datum
1174 ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
1175 {
1176         Datum d;
1177
1178         LDBM_LOCK;
1179         d = dbm_nextkey( ldbm );
1180         LDBM_UNLOCK;
1181
1182         return d;
1183 }
1184
1185 int
1186 ldbm_errno( LDBM ldbm )
1187 {
1188         int err;
1189
1190         LDBM_LOCK;
1191         err = dbm_error( ldbm );
1192         LDBM_UNLOCK;
1193
1194         return err;
1195 }
1196
1197 #endif /* ndbm */
1198 #endif /* ldbm */