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