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