1 /* attr.c - backend routines for dealing with attributes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2000-2021 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/socket.h>
22 #include <ac/string.h>
23
24 #include "slap.h"
25 #include "back-mdb.h"
26 #include "slap-config.h"
27 #include "lutil.h"
28
29 /* Find the ad, return -1 if not found,
30 * set point for insertion if ins is non-NULL
31 */
32 int
mdb_attr_slot(struct mdb_info * mdb,AttributeDescription * ad,int * ins)33 mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
34 {
35 unsigned base = 0, cursor = 0;
36 unsigned n = mdb->mi_nattrs;
37 int val = 0;
38
39 while ( 0 < n ) {
40 unsigned pivot = n >> 1;
41 cursor = base + pivot;
42
43 val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
44 if ( val < 0 ) {
45 n = pivot;
46 } else if ( val > 0 ) {
47 base = cursor + 1;
48 n -= pivot + 1;
49 } else {
50 return cursor;
51 }
52 }
53 if ( ins ) {
54 if ( val > 0 )
55 ++cursor;
56 *ins = cursor;
57 }
58 return -1;
59 }
60
61 static int
ainfo_insert(struct mdb_info * mdb,AttrInfo * a)62 ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
63 {
64 int x;
65 int i = mdb_attr_slot( mdb, a->ai_desc, &x );
66
67 /* Is it a dup? */
68 if ( i >= 0 )
69 return -1;
70
71 mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
72 sizeof( AttrInfo * ));
73 if ( x < mdb->mi_nattrs )
74 AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
75 ( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
76 mdb->mi_attrs[x] = a;
77 mdb->mi_nattrs++;
78 return 0;
79 }
80
81 AttrInfo *
mdb_attr_mask(struct mdb_info * mdb,AttributeDescription * desc)82 mdb_attr_mask(
83 struct mdb_info *mdb,
84 AttributeDescription *desc )
85 {
86 int i = mdb_attr_slot( mdb, desc, NULL );
87 return i < 0 ? NULL : mdb->mi_attrs[i];
88 }
89
90 /* Open all un-opened index DB handles */
91 int
mdb_attr_dbs_open(BackendDB * be,MDB_txn * tx0,ConfigReply * cr)92 mdb_attr_dbs_open(
93 BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
94 {
95 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
96 MDB_txn *txn;
97 MDB_dbi *dbis = NULL;
98 int i, flags;
99 int rc;
100
101 txn = tx0;
102 if ( txn == NULL ) {
103 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
104 if ( rc ) {
105 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
106 "txn_begin failed: %s (%d).",
107 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
108 Debug( LDAP_DEBUG_ANY,
109 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
110 cr->msg );
111 return rc;
112 }
113 dbis = ch_calloc( 1, mdb->mi_nattrs * sizeof(MDB_dbi) );
114 } else {
115 rc = 0;
116 }
117
118 flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
119 if ( !(slapMode & SLAP_TOOL_READONLY) )
120 flags |= MDB_CREATE;
121
122 for ( i=0; i<mdb->mi_nattrs; i++ ) {
123 if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
124 continue;
125 if ( !( mdb->mi_attrs[i]->ai_indexmask || mdb->mi_attrs[i]->ai_newmask )) /* not an index record */
126 continue;
127 rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
128 flags, &mdb->mi_attrs[i]->ai_dbi );
129 if ( rc ) {
130 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
131 "mdb_dbi_open(%s) failed: %s (%d).",
132 be->be_suffix[0].bv_val,
133 mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
134 mdb_strerror(rc), rc );
135 Debug( LDAP_DEBUG_ANY,
136 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
137 cr->msg );
138 break;
139 }
140 /* Remember newly opened DBI handles */
141 if ( dbis )
142 dbis[i] = mdb->mi_attrs[i]->ai_dbi;
143 }
144
145 /* Only commit if this is our txn */
146 if ( tx0 == NULL ) {
147 if ( !rc ) {
148 rc = mdb_txn_commit( txn );
149 if ( rc ) {
150 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
151 "txn_commit failed: %s (%d).",
152 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
153 Debug( LDAP_DEBUG_ANY,
154 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
155 cr->msg );
156 }
157 } else {
158 mdb_txn_abort( txn );
159 }
160 /* Something failed, forget anything we just opened */
161 if ( rc ) {
162 for ( i=0; i<mdb->mi_nattrs; i++ ) {
163 if ( dbis[i] ) {
164 mdb->mi_attrs[i]->ai_dbi = 0;
165 mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
166 }
167 }
168 mdb_attr_flush( mdb );
169 }
170 ch_free( dbis );
171 }
172
173 return rc;
174 }
175
176 void
mdb_attr_dbs_close(struct mdb_info * mdb)177 mdb_attr_dbs_close(
178 struct mdb_info *mdb
179 )
180 {
181 int i;
182 for ( i=0; i<mdb->mi_nattrs; i++ )
183 if ( mdb->mi_attrs[i]->ai_dbi ) {
184 mdb_dbi_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
185 mdb->mi_attrs[i]->ai_dbi = 0;
186 }
187 }
188
189 int
mdb_attr_index_config(struct mdb_info * mdb,const char * fname,int lineno,int argc,char ** argv,struct config_reply_s * c_reply)190 mdb_attr_index_config(
191 struct mdb_info *mdb,
192 const char *fname,
193 int lineno,
194 int argc,
195 char **argv,
196 struct config_reply_s *c_reply)
197 {
198 int rc = 0;
199 int i;
200 slap_mask_t mask;
201 char **attrs;
202 char **indexes = NULL;
203
204 attrs = ldap_str2charray( argv[0], "," );
205
206 if( attrs == NULL ) {
207 fprintf( stderr, "%s: line %d: "
208 "no attributes specified: %s\n",
209 fname, lineno, argv[0] );
210 return LDAP_PARAM_ERROR;
211 }
212
213 if ( argc > 1 ) {
214 indexes = ldap_str2charray( argv[1], "," );
215
216 if( indexes == NULL ) {
217 fprintf( stderr, "%s: line %d: "
218 "no indexes specified: %s\n",
219 fname, lineno, argv[1] );
220 rc = LDAP_PARAM_ERROR;
221 goto done;
222 }
223 }
224
225 if( indexes == NULL ) {
226 mask = mdb->mi_defaultmask;
227
228 } else {
229 mask = 0;
230
231 for ( i = 0; indexes[i] != NULL; i++ ) {
232 slap_mask_t index;
233 rc = slap_str2index( indexes[i], &index );
234
235 if( rc != LDAP_SUCCESS ) {
236 if ( c_reply )
237 {
238 snprintf(c_reply->msg, sizeof(c_reply->msg),
239 "index type \"%s\" undefined", indexes[i] );
240
241 fprintf( stderr, "%s: line %d: %s\n",
242 fname, lineno, c_reply->msg );
243 }
244 rc = LDAP_PARAM_ERROR;
245 goto done;
246 }
247
248 mask |= index;
249 }
250 }
251
252 if( !mask ) {
253 if ( c_reply )
254 {
255 snprintf(c_reply->msg, sizeof(c_reply->msg),
256 "no indexes selected" );
257 fprintf( stderr, "%s: line %d: %s\n",
258 fname, lineno, c_reply->msg );
259 }
260 rc = LDAP_PARAM_ERROR;
261 goto done;
262 }
263
264 for ( i = 0; attrs[i] != NULL; i++ ) {
265 AttrInfo *a;
266 AttributeDescription *ad;
267 const char *text;
268 #ifdef LDAP_COMP_MATCH
269 ComponentReference* cr = NULL;
270 AttrInfo *a_cr = NULL;
271 #endif
272
273 if( strcasecmp( attrs[i], "default" ) == 0 ) {
274 mdb->mi_defaultmask |= mask;
275 continue;
276 }
277
278 #ifdef LDAP_COMP_MATCH
279 if ( is_component_reference( attrs[i] ) ) {
280 rc = extract_component_reference( attrs[i], &cr );
281 if ( rc != LDAP_SUCCESS ) {
282 if ( c_reply )
283 {
284 snprintf(c_reply->msg, sizeof(c_reply->msg),
285 "index component reference\"%s\" undefined",
286 attrs[i] );
287 fprintf( stderr, "%s: line %d: %s\n",
288 fname, lineno, c_reply->msg );
289 }
290 goto done;
291 }
292 cr->cr_indexmask = mask;
293 /*
294 * After extracting a component reference
295 * only the name of a attribute will be remaining
296 */
297 } else {
298 cr = NULL;
299 }
300 #endif
301 ad = NULL;
302 rc = slap_str2ad( attrs[i], &ad, &text );
303
304 if( rc != LDAP_SUCCESS ) {
305 if ( c_reply )
306 {
307 snprintf(c_reply->msg, sizeof(c_reply->msg),
308 "index attribute \"%s\" undefined",
309 attrs[i] );
310
311 fprintf( stderr, "%s: line %d: %s\n",
312 fname, lineno, c_reply->msg );
313 }
314 fail:
315 #ifdef LDAP_COMP_MATCH
316 ch_free( cr );
317 #endif
318 goto done;
319 }
320
321 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
322 if (c_reply) {
323 snprintf(c_reply->msg, sizeof(c_reply->msg),
324 "index of attribute \"%s\" disallowed", attrs[i] );
325 fprintf( stderr, "%s: line %d: %s\n",
326 fname, lineno, c_reply->msg );
327 }
328 rc = LDAP_UNWILLING_TO_PERFORM;
329 goto fail;
330 }
331
332 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
333 ad->ad_type->sat_approx
334 && ad->ad_type->sat_approx->smr_indexer
335 && ad->ad_type->sat_approx->smr_filter ) )
336 {
337 if (c_reply) {
338 snprintf(c_reply->msg, sizeof(c_reply->msg),
339 "approx index of attribute \"%s\" disallowed", attrs[i] );
340 fprintf( stderr, "%s: line %d: %s\n",
341 fname, lineno, c_reply->msg );
342 }
343 rc = LDAP_INAPPROPRIATE_MATCHING;
344 goto fail;
345 }
346
347 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
348 ad->ad_type->sat_equality
349 && ad->ad_type->sat_equality->smr_indexer
350 && ad->ad_type->sat_equality->smr_filter ) )
351 {
352 if (c_reply) {
353 snprintf(c_reply->msg, sizeof(c_reply->msg),
354 "equality index of attribute \"%s\" disallowed", attrs[i] );
355 fprintf( stderr, "%s: line %d: %s\n",
356 fname, lineno, c_reply->msg );
357 }
358 rc = LDAP_INAPPROPRIATE_MATCHING;
359 goto fail;
360 }
361
362 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
363 ad->ad_type->sat_substr
364 && ad->ad_type->sat_substr->smr_indexer
365 && ad->ad_type->sat_substr->smr_filter ) )
366 {
367 if (c_reply) {
368 snprintf(c_reply->msg, sizeof(c_reply->msg),
369 "substr index of attribute \"%s\" disallowed", attrs[i] );
370 fprintf( stderr, "%s: line %d: %s\n",
371 fname, lineno, c_reply->msg );
372 }
373 rc = LDAP_INAPPROPRIATE_MATCHING;
374 goto fail;
375 }
376
377 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
378 ad->ad_cname.bv_val, mask );
379
380 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
381
382 #ifdef LDAP_COMP_MATCH
383 a->ai_cr = NULL;
384 #endif
385 a->ai_cursor = NULL;
386 a->ai_root = NULL;
387 a->ai_desc = ad;
388 a->ai_dbi = 0;
389 a->ai_multi_hi = UINT_MAX;
390 a->ai_multi_lo = UINT_MAX;
391
392 if ( mdb->mi_flags & MDB_IS_OPEN ) {
393 a->ai_indexmask = 0;
394 a->ai_newmask = mask;
395 } else {
396 a->ai_indexmask = mask;
397 a->ai_newmask = 0;
398 }
399
400 #ifdef LDAP_COMP_MATCH
401 if ( cr ) {
402 a_cr = mdb_attr_mask( mdb, ad );
403 if ( a_cr ) {
404 /*
405 * AttrInfo is already in AVL
406 * just add the extracted component reference
407 * in the AttrInfo
408 */
409 ch_free( a );
410 rc = insert_component_reference( cr, &a_cr->ai_cr );
411 if ( rc != LDAP_SUCCESS) {
412 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
413 rc = LDAP_PARAM_ERROR;
414 goto fail;
415 }
416 continue;
417 } else {
418 rc = insert_component_reference( cr, &a->ai_cr );
419 if ( rc != LDAP_SUCCESS) {
420 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
421 rc = LDAP_PARAM_ERROR;
422 ch_free( a );
423 goto fail;
424 }
425 }
426 }
427 #endif
428 rc = ainfo_insert( mdb, a );
429 if( rc ) {
430 AttrInfo *b = mdb_attr_mask( mdb, ad );
431 /* If this is just a multival record, reuse it for index info */
432 if ( !( b->ai_indexmask || b->ai_newmask ) && b->ai_multi_lo < UINT_MAX ) {
433 b->ai_indexmask = a->ai_indexmask;
434 b->ai_newmask = a->ai_newmask;
435 ch_free( a );
436 rc = 0;
437 continue;
438 }
439 if ( mdb->mi_flags & MDB_IS_OPEN ) {
440 /* If there is already an index defined for this attribute
441 * it must be replaced. Otherwise we end up with multiple
442 * olcIndex values for the same attribute */
443 if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
444 /* If we were editing this attr, reset it */
445 b->ai_indexmask &= ~MDB_INDEX_DELETING;
446 /* If this is leftover from a previous add, commit it */
447 if ( b->ai_newmask )
448 b->ai_indexmask = b->ai_newmask;
449 b->ai_newmask = a->ai_newmask;
450 ch_free( a );
451 rc = 0;
452 continue;
453 }
454 }
455 if (c_reply) {
456 snprintf(c_reply->msg, sizeof(c_reply->msg),
457 "duplicate index definition for attr \"%s\"",
458 attrs[i] );
459 fprintf( stderr, "%s: line %d: %s\n",
460 fname, lineno, c_reply->msg );
461 }
462
463 rc = LDAP_PARAM_ERROR;
464 goto done;
465 }
466 }
467
468 done:
469 ldap_charray_free( attrs );
470 if ( indexes != NULL ) ldap_charray_free( indexes );
471
472 return rc;
473 }
474
475 static int
mdb_attr_index_unparser(void * v1,void * v2)476 mdb_attr_index_unparser( void *v1, void *v2 )
477 {
478 AttrInfo *ai = v1;
479 BerVarray *bva = v2;
480 struct berval bv;
481 char *ptr;
482
483 slap_index2bvlen( ai->ai_indexmask, &bv );
484 if ( bv.bv_len ) {
485 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
486 ptr = ch_malloc( bv.bv_len+1 );
487 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
488 *bv.bv_val++ = ' ';
489 slap_index2bv( ai->ai_indexmask, &bv );
490 bv.bv_val = ptr;
491 ber_bvarray_add( bva, &bv );
492 }
493 return 0;
494 }
495
496 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
497 static AttrInfo aidef = { &addef };
498
499 void
mdb_attr_index_unparse(struct mdb_info * mdb,BerVarray * bva)500 mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
501 {
502 int i;
503
504 if ( mdb->mi_defaultmask ) {
505 aidef.ai_indexmask = mdb->mi_defaultmask;
506 mdb_attr_index_unparser( &aidef, bva );
507 }
508 for ( i=0; i<mdb->mi_nattrs; i++ )
509 if ( mdb->mi_attrs[i]->ai_indexmask )
510 mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
511 }
512
513 int
mdb_attr_multi_config(struct mdb_info * mdb,const char * fname,int lineno,int argc,char ** argv,struct config_reply_s * c_reply)514 mdb_attr_multi_config(
515 struct mdb_info *mdb,
516 const char *fname,
517 int lineno,
518 int argc,
519 char **argv,
520 struct config_reply_s *c_reply)
521 {
522 int rc = 0;
523 int i;
524 unsigned hi,lo;
525 char **attrs, *next, *s;
526
527 attrs = ldap_str2charray( argv[0], "," );
528
529 if( attrs == NULL ) {
530 fprintf( stderr, "%s: line %d: "
531 "no attributes specified: %s\n",
532 fname, lineno, argv[0] );
533 return LDAP_PARAM_ERROR;
534 }
535
536 hi = strtoul( argv[1], &next, 10 );
537 if ( next == argv[1] || next[0] != ',' )
538 goto badval;
539 s = next+1;
540 lo = strtoul( s, &next, 10 );
541 if ( next == s || next[0] != '\0' )
542 goto badval;
543
544 if ( lo > hi ) {
545 badval:
546 snprintf(c_reply->msg, sizeof(c_reply->msg),
547 "invalid hi/lo thresholds" );
548 fprintf( stderr, "%s: line %d: %s\n",
549 fname, lineno, c_reply->msg );
550 return LDAP_PARAM_ERROR;
551 }
552
553 for ( i = 0; attrs[i] != NULL; i++ ) {
554 AttrInfo *a;
555 AttributeDescription *ad;
556 const char *text;
557
558 if( strcasecmp( attrs[i], "default" ) == 0 ) {
559 mdb->mi_multi_hi = hi;
560 mdb->mi_multi_lo = lo;
561 continue;
562 }
563
564 ad = NULL;
565 rc = slap_str2ad( attrs[i], &ad, &text );
566
567 if( rc != LDAP_SUCCESS ) {
568 if ( c_reply )
569 {
570 snprintf(c_reply->msg, sizeof(c_reply->msg),
571 "multival attribute \"%s\" undefined",
572 attrs[i] );
573
574 fprintf( stderr, "%s: line %d: %s\n",
575 fname, lineno, c_reply->msg );
576 }
577 fail:
578 goto done;
579 }
580
581 a = (AttrInfo *) ch_calloc( 1, sizeof(AttrInfo) );
582
583 a->ai_desc = ad;
584 a->ai_multi_hi = hi;
585 a->ai_multi_lo = lo;
586
587 rc = ainfo_insert( mdb, a );
588 if( rc ) {
589 AttrInfo *b = mdb_attr_mask( mdb, ad );
590 /* If this is just an index record, reuse it for multival info */
591 if ( b->ai_multi_lo == UINT_MAX ) {
592 b->ai_multi_hi = a->ai_multi_hi;
593 b->ai_multi_lo = a->ai_multi_lo;
594 ch_free( a );
595 rc = 0;
596 continue;
597 }
598 if (c_reply) {
599 snprintf(c_reply->msg, sizeof(c_reply->msg),
600 "duplicate multival definition for attr \"%s\"",
601 attrs[i] );
602 fprintf( stderr, "%s: line %d: %s\n",
603 fname, lineno, c_reply->msg );
604 }
605
606 rc = LDAP_PARAM_ERROR;
607 goto done;
608 }
609 }
610
611 done:
612 ldap_charray_free( attrs );
613
614 return rc;
615 }
616
617 static int
mdb_attr_multi_unparser(void * v1,void * v2)618 mdb_attr_multi_unparser( void *v1, void *v2 )
619 {
620 AttrInfo *ai = v1;
621 BerVarray *bva = v2;
622 struct berval bv;
623 char digbuf[sizeof("4294967296,4294967296")];
624 char *ptr;
625
626 bv.bv_len = snprintf( digbuf, sizeof(digbuf), "%u,%u",
627 ai->ai_multi_hi, ai->ai_multi_lo );
628 if ( bv.bv_len ) {
629 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
630 ptr = ch_malloc( bv.bv_len+1 );
631 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
632 *bv.bv_val++ = ' ';
633 strcpy(bv.bv_val, digbuf);
634 bv.bv_val = ptr;
635 ber_bvarray_add( bva, &bv );
636 }
637 return 0;
638 }
639
640 void
mdb_attr_multi_unparse(struct mdb_info * mdb,BerVarray * bva)641 mdb_attr_multi_unparse( struct mdb_info *mdb, BerVarray *bva )
642 {
643 int i;
644
645 if ( mdb->mi_multi_hi < UINT_MAX ) {
646 aidef.ai_multi_hi = mdb->mi_multi_hi;
647 aidef.ai_multi_lo = mdb->mi_multi_lo;
648 mdb_attr_multi_unparser( &aidef, bva );
649 }
650 for ( i=0; i<mdb->mi_nattrs; i++ )
651 if ( mdb->mi_attrs[i]->ai_multi_hi < UINT_MAX )
652 mdb_attr_multi_unparser( mdb->mi_attrs[i], bva );
653 }
654
655 void
mdb_attr_multi_thresh(struct mdb_info * mdb,AttributeDescription * ad,unsigned * hi,unsigned * lo)656 mdb_attr_multi_thresh( struct mdb_info *mdb, AttributeDescription *ad, unsigned *hi, unsigned *lo )
657 {
658 AttrInfo *ai = mdb_attr_mask( mdb, ad );
659 if ( ai && ai->ai_multi_hi < UINT_MAX )
660 {
661 if ( hi )
662 *hi = ai->ai_multi_hi;
663 if ( lo )
664 *lo = ai->ai_multi_lo;
665 } else
666 {
667 if ( hi )
668 *hi = mdb->mi_multi_hi;
669 if ( lo )
670 *lo = mdb->mi_multi_lo;
671 }
672 }
673
674 void
mdb_attr_info_free(AttrInfo * ai)675 mdb_attr_info_free( AttrInfo *ai )
676 {
677 #ifdef LDAP_COMP_MATCH
678 free( ai->ai_cr );
679 #endif
680 free( ai );
681 }
682
683 void
mdb_attr_index_destroy(struct mdb_info * mdb)684 mdb_attr_index_destroy( struct mdb_info *mdb )
685 {
686 int i;
687
688 for ( i=0; i<mdb->mi_nattrs; i++ )
689 mdb_attr_info_free( mdb->mi_attrs[i] );
690
691 free( mdb->mi_attrs );
692 }
693
mdb_attr_index_free(struct mdb_info * mdb,AttributeDescription * ad)694 void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
695 {
696 int i;
697
698 i = mdb_attr_slot( mdb, ad, NULL );
699 if ( i >= 0 ) {
700 mdb_attr_info_free( mdb->mi_attrs[i] );
701 mdb->mi_nattrs--;
702 for (; i<mdb->mi_nattrs; i++)
703 mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
704 }
705 }
706
mdb_attr_flush(struct mdb_info * mdb)707 void mdb_attr_flush( struct mdb_info *mdb )
708 {
709 int i;
710
711 for ( i=0; i<mdb->mi_nattrs; i++ ) {
712 if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
713 /* if this is also a multival rec, just clear index */
714 if ( mdb->mi_attrs[i]->ai_multi_lo < UINT_MAX ) {
715 mdb->mi_attrs[i]->ai_indexmask = 0;
716 mdb->mi_attrs[i]->ai_newmask = 0;
717 } else {
718 int j;
719 mdb_attr_info_free( mdb->mi_attrs[i] );
720 mdb->mi_nattrs--;
721 for (j=i; j<mdb->mi_nattrs; j++)
722 mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
723 i--;
724 }
725 }
726 }
727 }
728
mdb_ad_read(struct mdb_info * mdb,MDB_txn * txn)729 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
730 {
731 int i, rc;
732 MDB_cursor *mc;
733 MDB_val key, data;
734 struct berval bdata;
735 const char *text;
736 AttributeDescription *ad;
737
738 rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
739 if ( rc ) {
740 Debug( LDAP_DEBUG_ANY,
741 "mdb_ad_read: cursor_open failed %s(%d)\n",
742 mdb_strerror(rc), rc );
743 return rc;
744 }
745
746 /* our array is 1-based, an index of 0 means no data */
747 i = mdb->mi_numads+1;
748 key.mv_size = sizeof(int);
749 key.mv_data = &i;
750
751 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
752
753 while ( rc == MDB_SUCCESS ) {
754 bdata.bv_len = data.mv_size;
755 bdata.bv_val = data.mv_data;
756 ad = NULL;
757 rc = slap_bv2ad( &bdata, &ad, &text );
758 if ( rc ) {
759 rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
760 } else {
761 if ( ad->ad_index >= MDB_MAXADS ) {
762 Debug( LDAP_DEBUG_ANY,
763 "mdb_adb_read: too many AttributeDescriptions in use\n" );
764 return LDAP_OTHER;
765 }
766 mdb->mi_adxs[ad->ad_index] = i;
767 mdb->mi_ads[i] = ad;
768 }
769 i++;
770 rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
771 }
772 mdb->mi_numads = i-1;
773
774 done:
775 if ( rc == MDB_NOTFOUND )
776 rc = 0;
777
778 mdb_cursor_close( mc );
779
780 return rc;
781 }
782
mdb_ad_get(struct mdb_info * mdb,MDB_txn * txn,AttributeDescription * ad)783 int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
784 {
785 int i, rc;
786 MDB_val key, val;
787
788 rc = mdb_ad_read( mdb, txn );
789 if (rc)
790 return rc;
791
792 if ( mdb->mi_adxs[ad->ad_index] )
793 return 0;
794
795 i = mdb->mi_numads+1;
796 key.mv_size = sizeof(int);
797 key.mv_data = &i;
798 val.mv_size = ad->ad_cname.bv_len;
799 val.mv_data = ad->ad_cname.bv_val;
800
801 rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
802 if ( rc == MDB_SUCCESS ) {
803 mdb->mi_adxs[ad->ad_index] = i;
804 mdb->mi_ads[i] = ad;
805 mdb->mi_numads = i;
806 } else {
807 Debug( LDAP_DEBUG_ANY,
808 "mdb_ad_get: mdb_put failed %s(%d)\n",
809 mdb_strerror(rc), rc );
810 }
811
812 return rc;
813 }
814
mdb_ad_unwind(struct mdb_info * mdb,int prev_ads)815 void mdb_ad_unwind( struct mdb_info *mdb, int prev_ads )
816 {
817 int i;
818
819 for (i=mdb->mi_numads; i>prev_ads; i--) {
820 mdb->mi_adxs[mdb->mi_ads[i]->ad_index] = 0;
821 mdb->mi_ads[i] = NULL;
822 }
823 mdb->mi_numads = i;
824 }
825