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