1 /* $NetBSD: modify.c,v 1.1.1.1 2014/05/28 09:58:50 tron Exp $ */ 2 3 /* modify.c - mdb backend modify routine */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2014 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 "portable.h" 20 21 #include <stdio.h> 22 #include <ac/string.h> 23 #include <ac/time.h> 24 25 #include "back-mdb.h" 26 27 static struct berval scbva[] = { 28 BER_BVC("glue"), 29 BER_BVNULL 30 }; 31 32 static void 33 mdb_modify_idxflags( 34 Operation *op, 35 AttributeDescription *desc, 36 int got_delete, 37 Attribute *newattrs, 38 Attribute *oldattrs ) 39 { 40 struct berval ix_at; 41 AttrInfo *ai; 42 43 /* check if modified attribute was indexed 44 * but not in case of NOOP... */ 45 ai = mdb_index_mask( op->o_bd, desc, &ix_at ); 46 if ( ai ) { 47 if ( got_delete ) { 48 Attribute *ap; 49 struct berval ix2; 50 51 ap = attr_find( oldattrs, desc ); 52 if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL; 53 54 /* Find all other attrs that index to same slot */ 55 for ( ap = newattrs; ap; ap = ap->a_next ) { 56 ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 ); 57 if ( ai && ix2.bv_val == ix_at.bv_val ) 58 ap->a_flags |= SLAP_ATTR_IXADD; 59 } 60 61 } else { 62 Attribute *ap; 63 64 ap = attr_find( newattrs, desc ); 65 if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD; 66 } 67 } 68 } 69 70 int mdb_modify_internal( 71 Operation *op, 72 MDB_txn *tid, 73 Modifications *modlist, 74 Entry *e, 75 const char **text, 76 char *textbuf, 77 size_t textlen ) 78 { 79 int rc, err; 80 Modification *mod; 81 Modifications *ml; 82 Attribute *save_attrs; 83 Attribute *ap; 84 int glue_attr_delete = 0; 85 int got_delete; 86 87 Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n", 88 e->e_id, e->e_dn, 0); 89 90 if ( !acl_check_modlist( op, e, modlist )) { 91 return LDAP_INSUFFICIENT_ACCESS; 92 } 93 94 /* save_attrs will be disposed of by caller */ 95 save_attrs = e->e_attrs; 96 e->e_attrs = attrs_dup( e->e_attrs ); 97 98 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 99 int match; 100 mod = &ml->sml_mod; 101 switch( mod->sm_op ) { 102 case LDAP_MOD_ADD: 103 case LDAP_MOD_REPLACE: 104 if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) { 105 value_match( &match, slap_schema.si_ad_structuralObjectClass, 106 slap_schema.si_ad_structuralObjectClass-> 107 ad_type->sat_equality, 108 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 109 &mod->sm_values[0], &scbva[0], text ); 110 if ( !match ) glue_attr_delete = 1; 111 } 112 } 113 if ( glue_attr_delete ) 114 break; 115 } 116 117 if ( glue_attr_delete ) { 118 Attribute **app = &e->e_attrs; 119 while ( *app != NULL ) { 120 if ( !is_at_operational( (*app)->a_desc->ad_type )) { 121 Attribute *save = *app; 122 *app = (*app)->a_next; 123 attr_free( save ); 124 continue; 125 } 126 app = &(*app)->a_next; 127 } 128 } 129 130 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 131 mod = &ml->sml_mod; 132 got_delete = 0; 133 134 switch ( mod->sm_op ) { 135 case LDAP_MOD_ADD: 136 Debug(LDAP_DEBUG_ARGS, 137 "mdb_modify_internal: add %s\n", 138 mod->sm_desc->ad_cname.bv_val, 0, 0); 139 err = modify_add_values( e, mod, get_permissiveModify(op), 140 text, textbuf, textlen ); 141 if( err != LDAP_SUCCESS ) { 142 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 143 err, *text, 0); 144 } 145 break; 146 147 case LDAP_MOD_DELETE: 148 if ( glue_attr_delete ) { 149 err = LDAP_SUCCESS; 150 break; 151 } 152 153 Debug(LDAP_DEBUG_ARGS, 154 "mdb_modify_internal: delete %s\n", 155 mod->sm_desc->ad_cname.bv_val, 0, 0); 156 err = modify_delete_values( e, mod, get_permissiveModify(op), 157 text, textbuf, textlen ); 158 if( err != LDAP_SUCCESS ) { 159 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 160 err, *text, 0); 161 } else { 162 got_delete = 1; 163 } 164 break; 165 166 case LDAP_MOD_REPLACE: 167 Debug(LDAP_DEBUG_ARGS, 168 "mdb_modify_internal: replace %s\n", 169 mod->sm_desc->ad_cname.bv_val, 0, 0); 170 err = modify_replace_values( e, mod, get_permissiveModify(op), 171 text, textbuf, textlen ); 172 if( err != LDAP_SUCCESS ) { 173 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 174 err, *text, 0); 175 } else { 176 got_delete = 1; 177 } 178 break; 179 180 case LDAP_MOD_INCREMENT: 181 Debug(LDAP_DEBUG_ARGS, 182 "mdb_modify_internal: increment %s\n", 183 mod->sm_desc->ad_cname.bv_val, 0, 0); 184 err = modify_increment_values( e, mod, get_permissiveModify(op), 185 text, textbuf, textlen ); 186 if( err != LDAP_SUCCESS ) { 187 Debug(LDAP_DEBUG_ARGS, 188 "mdb_modify_internal: %d %s\n", 189 err, *text, 0); 190 } else { 191 got_delete = 1; 192 } 193 break; 194 195 case SLAP_MOD_SOFTADD: 196 Debug(LDAP_DEBUG_ARGS, 197 "mdb_modify_internal: softadd %s\n", 198 mod->sm_desc->ad_cname.bv_val, 0, 0); 199 /* Avoid problems in index_add_mods() 200 * We need to add index if necessary. 201 */ 202 mod->sm_op = LDAP_MOD_ADD; 203 204 err = modify_add_values( e, mod, get_permissiveModify(op), 205 text, textbuf, textlen ); 206 207 mod->sm_op = SLAP_MOD_SOFTADD; 208 209 if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { 210 err = LDAP_SUCCESS; 211 } 212 213 if( err != LDAP_SUCCESS ) { 214 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 215 err, *text, 0); 216 } 217 break; 218 219 case SLAP_MOD_SOFTDEL: 220 Debug(LDAP_DEBUG_ARGS, 221 "mdb_modify_internal: softdel %s\n", 222 mod->sm_desc->ad_cname.bv_val, 0, 0); 223 /* Avoid problems in index_delete_mods() 224 * We need to add index if necessary. 225 */ 226 mod->sm_op = LDAP_MOD_DELETE; 227 228 err = modify_delete_values( e, mod, get_permissiveModify(op), 229 text, textbuf, textlen ); 230 231 mod->sm_op = SLAP_MOD_SOFTDEL; 232 233 if ( err == LDAP_SUCCESS ) { 234 got_delete = 1; 235 } else if ( err == LDAP_NO_SUCH_ATTRIBUTE ) { 236 err = LDAP_SUCCESS; 237 } 238 239 if( err != LDAP_SUCCESS ) { 240 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 241 err, *text, 0); 242 } 243 break; 244 245 case SLAP_MOD_ADD_IF_NOT_PRESENT: 246 if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) { 247 /* skip */ 248 err = LDAP_SUCCESS; 249 break; 250 } 251 252 Debug(LDAP_DEBUG_ARGS, 253 "mdb_modify_internal: add_if_not_present %s\n", 254 mod->sm_desc->ad_cname.bv_val, 0, 0); 255 /* Avoid problems in index_add_mods() 256 * We need to add index if necessary. 257 */ 258 mod->sm_op = LDAP_MOD_ADD; 259 260 err = modify_add_values( e, mod, get_permissiveModify(op), 261 text, textbuf, textlen ); 262 263 mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; 264 265 if( err != LDAP_SUCCESS ) { 266 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 267 err, *text, 0); 268 } 269 break; 270 271 default: 272 Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n", 273 mod->sm_op, 0, 0); 274 *text = "Invalid modify operation"; 275 err = LDAP_OTHER; 276 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 277 err, *text, 0); 278 } 279 280 if ( err != LDAP_SUCCESS ) { 281 attrs_free( e->e_attrs ); 282 e->e_attrs = save_attrs; 283 /* unlock entry, delete from cache */ 284 return err; 285 } 286 287 /* If objectClass was modified, reset the flags */ 288 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { 289 e->e_ocflags = 0; 290 } 291 292 if ( glue_attr_delete ) e->e_ocflags = 0; 293 294 295 /* check if modified attribute was indexed 296 * but not in case of NOOP... */ 297 if ( !op->o_noop ) { 298 mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs ); 299 } 300 } 301 302 /* check that the entry still obeys the schema */ 303 ap = NULL; 304 rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap, 305 text, textbuf, textlen ); 306 if ( rc != LDAP_SUCCESS || op->o_noop ) { 307 attrs_free( e->e_attrs ); 308 /* clear the indexing flags */ 309 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { 310 ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL); 311 } 312 e->e_attrs = save_attrs; 313 314 if ( rc != LDAP_SUCCESS ) { 315 Debug( LDAP_DEBUG_ANY, 316 "entry failed schema check: %s\n", 317 *text, 0, 0 ); 318 } 319 320 /* if NOOP then silently revert to saved attrs */ 321 return rc; 322 } 323 324 /* structuralObjectClass modified! */ 325 if ( ap ) { 326 assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass ); 327 if ( !op->o_noop ) { 328 mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass, 329 1, e->e_attrs, save_attrs ); 330 } 331 } 332 333 /* update the indices of the modified attributes */ 334 335 /* start with deleting the old index entries */ 336 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { 337 if ( ap->a_flags & SLAP_ATTR_IXDEL ) { 338 struct berval *vals; 339 Attribute *a2; 340 ap->a_flags &= ~SLAP_ATTR_IXDEL; 341 a2 = attr_find( e->e_attrs, ap->a_desc ); 342 if ( a2 ) { 343 /* need to detect which values were deleted */ 344 int i, j; 345 /* let add know there were deletes */ 346 if ( a2->a_flags & SLAP_ATTR_IXADD ) 347 a2->a_flags |= SLAP_ATTR_IXDEL; 348 vals = op->o_tmpalloc( (ap->a_numvals + 1) * 349 sizeof(struct berval), op->o_tmpmemctx ); 350 j = 0; 351 for ( i=0; i < ap->a_numvals; i++ ) { 352 rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 353 &ap->a_nvals[i], NULL, op->o_tmpmemctx ); 354 /* Save deleted values */ 355 if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) 356 vals[j++] = ap->a_nvals[i]; 357 } 358 BER_BVZERO(vals+j); 359 } else { 360 /* attribute was completely deleted */ 361 vals = ap->a_nvals; 362 } 363 rc = 0; 364 if ( !BER_BVISNULL( vals )) { 365 rc = mdb_index_values( op, tid, ap->a_desc, 366 vals, e->e_id, SLAP_INDEX_DELETE_OP ); 367 if ( rc != LDAP_SUCCESS ) { 368 Debug( LDAP_DEBUG_ANY, 369 "%s: attribute \"%s\" index delete failure\n", 370 op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); 371 attrs_free( e->e_attrs ); 372 e->e_attrs = save_attrs; 373 } 374 } 375 if ( vals != ap->a_nvals ) 376 op->o_tmpfree( vals, op->o_tmpmemctx ); 377 if ( rc ) return rc; 378 } 379 } 380 381 /* add the new index entries */ 382 for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { 383 if (ap->a_flags & SLAP_ATTR_IXADD) { 384 ap->a_flags &= ~SLAP_ATTR_IXADD; 385 if ( ap->a_flags & SLAP_ATTR_IXDEL ) { 386 /* if any values were deleted, we must readd index 387 * for all remaining values. 388 */ 389 ap->a_flags &= ~SLAP_ATTR_IXDEL; 390 rc = mdb_index_values( op, tid, ap->a_desc, 391 ap->a_nvals, 392 e->e_id, SLAP_INDEX_ADD_OP ); 393 } else { 394 int found = 0; 395 /* if this was only an add, we only need to index 396 * the added values. 397 */ 398 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 399 struct berval *vals; 400 if ( ml->sml_desc != ap->a_desc || !ml->sml_numvals ) 401 continue; 402 found = 1; 403 switch( ml->sml_op ) { 404 case LDAP_MOD_ADD: 405 case LDAP_MOD_REPLACE: 406 case LDAP_MOD_INCREMENT: 407 case SLAP_MOD_SOFTADD: 408 case SLAP_MOD_ADD_IF_NOT_PRESENT: 409 if ( ml->sml_op == LDAP_MOD_INCREMENT ) 410 vals = ap->a_nvals; 411 else if ( ml->sml_nvalues ) 412 vals = ml->sml_nvalues; 413 else 414 vals = ml->sml_values; 415 rc = mdb_index_values( op, tid, ap->a_desc, 416 vals, e->e_id, SLAP_INDEX_ADD_OP ); 417 break; 418 } 419 if ( rc ) 420 break; 421 } 422 /* This attr was affected by a modify of a subtype, so 423 * there was no direct match in the modlist. Just readd 424 * all of its values. 425 */ 426 if ( !found ) { 427 rc = mdb_index_values( op, tid, ap->a_desc, 428 ap->a_nvals, 429 e->e_id, SLAP_INDEX_ADD_OP ); 430 } 431 } 432 if ( rc != LDAP_SUCCESS ) { 433 Debug( LDAP_DEBUG_ANY, 434 "%s: attribute \"%s\" index add failure\n", 435 op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); 436 attrs_free( e->e_attrs ); 437 e->e_attrs = save_attrs; 438 return rc; 439 } 440 } 441 } 442 443 return rc; 444 } 445 446 447 int 448 mdb_modify( Operation *op, SlapReply *rs ) 449 { 450 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 451 Entry *e = NULL; 452 int manageDSAit = get_manageDSAit( op ); 453 char textbuf[SLAP_TEXT_BUFLEN]; 454 size_t textlen = sizeof textbuf; 455 MDB_txn *txn = NULL; 456 mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo; 457 Entry dummy = {0}; 458 459 LDAPControl **preread_ctrl = NULL; 460 LDAPControl **postread_ctrl = NULL; 461 LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; 462 int num_ctrls = 0; 463 464 #ifdef LDAP_X_TXN 465 int settle = 0; 466 #endif 467 468 Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(mdb_modify) ": %s\n", 469 op->o_req_dn.bv_val, 0, 0 ); 470 471 #ifdef LDAP_X_TXN 472 if( op->o_txnSpec ) { 473 /* acquire connection lock */ 474 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 475 if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { 476 rs->sr_text = "invalid transaction identifier"; 477 rs->sr_err = LDAP_X_TXN_ID_INVALID; 478 goto txnReturn; 479 } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { 480 settle=1; 481 goto txnReturn; 482 } 483 484 if( op->o_conn->c_txn_backend == NULL ) { 485 op->o_conn->c_txn_backend = op->o_bd; 486 487 } else if( op->o_conn->c_txn_backend != op->o_bd ) { 488 rs->sr_text = "transaction cannot span multiple database contexts"; 489 rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; 490 goto txnReturn; 491 } 492 493 /* insert operation into transaction */ 494 495 rs->sr_text = "transaction specified"; 496 rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; 497 498 txnReturn: 499 /* release connection lock */ 500 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 501 502 if( !settle ) { 503 send_ldap_result( op, rs ); 504 return rs->sr_err; 505 } 506 } 507 #endif 508 509 ctrls[num_ctrls] = NULL; 510 511 /* begin transaction */ 512 rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi ); 513 rs->sr_text = NULL; 514 if( rs->sr_err != 0 ) { 515 Debug( LDAP_DEBUG_TRACE, 516 LDAP_XSTRING(mdb_modify) ": txn_begin failed: " 517 "%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 518 rs->sr_err = LDAP_OTHER; 519 rs->sr_text = "internal error"; 520 goto return_results; 521 } 522 txn = moi->moi_txn; 523 524 /* Don't touch the opattrs, if this is a contextCSN update 525 * initiated from updatedn */ 526 if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next || 527 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) { 528 529 slap_mods_opattrs( op, &op->orm_modlist, 1 ); 530 } 531 532 /* get entry or ancestor */ 533 rs->sr_err = mdb_dn2entry( op, txn, NULL, &op->o_req_ndn, &e, NULL, 1 ); 534 535 if ( rs->sr_err != 0 ) { 536 Debug( LDAP_DEBUG_TRACE, 537 LDAP_XSTRING(mdb_modify) ": dn2entry failed (%d)\n", 538 rs->sr_err, 0, 0 ); 539 switch( rs->sr_err ) { 540 case MDB_NOTFOUND: 541 break; 542 case LDAP_BUSY: 543 rs->sr_text = "ldap server busy"; 544 goto return_results; 545 default: 546 rs->sr_err = LDAP_OTHER; 547 rs->sr_text = "internal error"; 548 goto return_results; 549 } 550 } 551 552 /* acquire and lock entry */ 553 /* FIXME: dn2entry() should return non-glue entry */ 554 if (( rs->sr_err == MDB_NOTFOUND ) || 555 ( !manageDSAit && e && is_entry_glue( e ))) 556 { 557 if ( e != NULL ) { 558 rs->sr_matched = ch_strdup( e->e_dn ); 559 if ( is_entry_referral( e )) { 560 BerVarray ref = get_entry_referrals( op, e ); 561 rs->sr_ref = referral_rewrite( ref, &e->e_name, 562 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 563 ber_bvarray_free( ref ); 564 } else { 565 rs->sr_ref = NULL; 566 } 567 mdb_entry_return( op, e ); 568 e = NULL; 569 570 } else { 571 rs->sr_ref = referral_rewrite( default_referral, NULL, 572 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 573 } 574 575 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; 576 rs->sr_err = LDAP_REFERRAL; 577 send_ldap_result( op, rs ); 578 goto done; 579 } 580 581 if ( !manageDSAit && is_entry_referral( e ) ) { 582 /* entry is a referral, don't allow modify */ 583 rs->sr_ref = get_entry_referrals( op, e ); 584 585 Debug( LDAP_DEBUG_TRACE, 586 LDAP_XSTRING(mdb_modify) ": entry is referral\n", 587 0, 0, 0 ); 588 589 rs->sr_err = LDAP_REFERRAL; 590 rs->sr_matched = e->e_name.bv_val; 591 rs->sr_flags = REP_REF_MUSTBEFREED; 592 send_ldap_result( op, rs ); 593 rs->sr_matched = NULL; 594 goto done; 595 } 596 597 if ( get_assert( op ) && 598 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 599 { 600 rs->sr_err = LDAP_ASSERTION_FAILED; 601 goto return_results; 602 } 603 604 if( op->o_preread ) { 605 if( preread_ctrl == NULL ) { 606 preread_ctrl = &ctrls[num_ctrls++]; 607 ctrls[num_ctrls] = NULL; 608 } 609 if ( slap_read_controls( op, rs, e, 610 &slap_pre_read_bv, preread_ctrl ) ) 611 { 612 Debug( LDAP_DEBUG_TRACE, 613 "<=- " LDAP_XSTRING(mdb_modify) ": pre-read " 614 "failed!\n", 0, 0, 0 ); 615 if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { 616 /* FIXME: is it correct to abort 617 * operation if control fails? */ 618 goto return_results; 619 } 620 } 621 } 622 623 /* Modify the entry */ 624 dummy = *e; 625 rs->sr_err = mdb_modify_internal( op, txn, op->orm_modlist, 626 &dummy, &rs->sr_text, textbuf, textlen ); 627 628 if( rs->sr_err != LDAP_SUCCESS ) { 629 Debug( LDAP_DEBUG_TRACE, 630 LDAP_XSTRING(mdb_modify) ": modify failed (%d)\n", 631 rs->sr_err, 0, 0 ); 632 /* Only free attrs if they were dup'd. */ 633 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 634 goto return_results; 635 } 636 637 /* change the entry itself */ 638 rs->sr_err = mdb_id2entry_update( op, txn, NULL, &dummy ); 639 if ( rs->sr_err != 0 ) { 640 Debug( LDAP_DEBUG_TRACE, 641 LDAP_XSTRING(mdb_modify) ": id2entry update failed " "(%d)\n", 642 rs->sr_err, 0, 0 ); 643 rs->sr_text = "entry update failed"; 644 goto return_results; 645 } 646 647 if( op->o_postread ) { 648 if( postread_ctrl == NULL ) { 649 postread_ctrl = &ctrls[num_ctrls++]; 650 ctrls[num_ctrls] = NULL; 651 } 652 if( slap_read_controls( op, rs, &dummy, 653 &slap_post_read_bv, postread_ctrl ) ) 654 { 655 Debug( LDAP_DEBUG_TRACE, 656 "<=- " LDAP_XSTRING(mdb_modify) 657 ": post-read failed!\n", 0, 0, 0 ); 658 if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { 659 /* FIXME: is it correct to abort 660 * operation if control fails? */ 661 goto return_results; 662 } 663 } 664 } 665 666 /* Only free attrs if they were dup'd. */ 667 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 668 if( moi == &opinfo ) { 669 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 670 opinfo.moi_oe.oe_key = NULL; 671 if( op->o_noop ) { 672 mdb_txn_abort( txn ); 673 rs->sr_err = LDAP_X_NO_OPERATION; 674 txn = NULL; 675 goto return_results; 676 } else { 677 rs->sr_err = mdb_txn_commit( txn ); 678 txn = NULL; 679 } 680 } 681 682 if( rs->sr_err != 0 ) { 683 Debug( LDAP_DEBUG_ANY, 684 LDAP_XSTRING(mdb_modify) ": txn_%s failed: %s (%d)\n", 685 op->o_noop ? "abort (no-op)" : "commit", 686 mdb_strerror(rs->sr_err), rs->sr_err ); 687 rs->sr_err = LDAP_OTHER; 688 rs->sr_text = "commit failed"; 689 690 goto return_results; 691 } 692 693 Debug( LDAP_DEBUG_TRACE, 694 LDAP_XSTRING(mdb_modify) ": updated%s id=%08lx dn=\"%s\"\n", 695 op->o_noop ? " (no-op)" : "", 696 dummy.e_id, op->o_req_dn.bv_val ); 697 698 rs->sr_err = LDAP_SUCCESS; 699 rs->sr_text = NULL; 700 if( num_ctrls ) rs->sr_ctrls = ctrls; 701 702 return_results: 703 if( dummy.e_attrs ) { 704 attrs_free( dummy.e_attrs ); 705 } 706 send_ldap_result( op, rs ); 707 708 #if 0 709 if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) { 710 TXN_CHECKPOINT( mdb->bi_dbenv, 711 mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 ); 712 } 713 #endif 714 715 done: 716 slap_graduate_commit_csn( op ); 717 718 if( moi == &opinfo ) { 719 if( txn != NULL ) { 720 mdb_txn_abort( txn ); 721 } 722 if ( opinfo.moi_oe.oe_key ) { 723 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 724 } 725 } else { 726 moi->moi_ref--; 727 } 728 729 if( e != NULL ) { 730 mdb_entry_return( op, e ); 731 } 732 733 if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { 734 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 735 slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); 736 } 737 if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { 738 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 739 slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); 740 } 741 742 rs->sr_text = NULL; 743 744 return rs->sr_err; 745 } 746