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