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