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