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