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