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