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