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