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