]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modify.c
Move MSVC port to the Attic
[openldap] / servers / slapd / back-bdb / modify.c
1 /* modify.c - bdb backend modify routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 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 #include <ac/string.h>
21 #include <ac/time.h>
22
23 #include "back-bdb.h"
24 #include "external.h"
25
26 static struct berval scbva[] = {
27         BER_BVC("glue"),
28         BER_BVNULL
29 };
30
31 int bdb_modify_internal(
32         Operation *op,
33         DB_TXN *tid,
34         Modifications *modlist,
35         Entry *e,
36         const char **text,
37         char *textbuf,
38         size_t textlen )
39 {
40         int rc, err;
41         Modification    *mod;
42         Modifications   *ml;
43         Attribute       *save_attrs;
44         Attribute       *ap;
45         int                     glue_attr_delete = 0;
46
47 #ifdef NEW_LOGGING
48         LDAP_LOG ( OPERATION, ENTRY, "bdb_modify_internal: 0x%08lx: %s\n", 
49                 e->e_id, e->e_dn, 0 );
50 #else
51         Debug( LDAP_DEBUG_TRACE, "bdb_modify_internal: 0x%08lx: %s\n",
52                 e->e_id, e->e_dn, 0);
53 #endif
54
55         if ( !acl_check_modlist( op, e, modlist )) {
56                 return LDAP_INSUFFICIENT_ACCESS;
57         }
58
59         /* save_attrs will be disposed of by bdb_cache_modify */
60         save_attrs = e->e_attrs;
61         e->e_attrs = attrs_dup( e->e_attrs );
62
63         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
64                 int match;
65                 mod = &ml->sml_mod;
66                 switch( mod->sm_op ) {
67                 case LDAP_MOD_ADD:
68                 case LDAP_MOD_REPLACE:
69                         if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
70                                 value_match( &match, slap_schema.si_ad_structuralObjectClass,
71                                 slap_schema.si_ad_structuralObjectClass->ad_type->sat_equality,
72                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
73                                 &mod->sm_values[0], &scbva[0], text );
74                                 if ( !match )
75                                         glue_attr_delete = 1;
76                         }
77                 }
78                 if ( glue_attr_delete )
79                         break;
80         }
81
82         if ( glue_attr_delete ) {
83                 Attribute       **app = &e->e_attrs;
84                 while ( *app != NULL ) {
85                         if ( !is_at_operational( (*app)->a_desc->ad_type )) {
86                                 Attribute *save = *app;
87                                 *app = (*app)->a_next;
88                                 attr_free( save );
89                                 continue;
90                         }
91                         app = &(*app)->a_next;
92                 }
93         }
94
95         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
96                 mod = &ml->sml_mod;
97
98                 switch ( mod->sm_op ) {
99                 case LDAP_MOD_ADD:
100 #ifdef NEW_LOGGING
101                         LDAP_LOG ( OPERATION, DETAIL1, "bdb_modify_internal: add\n", 0,0,0);
102 #else
103                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: add\n", 0, 0, 0);
104 #endif
105                         err = modify_add_values( e, mod, get_permissiveModify(op),
106                                 text, textbuf, textlen );
107                         if( err != LDAP_SUCCESS ) {
108 #ifdef NEW_LOGGING
109                                 LDAP_LOG ( OPERATION, ERR, 
110                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
111 #else
112                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
113                                         err, *text, 0);
114 #endif
115                         }
116                         break;
117
118                 case LDAP_MOD_DELETE:
119                         if ( glue_attr_delete ) {
120                                 err = LDAP_SUCCESS;
121                                 break;
122                         }
123
124 #ifdef NEW_LOGGING
125                         LDAP_LOG ( OPERATION, DETAIL1, 
126                                 "bdb_modify_internal: delete\n", 0, 0, 0 );
127 #else
128                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: delete\n", 0, 0, 0);
129 #endif
130                         err = modify_delete_values( e, mod, get_permissiveModify(op),
131                                 text, textbuf, textlen );
132                         assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
133                         if( err != LDAP_SUCCESS ) {
134 #ifdef NEW_LOGGING
135                                 LDAP_LOG ( OPERATION, ERR, 
136                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
137 #else
138                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
139                                         err, *text, 0);
140 #endif
141                         }
142                         break;
143
144                 case LDAP_MOD_REPLACE:
145 #ifdef NEW_LOGGING
146                         LDAP_LOG ( OPERATION, DETAIL1, 
147                                 "bdb_modify_internal: replace\n", 0, 0, 0 );
148 #else
149                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0);
150 #endif
151                         err = modify_replace_values( e, mod, get_permissiveModify(op),
152                                 text, textbuf, textlen );
153                         if( err != LDAP_SUCCESS ) {
154 #ifdef NEW_LOGGING
155                                 LDAP_LOG ( OPERATION, ERR, 
156                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
157 #else
158                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
159                                         err, *text, 0);
160 #endif
161                         }
162                         break;
163
164                 case LDAP_MOD_INCREMENT:
165 #ifdef NEW_LOGGING
166                         LDAP_LOG ( OPERATION, DETAIL1, 
167                                 "bdb_modify_internal: increment\n", 0, 0, 0 );
168 #else
169                         Debug(LDAP_DEBUG_ARGS,
170                                 "bdb_modify_internal: increment\n", 0, 0, 0);
171 #endif
172                         err = modify_increment_values( e, mod, get_permissiveModify(op),
173                                 text, textbuf, textlen );
174                         if( err != LDAP_SUCCESS ) {
175 #ifdef NEW_LOGGING
176                                 LDAP_LOG ( OPERATION, ERR, 
177                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
178 #else
179                                 Debug(LDAP_DEBUG_ARGS,
180                                         "bdb_modify_internal: %d %s\n",
181                                         err, *text, 0);
182 #endif
183                         }
184                         break;
185
186                 case SLAP_MOD_SOFTADD:
187 #ifdef NEW_LOGGING
188                         LDAP_LOG ( OPERATION, DETAIL1, 
189                                 "bdb_modify_internal: softadd\n",0,0,0 );
190 #else
191                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: softadd\n", 0, 0, 0);
192 #endif
193                         /* Avoid problems in index_add_mods()
194                          * We need to add index if necessary.
195                          */
196                         mod->sm_op = LDAP_MOD_ADD;
197
198                         err = modify_add_values( e, mod, get_permissiveModify(op),
199                                 text, textbuf, textlen );
200
201                         mod->sm_op = SLAP_MOD_SOFTADD;
202
203                         if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
204                                 err = LDAP_SUCCESS;
205                         }
206
207                         if( err != LDAP_SUCCESS ) {
208 #ifdef NEW_LOGGING
209                                 LDAP_LOG ( OPERATION, ERR, 
210                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
211 #else
212                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
213                                         err, *text, 0);
214 #endif
215                         }
216                         break;
217
218                 default:
219 #ifdef NEW_LOGGING
220                                 LDAP_LOG ( OPERATION, ERR, 
221                                         "bdb_modify_internal: invalid op %d\n", mod->sm_op, 0, 0 );
222 #else
223                         Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n",
224                                 mod->sm_op, 0, 0);
225 #endif
226                         *text = "Invalid modify operation";
227                         err = LDAP_OTHER;
228 #ifdef NEW_LOGGING
229                                 LDAP_LOG ( OPERATION, ERR, 
230                                         "bdb_modify_internal: %d %s\n", err, *text, 0 );
231 #else
232                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
233                                 err, *text, 0);
234 #endif
235                 }
236
237                 if ( err != LDAP_SUCCESS ) {
238                         attrs_free( e->e_attrs );
239                         e->e_attrs = save_attrs;
240                         /* unlock entry, delete from cache */
241                         return err; 
242                 }
243
244                 /* If objectClass was modified, reset the flags */
245                 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
246                         e->e_ocflags = 0;
247                 }
248
249                 if ( glue_attr_delete ) {
250                         e->e_ocflags = 0;
251                 }
252
253                 /* check if modified attribute was indexed
254                  * but not in case of NOOP... */
255                 err = bdb_index_is_indexed( op->o_bd, mod->sm_desc );
256                 if ( err == LDAP_SUCCESS && !op->o_noop ) {
257                         ap = attr_find( save_attrs, mod->sm_desc );
258                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
259
260                         ap = attr_find( e->e_attrs, mod->sm_desc );
261                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
262                 }
263         }
264
265         /* check that the entry still obeys the schema */
266         rc = entry_schema_check( op->o_bd, e, save_attrs, text, textbuf, textlen );
267         if ( rc != LDAP_SUCCESS || op->o_noop ) {
268                 attrs_free( e->e_attrs );
269                 /* clear the indexing flags */
270                 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
271                         ap->a_flags = 0;
272                 }
273                 e->e_attrs = save_attrs;
274
275                 if ( rc != LDAP_SUCCESS ) {
276 #ifdef NEW_LOGGING
277                         LDAP_LOG ( OPERATION, ERR, "bdb_modify_internal: "
278                                 "entry failed schema check %s\n", 
279                                 *text, 0, 0 );
280 #else
281                         Debug( LDAP_DEBUG_ANY,
282                                 "entry failed schema check: %s\n",
283                                 *text, 0, 0 );
284 #endif
285                 }
286
287                 /* if NOOP then silently revert to saved attrs */
288                 return rc;
289         }
290
291         /* update the indices of the modified attributes */
292
293         /* start with deleting the old index entries */
294         for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
295                 if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
296                         rc = bdb_index_values( op, tid, ap->a_desc,
297                                 ap->a_nvals,
298                                 e->e_id, SLAP_INDEX_DELETE_OP );
299                         if ( rc != LDAP_SUCCESS ) {
300                                 attrs_free( e->e_attrs );
301                                 e->e_attrs = save_attrs;
302 #ifdef NEW_LOGGING
303                                 LDAP_LOG ( OPERATION, ERR, 
304                                         "bdb_modify_internal: attribute index delete failure\n",
305                                         0, 0, 0 );
306 #else
307                                 Debug( LDAP_DEBUG_ANY,
308                                        "Attribute index delete failure",
309                                        0, 0, 0 );
310 #endif
311                                 return rc;
312                         }
313                         ap->a_flags &= ~SLAP_ATTR_IXDEL;
314                 }
315         }
316
317         /* add the new index entries */
318         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
319                 if (ap->a_flags & SLAP_ATTR_IXADD) {
320                         rc = bdb_index_values( op, tid, ap->a_desc,
321                                 ap->a_nvals,
322                                 e->e_id, SLAP_INDEX_ADD_OP );
323                         if ( rc != LDAP_SUCCESS ) {
324                                 attrs_free( e->e_attrs );
325                                 e->e_attrs = save_attrs;
326 #ifdef NEW_LOGGING
327                                 LDAP_LOG ( OPERATION, ERR, 
328                                         "bdb_modify_internal: attribute index add failure\n", 
329                                         0, 0, 0 );
330 #else
331                                 Debug( LDAP_DEBUG_ANY,
332                                        "Attribute index add failure",
333                                        0, 0, 0 );
334 #endif
335                                 return rc;
336                         }
337                         ap->a_flags &= ~SLAP_ATTR_IXADD;
338                 }
339         }
340
341         return rc;
342 }
343
344
345 int
346 bdb_modify( Operation *op, SlapReply *rs )
347 {
348         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
349         Entry           *e = NULL;
350         EntryInfo       *ei = NULL;
351         int             manageDSAit = get_manageDSAit( op );
352         char textbuf[SLAP_TEXT_BUFLEN];
353         size_t textlen = sizeof textbuf;
354         DB_TXN  *ltid = NULL, *lt2;
355         struct bdb_op_info opinfo;
356         Entry           dummy = {0};
357
358         u_int32_t       locker = 0;
359         DB_LOCK         lock;
360
361         int             num_retries = 0;
362
363         LDAPControl **preread_ctrl = NULL;
364         LDAPControl **postread_ctrl = NULL;
365         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
366         int num_ctrls = 0;
367
368         Operation* ps_list;
369         struct psid_entry *pm_list, *pm_prev;
370         int rc;
371         EntryInfo       *suffix_ei;
372         Entry           *ctxcsn_e;
373         int                     ctxcsn_added = 0;
374
375 #ifdef NEW_LOGGING
376         LDAP_LOG ( OPERATION, ENTRY, "bdb_modify: %s\n",
377                 op->o_req_dn.bv_val, 0, 0 );
378 #else
379         Debug( LDAP_DEBUG_ARGS, "bdb_modify: %s\n",
380                 op->o_req_dn.bv_val, 0, 0 );
381 #endif
382
383         ctrls[num_ctrls] = NULL;
384
385         if( 0 ) {
386 retry:  /* transaction retry */
387                 if ( dummy.e_attrs ) {
388                         attrs_free( dummy.e_attrs );
389                         dummy.e_attrs = NULL;
390                 }
391                 if( e != NULL ) {
392                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
393                         e = NULL;
394                 }
395 #ifdef NEW_LOGGING
396                 LDAP_LOG ( OPERATION, DETAIL1, "bdb_modify: retrying...\n", 0, 0, 0 );
397 #else
398                 Debug(LDAP_DEBUG_TRACE,
399                         "bdb_modify: retrying...\n", 0, 0, 0);
400 #endif
401
402                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
403                 while ( pm_list != NULL ) {
404                         LDAP_LIST_REMOVE ( pm_list, ps_link );
405                         pm_prev = pm_list;
406                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
407                         ch_free( pm_prev );
408                 }
409
410                 rs->sr_err = TXN_ABORT( ltid );
411                 ltid = NULL;
412                 op->o_private = NULL;
413                 op->o_do_not_cache = opinfo.boi_acl_cache;
414                 if( rs->sr_err != 0 ) {
415                         rs->sr_err = LDAP_OTHER;
416                         rs->sr_text = "internal error";
417                         goto return_results;
418                 }
419                 ldap_pvt_thread_yield();
420                 bdb_trans_backoff( ++num_retries );
421         }
422
423         /* begin transaction */
424         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
425                 bdb->bi_db_opflags );
426         rs->sr_text = NULL;
427         if( rs->sr_err != 0 ) {
428 #ifdef NEW_LOGGING
429                 LDAP_LOG ( OPERATION, DETAIL1, 
430                         "bdb_modify: txn_begin failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
431 #else
432                 Debug( LDAP_DEBUG_TRACE,
433                         "bdb_modify: txn_begin failed: %s (%d)\n",
434                         db_strerror(rs->sr_err), rs->sr_err, 0 );
435 #endif
436                 rs->sr_err = LDAP_OTHER;
437                 rs->sr_text = "internal error";
438                 goto return_results;
439         }
440
441         locker = TXN_ID ( ltid );
442
443         opinfo.boi_bdb = op->o_bd;
444         opinfo.boi_txn = ltid;
445         opinfo.boi_locker = locker;
446         opinfo.boi_err = 0;
447         opinfo.boi_acl_cache = op->o_do_not_cache;
448         op->o_private = &opinfo;
449
450         /* get entry or ancestor */
451         rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
452                 locker, &lock );
453
454         if ( rs->sr_err != 0 ) {
455 #ifdef NEW_LOGGING
456                 LDAP_LOG ( OPERATION, DETAIL1, 
457                         "bdb_modify: dn2entry failed: (%d)\n", rs->sr_err, 0, 0 );
458 #else
459                 Debug( LDAP_DEBUG_TRACE,
460                         "bdb_modify: dn2entry failed (%d)\n",
461                         rs->sr_err, 0, 0 );
462 #endif
463                 switch( rs->sr_err ) {
464                 case DB_LOCK_DEADLOCK:
465                 case DB_LOCK_NOTGRANTED:
466                         goto retry;
467                 case DB_NOTFOUND:
468                         break;
469                 case LDAP_BUSY:
470                         rs->sr_text = "ldap server busy";
471                         goto return_results;
472                 default:
473                         rs->sr_err = LDAP_OTHER;
474                         rs->sr_text = "internal error";
475                         goto return_results;
476                 }
477         }
478
479         e = ei->bei_e;
480         /* acquire and lock entry */
481         /* FIXME: dn2entry() should return non-glue entry */
482         if (( rs->sr_err == DB_NOTFOUND ) ||
483                 ( !manageDSAit && e && is_entry_glue( e )))
484         {
485                 if ( e != NULL ) {
486                         rs->sr_matched = ch_strdup( e->e_dn );
487                         rs->sr_ref = is_entry_referral( e )
488                                 ? get_entry_referrals( op, e )
489                                 : NULL;
490                         bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, e);
491                         e = NULL;
492
493                 } else {
494                         BerVarray deref = NULL;
495                         if ( !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
496                                 syncinfo_t *si;
497                                 LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) {
498                                         struct berval tmpbv;
499                                         ber_dupbv( &tmpbv, &si->si_provideruri_bv[0] );
500                                         ber_bvarray_add( &deref, &tmpbv );
501                 }
502                         } else {
503                                 deref = default_referral;
504                         }
505                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn,
506                                 LDAP_SCOPE_DEFAULT );
507                 }
508
509                 rs->sr_err = LDAP_REFERRAL;
510                 send_ldap_result( op, rs );
511
512                 if ( rs->sr_ref != default_referral ) {
513                         ber_bvarray_free( rs->sr_ref );
514                 }
515                 free( (char *)rs->sr_matched );
516                 rs->sr_ref = NULL;
517                 rs->sr_matched = NULL;
518
519                 goto done;
520         }
521
522         if ( !manageDSAit && is_entry_referral( e ) ) {
523                 /* entry is a referral, don't allow modify */
524                 rs->sr_ref = get_entry_referrals( op, e );
525
526 #ifdef NEW_LOGGING
527                 LDAP_LOG ( OPERATION, DETAIL1,
528                         "bdb_modify: entry is referral\n",
529                         0, 0, 0 );
530 #else
531                 Debug( LDAP_DEBUG_TRACE,
532                         "bdb_modify: entry is referral\n",
533                         0, 0, 0 );
534 #endif
535
536                 rs->sr_err = LDAP_REFERRAL;
537                 rs->sr_matched = e->e_name.bv_val;
538                 send_ldap_result( op, rs );
539
540                 ber_bvarray_free( rs->sr_ref );
541                 rs->sr_ref = NULL;
542                 rs->sr_matched = NULL;
543                 goto done;
544         }
545
546         if ( get_assert( op ) &&
547                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
548         {
549                 rs->sr_err = LDAP_ASSERTION_FAILED;
550                 goto return_results;
551         }
552
553         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop && !op->o_no_psearch ) {
554                 ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
555                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
556                         rc = bdb_psearch(op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY );
557                         if ( rc ) {
558 #ifdef NEW_LOGGING
559                                 LDAP_LOG ( OPERATION, ERR,
560                                         "bdb_modify: persistent search failed (%d,%d)\n",
561                                         rc, rs->sr_err, 0 );
562 #else
563                                 Debug( LDAP_DEBUG_TRACE,
564                                         "bdb_modify: persistent search failed (%d,%d)\n",
565                                         rc, rs->sr_err, 0 );
566 #endif
567                         }
568                 }
569                 ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
570         }
571
572         if( op->o_preread ) {
573                 if( preread_ctrl == NULL ) {
574                         preread_ctrl = &ctrls[num_ctrls++];
575                         ctrls[num_ctrls] = NULL;
576                 }
577                 if ( slap_read_controls( op, rs, e,
578                         &slap_pre_read_bv, preread_ctrl ) )
579                 {
580 #ifdef NEW_LOGGING
581                         LDAP_LOG ( OPERATION, DETAIL1,
582                                 "<=- bdb_modify: pre-read failed!\n", 0, 0, 0 );
583 #else
584                         Debug( LDAP_DEBUG_TRACE,
585                                 "<=- bdb_modify: pre-read failed!\n", 0, 0, 0 );
586 #endif
587                         goto return_results;
588                 }
589         }
590
591         /* nested transaction */
592         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
593                 bdb->bi_db_opflags );
594         rs->sr_text = NULL;
595         if( rs->sr_err != 0 ) {
596 #ifdef NEW_LOGGING
597                 LDAP_LOG ( OPERATION, ERR, 
598                         "bdb_modify: txn_begin(2) failed: %s (%d)\n",
599                         db_strerror(rs->sr_err), rs->sr_err, 0 );
600 #else
601                 Debug( LDAP_DEBUG_TRACE,
602                         "bdb_modify: txn_begin(2) failed: %s (%d)\n",
603                         db_strerror(rs->sr_err), rs->sr_err, 0 );
604 #endif
605                 rs->sr_err = LDAP_OTHER;
606                 rs->sr_text = "internal error";
607                 goto return_results;
608         }
609         /* Modify the entry */
610         dummy = *e;
611         rs->sr_err = bdb_modify_internal( op, lt2, op->oq_modify.rs_modlist,
612                 &dummy, &rs->sr_text, textbuf, textlen );
613
614         if( rs->sr_err != LDAP_SUCCESS ) {
615 #ifdef NEW_LOGGING
616                 LDAP_LOG ( OPERATION, ERR, 
617                         "bdb_modify: modify failed (%d)\n", rs->sr_err, 0, 0 );
618 #else
619                 Debug( LDAP_DEBUG_TRACE,
620                         "bdb_modify: modify failed (%d)\n",
621                         rs->sr_err, 0, 0 );
622 #endif
623                 if ( (rs->sr_err == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
624                         rs->sr_err = opinfo.boi_err;
625                 }
626                 /* Only free attrs if they were dup'd.  */
627                 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
628                 switch( rs->sr_err ) {
629                 case DB_LOCK_DEADLOCK:
630                 case DB_LOCK_NOTGRANTED:
631                         goto retry;
632                 }
633                 goto return_results;
634         }
635
636         /* change the entry itself */
637         rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
638         if ( rs->sr_err != 0 ) {
639 #ifdef NEW_LOGGING
640                 LDAP_LOG ( OPERATION, ERR, 
641                         "bdb_modify: id2entry update failed (%d)\n", rs->sr_err, 0, 0 );
642 #else
643                 Debug( LDAP_DEBUG_TRACE,
644                         "bdb_modify: id2entry update failed (%d)\n",
645                         rs->sr_err, 0, 0 );
646 #endif
647                 switch( rs->sr_err ) {
648                 case DB_LOCK_DEADLOCK:
649                 case DB_LOCK_NOTGRANTED:
650                         goto retry;
651                 }
652                 rs->sr_text = "entry update failed";
653                 goto return_results;
654         }
655
656         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
657                 rs->sr_err = LDAP_OTHER;
658                 rs->sr_text = "txn_commit(2) failed";
659                 goto return_results;
660         }
661
662         if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
663                 rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei,
664                         &ctxcsn_e, &ctxcsn_added, locker );
665                 switch ( rc ) {
666                 case BDB_CSN_ABORT :
667                         goto return_results;
668                 case BDB_CSN_RETRY :
669                         goto retry;
670                 }
671         }
672
673         if( op->o_postread ) {
674                 if( postread_ctrl == NULL ) {
675                         postread_ctrl = &ctrls[num_ctrls++];
676                         ctrls[num_ctrls] = NULL;
677                 }
678                 if( slap_read_controls( op, rs, &dummy,
679                         &slap_post_read_bv, postread_ctrl ) )
680                 {
681 #ifdef NEW_LOGGING
682                         LDAP_LOG ( OPERATION, DETAIL1,
683                                 "<=- bdb_modify: post-read failed!\n", 0, 0, 0 );
684 #else
685                         Debug( LDAP_DEBUG_TRACE,
686                                 "<=- bdb_modify: post-read failed!\n", 0, 0, 0 );
687 #endif
688                         goto return_results;
689                 }
690         }
691
692         if( op->o_noop ) {
693                 if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
694                         rs->sr_text = "txn_abort (no-op) failed";
695                 } else {
696                         rs->sr_err = LDAP_NO_OPERATION;
697                         goto return_results;
698                 }
699         } else {
700                 rc = bdb_cache_modify( e, dummy.e_attrs, bdb->bi_dbenv, locker, &lock );
701                 switch( rc ) {
702                 case DB_LOCK_DEADLOCK:
703                 case DB_LOCK_NOTGRANTED:
704                         goto retry;
705                 }
706                 dummy.e_attrs = NULL;
707
708                 if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
709                         if ( ctxcsn_added ) {
710                                 bdb_cache_add( bdb, suffix_ei, ctxcsn_e,
711                                         (struct berval *)&slap_ldapsync_cn_bv, locker );
712                         }
713                 }
714
715                 if ( rs->sr_err == LDAP_SUCCESS ) {
716                         /* Loop through in-scope entries for each psearch spec */
717                         ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
718                         LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
719                                 rc = bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_MODIFY );
720                                 if ( rc ) {
721 #ifdef NEW_LOGGING
722                                         LDAP_LOG ( OPERATION, ERR,
723                                                 "bdb_modify: persistent search failed (%d,%d)\n",
724                                                 rc, rs->sr_err, 0 );
725 #else
726                                         Debug( LDAP_DEBUG_TRACE,
727                                                 "bdb_modify: persistent search failed (%d,%d)\n",
728                                                 rc, rs->sr_err, 0 );
729 #endif
730                                 }
731                         }
732                         pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
733                         while ( pm_list != NULL ) {
734                                 rc = bdb_psearch(op, rs, pm_list->ps_op,
735                                                         e, LDAP_PSEARCH_BY_SCOPEOUT);
736                                 if ( rc ) {
737 #ifdef NEW_LOGGING
738                                         LDAP_LOG ( OPERATION, ERR,
739                                                 "bdb_modify: persistent search failed (%d,%d)\n",
740                                                 rc, rs->sr_err, 0 );
741 #else
742                                         Debug( LDAP_DEBUG_TRACE,
743                                                 "bdb_modify: persistent search failed (%d,%d)\n",
744                                                 rc, rs->sr_err, 0 );
745 #endif
746                                 }
747                                 LDAP_LIST_REMOVE ( pm_list, ps_link );
748                                 pm_prev = pm_list;
749                                 pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
750                                 ch_free( pm_prev );
751                         }
752                         ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
753                 }
754
755                 rs->sr_err = TXN_COMMIT( ltid, 0 );
756         }
757         ltid = NULL;
758         op->o_private = NULL;
759
760         if( rs->sr_err != 0 ) {
761 #ifdef NEW_LOGGING
762                 LDAP_LOG ( OPERATION, ERR, 
763                         "bdb_modify: txn_%s failed %s (%d)\n", 
764                         op->o_noop ? "abort (no_op)" : "commit",
765                         db_strerror(rs->sr_err), rs->sr_err );
766 #else
767                 Debug( LDAP_DEBUG_TRACE,
768                         "bdb_modify: txn_%s failed: %s (%d)\n",
769                         op->o_noop ? "abort (no-op)" : "commit",
770                         db_strerror(rs->sr_err), rs->sr_err );
771 #endif
772                 rs->sr_err = LDAP_OTHER;
773                 rs->sr_text = "commit failed";
774
775                 goto return_results;
776         }
777
778 #ifdef NEW_LOGGING
779         LDAP_LOG ( OPERATION, DETAIL1, 
780                 "bdb_modify: updated%s id=%08lx dn=\"%s\"\n", 
781                 op->o_noop ? " (no_op)" : "", e->e_id, e->e_dn );
782 #else
783         Debug( LDAP_DEBUG_TRACE,
784                 "bdb_modify: updated%s id=%08lx dn=\"%s\"\n",
785                 op->o_noop ? " (no-op)" : "",
786                 e->e_id, e->e_dn );
787 #endif
788
789         rs->sr_err = LDAP_SUCCESS;
790         rs->sr_text = NULL;
791         if( num_ctrls ) rs->sr_ctrls = ctrls;
792
793 return_results:
794         if( dummy.e_attrs ) {
795                 attrs_free( dummy.e_attrs );
796         }
797         send_ldap_result( op, rs );
798
799         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
800                 ldap_pvt_thread_yield();
801                 TXN_CHECKPOINT( bdb->bi_dbenv,
802                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
803         }
804
805 done:
806         if( ltid != NULL ) {
807                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
808                 while ( pm_list != NULL ) {
809                         LDAP_LIST_REMOVE ( pm_list, ps_link );
810                         pm_prev = pm_list;
811                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
812                         ch_free( pm_prev );
813                 }
814                 TXN_ABORT( ltid );
815                 op->o_private = NULL;
816         }
817
818         if( e != NULL ) {
819                 bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e);
820         }
821
822         if( preread_ctrl != NULL ) {
823                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, &op->o_tmpmemctx );
824                 slap_sl_free( *preread_ctrl, &op->o_tmpmemctx );
825         }
826         if( postread_ctrl != NULL ) {
827                 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, &op->o_tmpmemctx );
828                 slap_sl_free( *postread_ctrl, &op->o_tmpmemctx );
829         }
830         return rs->sr_err;
831 }