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