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