]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modrdn.c
definitely fix NOOP in back-bdb
[openldap] / servers / slapd / back-bdb / modrdn.c
1 /* modrdn.c - bdb backend modrdn routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 int
17 bdb_modrdn(
18         Backend *be,
19         Connection      *conn,
20         Operation       *op,
21         struct berval   *dn,
22         struct berval   *ndn,
23         struct berval   *newrdn,
24         struct berval   *nnewrdn,
25         int             deleteoldrdn,
26         struct berval   *newSuperior,
27         struct berval   *nnewSuperior )
28 {
29         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
30         AttributeDescription *children = slap_schema.si_ad_children;
31         struct berval   p_dn, p_ndn;
32         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
33         int             isroot = -1;
34         Entry           *e = NULL;
35         Entry           *p = NULL;
36         Entry           *matched;
37         /* LDAP v2 supporting correct attribute handling. */
38         LDAPRDN         *new_rdn = NULL;
39         LDAPRDN         *old_rdn = NULL;
40         int                     rc;
41         const char *text;
42         char textbuf[SLAP_TEXT_BUFLEN];
43         size_t textlen = sizeof textbuf;
44         DB_TXN *        ltid = NULL;
45         struct bdb_op_info opinfo;
46
47         ID                      id;
48
49         Entry           *np = NULL;                     /* newSuperior Entry */
50         struct berval   *np_dn = NULL;                  /* newSuperior dn */
51         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
52         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
53
54         /* Used to interface with bdb_modify_internal() */
55         Modifications   *mod = NULL;            /* Used to delete old rdn */
56
57         int             manageDSAit = get_manageDSAit( op );
58
59         u_int32_t       locker;
60         DB_LOCK         lock;
61
62         int             noop = 0;
63
64 #ifdef NEW_LOGGING
65         LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", 
66                 dn->bv_val,newrdn->bv_val, newSuperior ? newSuperior->bv_val : "NULL" );
67 #else
68         Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
69                 dn->bv_val, newrdn->bv_val,
70                 newSuperior ? newSuperior->bv_val : "NULL" );
71 #endif
72
73 #if 0
74         if( newSuperior != NULL ) {
75                 rc = LDAP_UNWILLING_TO_PERFORM;
76                 text = "newSuperior not implemented (yet)";
77                 goto return_results;
78         }
79 #endif
80
81         if( 0 ) {
82 retry:  /* transaction retry */
83                 if (e != NULL) {
84                         bdb_cache_delete_entry(&bdb->bi_cache, e);
85                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
86                 }
87                 if (p != NULL) {
88                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
89                 }
90                 if (np != NULL) {
91                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
92                 }
93 #ifdef NEW_LOGGING
94                 LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0);
95 #else
96                 Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
97 #endif
98                 rc = TXN_ABORT( ltid );
99                 ltid = NULL;
100                 op->o_private = NULL;
101                 if( rc != 0 ) {
102                         rc = LDAP_OTHER;
103                         text = "internal error";
104                         goto return_results;
105                 }
106                 ldap_pvt_thread_yield();
107         }
108
109         /* begin transaction */
110         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
111                 bdb->bi_db_opflags );
112         text = NULL;
113         if( rc != 0 ) {
114 #ifdef NEW_LOGGING
115                 LDAP_LOG ( OPERATION, ERR, 
116                         "==>bdb_modrdn: txn_begin failed: %s (%d)\n", 
117                         db_strerror(rc), rc, 0 );
118 #else
119                 Debug( LDAP_DEBUG_TRACE,
120                         "bdb_delete: txn_begin failed: %s (%d)\n",
121                         db_strerror(rc), rc, 0 );
122 #endif
123                 rc = LDAP_OTHER;
124                 text = "internal error";
125                 goto return_results;
126         }
127
128         locker = TXN_ID ( ltid );
129
130         opinfo.boi_bdb = be;
131         opinfo.boi_txn = ltid;
132         opinfo.boi_err = 0;
133         op->o_private = &opinfo;
134
135         /* get entry */
136         rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW, locker, &lock );
137
138         switch( rc ) {
139         case 0:
140         case DB_NOTFOUND:
141                 break;
142         case DB_LOCK_DEADLOCK:
143         case DB_LOCK_NOTGRANTED:
144                 goto retry;
145         case LDAP_BUSY:
146                 text = "ldap server busy";
147                 goto return_results;
148         default:
149                 rc = LDAP_OTHER;
150                 text = "internal error";
151                 goto return_results;
152         }
153
154         if ( e == NULL ) {
155                 char* matched_dn = NULL;
156                 BerVarray refs;
157
158                 if( matched != NULL ) {
159                         matched_dn = ch_strdup( matched->e_dn );
160                         refs = is_entry_referral( matched )
161                                 ? get_entry_referrals( be, conn, op, matched )
162                                 : NULL;
163                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched);
164                         matched = NULL;
165
166                 } else {
167                         refs = referral_rewrite( default_referral,
168                                 NULL, dn, LDAP_SCOPE_DEFAULT );
169                 }
170
171                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
172                         matched_dn, NULL, refs, NULL );
173
174                 ber_bvarray_free( refs );
175                 free( matched_dn );
176
177                 goto done;
178         }
179
180         if (!manageDSAit && is_entry_referral( e ) ) {
181                 /* parent is a referral, don't allow add */
182                 /* parent is an alias, don't allow add */
183                 BerVarray refs = get_entry_referrals( be,
184                         conn, op, e );
185
186 #ifdef NEW_LOGGING
187                 LDAP_LOG ( OPERATION, DETAIL1, 
188                         "==>bdb_modrdn: entry %s is referral \n", e->e_dn, 0, 0 );
189 #else
190                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n",
191                         e->e_dn, 0, 0 );
192 #endif
193
194                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
195                         e->e_dn, NULL, refs, NULL );
196
197                 ber_bvarray_free( refs );
198                 goto done;
199         }
200
201         if ( be_issuffix( be, &e->e_nname ) ) {
202                 p_ndn = slap_empty_bv;
203         } else {
204                 dnParent( &e->e_nname, &p_ndn );
205         }
206         np_ndn = &p_ndn;
207         if ( p_ndn.bv_len != 0 ) {
208                 /* Make sure parent entry exist and we can write its 
209                  * children.
210                  */
211                 rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0, locker, &lock );
212
213                 switch( rc ) {
214                 case 0:
215                 case DB_NOTFOUND:
216                         break;
217                 case DB_LOCK_DEADLOCK:
218                 case DB_LOCK_NOTGRANTED:
219                         goto retry;
220                 case LDAP_BUSY:
221                         text = "ldap server busy";
222                         goto return_results;
223                 default:
224                         rc = LDAP_OTHER;
225                         text = "internal error";
226                         goto return_results;
227                 }
228
229                 if( p == NULL) {
230 #ifdef NEW_LOGGING
231                         LDAP_LOG ( OPERATION, ERR, 
232                                 "==>bdb_modrdn: parent does not exist\n", 0, 0, 0 );
233 #else
234                         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
235                                 0, 0, 0);
236 #endif
237                         rc = LDAP_OTHER;
238                         goto return_results;
239                 }
240
241                 /* check parent for "children" acl */
242                 if ( ! access_allowed( be, conn, op, p,
243                         children, NULL, ACL_WRITE, NULL ) )
244                 {
245 #ifdef NEW_LOGGING
246                         LDAP_LOG ( OPERATION, ERR, 
247                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
248 #else
249                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
250                                 0, 0 );
251 #endif
252                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
253                                 NULL, NULL, NULL, NULL );
254                         goto return_results;
255                 }
256
257 #ifdef NEW_LOGGING
258                 LDAP_LOG ( OPERATION, DETAIL1, 
259                         "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val, 0, 0 );
260 #else
261                 Debug( LDAP_DEBUG_TRACE,
262                         "bdb_modrdn: wr to children of entry %s OK\n",
263                         p_ndn.bv_val, 0, 0 );
264 #endif
265                 
266                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
267                         p_dn = slap_empty_bv;
268                 } else {
269                         dnParent( &e->e_name, &p_dn );
270                 }
271
272 #ifdef NEW_LOGGING
273                 LDAP_LOG ( OPERATION, DETAIL1, 
274                         "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
275 #else
276                 Debug( LDAP_DEBUG_TRACE,
277                         "bdb_modrdn: parent dn=%s\n",
278                         p_dn.bv_val, 0, 0 );
279 #endif
280
281         } else {
282                 /* no parent, modrdn entry directly under root */
283                 isroot = be_isroot( be, &op->o_ndn );
284                 if ( ! isroot ) {
285                         if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
286                                 || be_isupdate( be, &op->o_ndn ) ) {
287
288                                 p = (Entry *)&slap_entry_root;
289
290                                 /* check parent for "children" acl */
291                                 rc = access_allowed( be, conn, op, p,
292                                         children, NULL, ACL_WRITE, NULL );
293
294                                 p = NULL;
295
296                                 if ( ! rc )
297                                 {
298 #ifdef NEW_LOGGING
299                                         LDAP_LOG ( OPERATION, ERR, 
300                                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
301 #else
302                                         Debug( LDAP_DEBUG_TRACE, 
303                                                 "no access to parent\n", 
304                                                 0, 0, 0 );
305 #endif
306                                         send_ldap_result( conn, op, 
307                                                 LDAP_INSUFFICIENT_ACCESS,
308                                                 NULL, NULL, NULL, NULL );
309                                         goto return_results;
310                                 }
311
312 #ifdef NEW_LOGGING
313                                 LDAP_LOG ( OPERATION, DETAIL1, 
314                                         "==>bdb_modrdn: wr to children of entry \"%s\" OK\n", 
315                                         p_dn.bv_val, 0, 0 );
316 #else
317                                 Debug( LDAP_DEBUG_TRACE,
318                                         "bdb_modrdn: wr to children of entry \"\" OK\n",
319                                         0, 0, 0 );
320 #endif
321                 
322                                 p_dn.bv_val = "";
323                                 p_dn.bv_len = 0;
324
325 #ifdef NEW_LOGGING
326                                 LDAP_LOG ( OPERATION, DETAIL1, 
327                                         "==>bdb_modrdn: parent dn=\"\" \n", 0, 0, 0 );
328 #else
329                                 Debug( LDAP_DEBUG_TRACE,
330                                         "bdb_modrdn: parent dn=\"\"\n",
331                                         0, 0, 0 );
332 #endif
333
334                         } else {
335 #ifdef NEW_LOGGING
336                                 LDAP_LOG ( OPERATION, ERR, 
337                                         "==>bdb_modrdn: no parent, not root &\"\" is not "
338                                         "suffix\n", 0, 0, 0 );
339 #else
340                                 Debug( LDAP_DEBUG_TRACE,
341                                         "bdb_modrdn: no parent, not root "
342                                         "& \"\" is not suffix\n",
343                                         0, 0, 0);
344 #endif
345                                 rc = LDAP_INSUFFICIENT_ACCESS;
346                                 goto return_results;
347                         }
348                 }
349         }
350
351         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
352
353         if ( newSuperior != NULL ) {
354 #ifdef NEW_LOGGING
355                 LDAP_LOG ( OPERATION, DETAIL1, 
356                         "==>bdb_modrdn: new parent \"%s\" requested...\n", 
357                         newSuperior->bv_val, 0, 0 );
358 #else
359                 Debug( LDAP_DEBUG_TRACE, 
360                         "bdb_modrdn: new parent \"%s\" requested...\n",
361                         newSuperior->bv_val, 0, 0 );
362 #endif
363
364                 if ( newSuperior->bv_len ) {
365                         np_dn = newSuperior;
366                         np_ndn = nnewSuperior;
367
368                         /* newSuperior == oldParent?, if so ==> ERROR */
369                         /* newSuperior == entry being moved?, if so ==> ERROR */
370                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
371
372                         rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0, locker, &lock );
373
374                         switch( rc ) {
375                         case 0:
376                         case DB_NOTFOUND:
377                                 break;
378                         case DB_LOCK_DEADLOCK:
379                         case DB_LOCK_NOTGRANTED:
380                                 goto retry;
381                         case LDAP_BUSY:
382                                 text = "ldap server busy";
383                                 goto return_results;
384                         default:
385                                 rc = LDAP_OTHER;
386                                 text = "internal error";
387                                 goto return_results;
388                         }
389
390                         if( np == NULL) {
391 #ifdef NEW_LOGGING
392                                 LDAP_LOG ( OPERATION, DETAIL1, 
393                                         "==>bdb_modrdn: newSup(ndn=%s) not here!\n", 
394                                         np_ndn->bv_val, 0, 0 );
395 #else
396                                 Debug( LDAP_DEBUG_TRACE,
397                                         "bdb_modrdn: newSup(ndn=%s) not here!\n",
398                                         np_ndn->bv_val, 0, 0);
399 #endif
400                                 rc = LDAP_OTHER;
401                                 goto return_results;
402                         }
403
404 #ifdef NEW_LOGGING
405                         LDAP_LOG ( OPERATION, DETAIL1, 
406                                 "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", 
407                                 np, (long) np->e_id, 0 );
408 #else
409                         Debug( LDAP_DEBUG_TRACE,
410                                 "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
411                                 np, (long) np->e_id, 0 );
412 #endif
413
414                         /* check newSuperior for "children" acl */
415                         if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE, NULL ) ) {
416 #ifdef NEW_LOGGING
417                                 LDAP_LOG ( OPERATION, DETAIL1, 
418                                         "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 );
419 #else
420                                 Debug( LDAP_DEBUG_TRACE,
421                                         "bdb_modrdn: no wr to newSup children\n",
422                                         0, 0, 0 );
423 #endif
424                                 rc = LDAP_INSUFFICIENT_ACCESS;
425                                 goto return_results;
426                         }
427
428 #ifdef BDB_ALIASES
429                         if ( is_entry_alias( np ) ) {
430                                 /* parent is an alias, don't allow add */
431 #ifdef NEW_LOGGING
432                                 LDAP_LOG ( OPERATION, DETAIL1, 
433                                         "==>bdb_modrdn: entry is alias\n", 0, 0, 0 );
434 #else
435                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
436                                         0, 0, 0 );
437 #endif
438
439                                 rc = LDAP_ALIAS_PROBLEM;
440                                 goto return_results;
441                         }
442 #endif
443
444                         if ( is_entry_referral( np ) ) {
445                                 /* parent is a referral, don't allow add */
446 #ifdef NEW_LOGGING
447                                 LDAP_LOG ( OPERATION, DETAIL1, 
448                                         "==>bdb_modrdn: entry is referral\n", 0, 0, 0 );
449 #else
450                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
451                                         0, 0, 0 );
452 #endif
453
454                                 rc = LDAP_OTHER;
455                                 goto return_results;
456                         }
457
458                 } else {
459                         if ( isroot == -1 ) {
460                                 isroot = be_isroot( be, &op->o_ndn );
461                         }
462                         
463                         np_dn = NULL;
464
465                         /* no parent, modrdn entry directly under root */
466                         if ( ! isroot ) {
467                                 if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
468                                         || be_isupdate( be, &op->o_ndn ) ) {
469                                         np = (Entry *)&slap_entry_root;
470
471                                         /* check parent for "children" acl */
472                                         rc = access_allowed( be, conn, op, np,
473                                                 children, NULL, ACL_WRITE, NULL );
474
475                                         np = NULL;
476
477                                         if ( ! rc )
478                                         {
479 #ifdef NEW_LOGGING
480                                                 LDAP_LOG ( OPERATION, ERR, 
481                                                         "==>bdb_modrdn: no access to superior\n", 0, 0, 0 );
482 #else
483                                                 Debug( LDAP_DEBUG_TRACE, 
484                                                         "no access to new superior\n", 
485                                                         0, 0, 0 );
486 #endif
487                                                 send_ldap_result( conn, op, 
488                                                         LDAP_INSUFFICIENT_ACCESS,
489                                                         NULL, NULL, NULL, NULL );
490                                                 goto return_results;
491                                         }
492
493 #ifdef NEW_LOGGING
494                                         LDAP_LOG ( OPERATION, DETAIL1, 
495                                                 "bdb_modrdn: wr to children entry \"\" OK\n", 0, 0, 0 );
496 #else
497                                         Debug( LDAP_DEBUG_TRACE,
498                                                 "bdb_modrdn: wr to children of entry \"\" OK\n",
499                                                 0, 0, 0 );
500 #endif
501                 
502                                 } else {
503 #ifdef NEW_LOGGING
504                                         LDAP_LOG ( OPERATION, ERR, 
505                                                 "bdb_modrdn: new superior=\"\", not root & \"\" "
506                                                 "is not suffix\n", 0, 0, 0 );
507 #else
508                                         Debug( LDAP_DEBUG_TRACE,
509                                                 "bdb_modrdn: new superior=\"\", not root "
510                                                 "& \"\" is not suffix\n",
511                                                 0, 0, 0);
512 #endif
513                                         rc = LDAP_INSUFFICIENT_ACCESS;
514                                         goto return_results;
515                                 }
516                         }
517
518 #ifdef NEW_LOGGING
519                         LDAP_LOG ( OPERATION, DETAIL1, 
520                                 "bdb_modrdn: new superior=\"\"\n", 0, 0, 0 );
521 #else
522                         Debug( LDAP_DEBUG_TRACE,
523                                 "bdb_modrdn: new superior=\"\"\n",
524                                 0, 0, 0 );
525 #endif
526                 }
527
528 #ifdef NEW_LOGGING
529                 LDAP_LOG ( OPERATION, DETAIL1, 
530                         "bdb_modrdn: wr to new parent's children OK\n", 0, 0, 0 );
531 #else
532                 Debug( LDAP_DEBUG_TRACE,
533                         "bdb_modrdn: wr to new parent's children OK\n",
534                         0, 0, 0 );
535 #endif
536
537                 new_parent_dn = np_dn;
538         }
539         
540         /* Build target dn and make sure target entry doesn't exist already. */
541         build_new_dn( &new_dn, new_parent_dn, newrdn ); 
542
543         dnNormalize2( NULL, &new_dn, &new_ndn );
544
545 #ifdef NEW_LOGGING
546         LDAP_LOG ( OPERATION, RESULTS, 
547                 "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val, 0, 0 );
548 #else
549         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
550                 new_ndn.bv_val, 0, 0 );
551 #endif
552
553         rc = bdb_dn2id ( be, ltid, &new_ndn, &id, 0 );
554         switch( rc ) {
555         case DB_LOCK_DEADLOCK:
556         case DB_LOCK_NOTGRANTED:
557                 goto retry;
558         case DB_NOTFOUND:
559                 break;
560         case 0:
561                 rc = LDAP_ALREADY_EXISTS;
562                 goto return_results;
563         default:
564                 rc = LDAP_OTHER;
565                 text = "internal error";
566                 goto return_results;
567         }
568
569 #ifdef NEW_LOGGING
570         LDAP_LOG ( OPERATION, ERR, 
571                 "bdb_modrdn: new ndn=%s does not exist\n", new_ndn.bv_val, 0, 0 );
572 #else
573         Debug( LDAP_DEBUG_TRACE,
574                 "bdb_modrdn: new ndn=%s does not exist\n",
575                 new_ndn.bv_val, 0, 0 );
576 #endif
577
578         /* Get attribute type and attribute value of our new rdn, we will
579          * need to add that to our new entry
580          */
581         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text,
582                 LDAP_DN_FORMAT_LDAP ) )
583         {
584 #ifdef NEW_LOGGING
585                 LDAP_LOG ( OPERATION, ERR, 
586                         "bdb_modrdn: can't figure out "
587                         "type(s)/values(s) of newrdn\n", 
588                         0, 0, 0 );
589 #else
590                 Debug( LDAP_DEBUG_TRACE,
591                         "bdb_modrdn: can't figure out "
592                         "type(s)/values(s) of newrdn\n", 
593                         0, 0, 0 );
594 #endif
595                 rc = LDAP_INVALID_DN_SYNTAX;
596                 text = "unknown type(s) used in RDN";
597                 goto return_results;
598         }
599
600 #ifdef NEW_LOGGING
601         LDAP_LOG ( OPERATION, RESULTS, 
602                 "bdb_modrdn: new_rdn_type=\"%s\", "
603                 "new_rdn_val=\"%s\"\n",
604                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
605                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
606 #else
607         Debug( LDAP_DEBUG_TRACE,
608                 "bdb_modrdn: new_rdn_type=\"%s\", "
609                 "new_rdn_val=\"%s\"\n",
610                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
611                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
612 #endif
613
614         if ( deleteoldrdn ) {
615                 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
616                         LDAP_DN_FORMAT_LDAP ) )
617                 {
618 #ifdef NEW_LOGGING
619                         LDAP_LOG ( OPERATION, ERR, 
620                                 "bdb_modrdn: can't figure out "
621                                 "type(s)/values(s) of old_rdn\n", 
622                                 0, 0, 0 );
623 #else
624                         Debug( LDAP_DEBUG_TRACE,
625                                 "bdb_modrdn: can't figure out "
626                                 "the old_rdn type(s)/value(s)\n", 
627                                 0, 0, 0 );
628 #endif
629                         rc = LDAP_OTHER;
630                         text = "cannot parse RDN from old DN";
631                         goto return_results;            
632                 }
633         }
634
635         /* prepare modlist of modifications from old/new rdn */
636         rc = slap_modrdn2mods( be, conn, op, e, old_rdn, new_rdn, 
637                         deleteoldrdn, &mod );
638         if ( rc != LDAP_SUCCESS ) {
639                 goto return_results;
640         }
641         
642         /* delete old one */
643         rc = bdb_dn2id_delete( be, ltid, p_ndn.bv_val, e );
644         if ( rc != 0 ) {
645                 switch( rc ) {
646                 case DB_LOCK_DEADLOCK:
647                 case DB_LOCK_NOTGRANTED:
648                         goto retry;
649                 }
650                 rc = LDAP_OTHER;
651                 text = "DN index delete fail";
652                 goto return_results;
653         }
654
655         (void) bdb_cache_delete_entry(&bdb->bi_cache, e);
656
657         /* Binary format uses a single contiguous block, cannot
658          * free individual fields. Leave new_dn/new_ndn set so
659          * they can be individually freed later.
660          */
661         e->e_name = new_dn;
662         e->e_nname = new_ndn;
663
664         new_dn.bv_val = NULL;
665         new_ndn.bv_val = NULL;
666
667         /* add new one */
668         rc = bdb_dn2id_add( be, ltid, np_ndn, e );
669         if ( rc != 0 ) {
670                 switch( rc ) {
671                 case DB_LOCK_DEADLOCK:
672                 case DB_LOCK_NOTGRANTED:
673                         goto retry;
674                 }
675                 rc = LDAP_OTHER;
676                 text = "DN index add failed";
677                 goto return_results;
678         }
679
680         /* modify entry */
681         rc = bdb_modify_internal( be, conn, op, ltid, &mod[0], e,
682                 &text, textbuf, textlen );
683
684         if( rc != LDAP_SUCCESS ) {
685                 switch( rc ) {
686                 case DB_LOCK_DEADLOCK:
687                 case DB_LOCK_NOTGRANTED:
688                         goto retry;
689                 }
690                 goto return_results;
691         }
692         
693         /* id2entry index */
694         rc = bdb_id2entry_update( be, ltid, e );
695         if ( rc != 0 ) {
696                 switch( rc ) {
697                 case DB_LOCK_DEADLOCK:
698                 case DB_LOCK_NOTGRANTED:
699                         goto retry;
700                 }
701                 rc = LDAP_OTHER;
702                 text = "entry update failed";
703                 goto return_results;
704         }
705
706         if( op->o_noop ) {
707                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
708                         text = "txn_abort (no-op) failed";
709                 } else {
710                         noop = 1;
711                         rc = LDAP_SUCCESS;
712                 }
713
714         } else {
715                 char gid[DB_XIDDATASIZE];
716
717                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
718                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
719
720                 if(( rc=TXN_PREPARE( ltid, gid )) != 0 ) {
721                         text = "txn_prepare failed";
722                 } else {
723                         if( bdb_cache_update_entry(&bdb->bi_cache, e) == -1 ) {
724                                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
725                                         text ="cache update & txn_abort failed";
726                                 } else {
727                                         rc = LDAP_OTHER;
728                                         text = "cache update failed";
729                                 }
730
731                         } else {
732                                 if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) {
733                                         text = "txn_commit failed";
734                                 } else {
735                                         rc = LDAP_SUCCESS;
736                                 }
737                         }
738                 }
739         }
740  
741         ltid = NULL;
742         op->o_private = NULL;
743  
744         if( rc == LDAP_SUCCESS ) {
745 #ifdef NEW_LOGGING
746                 LDAP_LOG ( OPERATION, RESULTS, 
747                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 
748                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
749 #else
750                 Debug(LDAP_DEBUG_TRACE,
751                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n",
752                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
753 #endif
754                 text = NULL;
755                 if ( !noop ) {
756                         bdb_cache_entry_commit( e );
757                 }
758
759         } else {
760 #ifdef NEW_LOGGING
761                 LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", 
762                         text, db_strerror(rc), rc );
763 #else
764                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
765                         text, db_strerror(rc), rc );
766 #endif
767                 rc = LDAP_OTHER;
768         }
769
770 return_results:
771         send_ldap_result( conn, op, rc,
772                 NULL, text, NULL, NULL );
773
774         if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
775                 ldap_pvt_thread_yield();
776                 TXN_CHECKPOINT( bdb->bi_dbenv,
777                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
778         }
779
780 done:
781         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
782         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
783
784         /* LDAP v2 supporting correct attribute handling. */
785         if ( new_rdn != NULL ) {
786                 ldap_rdnfree( new_rdn );
787         }
788         if ( old_rdn != NULL ) {
789                 ldap_rdnfree( old_rdn );
790         }
791         if( mod != NULL ) {
792                 Modifications *tmp;
793                 for (; mod; mod=tmp ) {
794                         tmp = mod->sml_next;
795                         free( mod );
796                 }
797         }
798
799         /* LDAP v3 Support */
800         if( np != NULL ) {
801                 /* free new parent and reader lock */
802                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
803         }
804
805         if( p != NULL ) {
806                 /* free parent and reader lock */
807                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
808         }
809
810         /* free entry */
811         if( e != NULL ) {
812                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
813         }
814
815         if( ltid != NULL ) {
816                 TXN_ABORT( ltid );
817                 op->o_private = NULL;
818         }
819
820         return ( ( rc == LDAP_SUCCESS ) ? noop : rc );
821 }