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