Home | History | Annotate | Line # | Download | only in back-mdb
delete.c revision 1.1.1.3.6.1
      1  1.1.1.3.6.1    martin /*	$NetBSD: delete.c,v 1.1.1.3.6.1 2019/08/10 06:17:18 martin Exp $	*/
      2          1.1      tron 
      3          1.1      tron /* delete.c - mdb backend delete routine */
      4          1.1      tron /* $OpenLDAP$ */
      5          1.1      tron /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6          1.1      tron  *
      7  1.1.1.3.6.1    martin  * Copyright 2000-2019 The OpenLDAP Foundation.
      8          1.1      tron  * All rights reserved.
      9          1.1      tron  *
     10          1.1      tron  * Redistribution and use in source and binary forms, with or without
     11          1.1      tron  * modification, are permitted only as authorized by the OpenLDAP
     12          1.1      tron  * Public License.
     13          1.1      tron  *
     14          1.1      tron  * A copy of this license is available in the file LICENSE in the
     15          1.1      tron  * top-level directory of the distribution or, alternatively, at
     16          1.1      tron  * <http://www.OpenLDAP.org/license.html>.
     17          1.1      tron  */
     18          1.1      tron 
     19      1.1.1.2  christos #include <sys/cdefs.h>
     20  1.1.1.3.6.1    martin __RCSID("$NetBSD: delete.c,v 1.1.1.3.6.1 2019/08/10 06:17:18 martin Exp $");
     21      1.1.1.2  christos 
     22          1.1      tron #include "portable.h"
     23          1.1      tron 
     24          1.1      tron #include <stdio.h>
     25          1.1      tron #include <ac/string.h>
     26          1.1      tron 
     27          1.1      tron #include "lutil.h"
     28          1.1      tron #include "back-mdb.h"
     29          1.1      tron 
     30          1.1      tron int
     31          1.1      tron mdb_delete( Operation *op, SlapReply *rs )
     32          1.1      tron {
     33          1.1      tron 	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
     34          1.1      tron 	struct berval	pdn = {0, NULL};
     35          1.1      tron 	Entry	*e = NULL;
     36          1.1      tron 	Entry	*p = NULL;
     37          1.1      tron 	int		manageDSAit = get_manageDSAit( op );
     38          1.1      tron 	AttributeDescription *children = slap_schema.si_ad_children;
     39          1.1      tron 	AttributeDescription *entry = slap_schema.si_ad_entry;
     40          1.1      tron 	MDB_txn		*txn = NULL;
     41          1.1      tron 	MDB_cursor	*mc;
     42          1.1      tron 	mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
     43          1.1      tron 
     44          1.1      tron 	LDAPControl **preread_ctrl = NULL;
     45          1.1      tron 	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
     46          1.1      tron 	int num_ctrls = 0;
     47          1.1      tron 
     48          1.1      tron 	int	parent_is_glue = 0;
     49          1.1      tron 	int parent_is_leaf = 0;
     50          1.1      tron 
     51          1.1      tron #ifdef LDAP_X_TXN
     52          1.1      tron 	int settle = 0;
     53          1.1      tron #endif
     54          1.1      tron 
     55          1.1      tron 	Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_delete) ": %s\n",
     56          1.1      tron 		op->o_req_dn.bv_val, 0, 0 );
     57          1.1      tron 
     58          1.1      tron #ifdef LDAP_X_TXN
     59          1.1      tron 	if( op->o_txnSpec ) {
     60          1.1      tron 		/* acquire connection lock */
     61          1.1      tron 		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
     62          1.1      tron 		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
     63          1.1      tron 			rs->sr_text = "invalid transaction identifier";
     64          1.1      tron 			rs->sr_err = LDAP_X_TXN_ID_INVALID;
     65          1.1      tron 			goto txnReturn;
     66          1.1      tron 		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
     67          1.1      tron 			settle=1;
     68          1.1      tron 			goto txnReturn;
     69          1.1      tron 		}
     70          1.1      tron 
     71          1.1      tron 		if( op->o_conn->c_txn_backend == NULL ) {
     72          1.1      tron 			op->o_conn->c_txn_backend = op->o_bd;
     73          1.1      tron 
     74          1.1      tron 		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
     75          1.1      tron 			rs->sr_text = "transaction cannot span multiple database contexts";
     76          1.1      tron 			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
     77          1.1      tron 			goto txnReturn;
     78          1.1      tron 		}
     79          1.1      tron 
     80          1.1      tron 		/* insert operation into transaction */
     81          1.1      tron 
     82          1.1      tron 		rs->sr_text = "transaction specified";
     83          1.1      tron 		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
     84          1.1      tron 
     85          1.1      tron txnReturn:
     86          1.1      tron 		/* release connection lock */
     87          1.1      tron 		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
     88          1.1      tron 
     89          1.1      tron 		if( !settle ) {
     90          1.1      tron 			send_ldap_result( op, rs );
     91          1.1      tron 			return rs->sr_err;
     92          1.1      tron 		}
     93          1.1      tron 	}
     94          1.1      tron #endif
     95          1.1      tron 
     96          1.1      tron 	ctrls[num_ctrls] = 0;
     97          1.1      tron 
     98          1.1      tron 	/* begin transaction */
     99          1.1      tron 	rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
    100          1.1      tron 	rs->sr_text = NULL;
    101          1.1      tron 	if( rs->sr_err != 0 ) {
    102          1.1      tron 		Debug( LDAP_DEBUG_TRACE,
    103          1.1      tron 			LDAP_XSTRING(mdb_delete) ": txn_begin failed: "
    104          1.1      tron 			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    105          1.1      tron 		rs->sr_err = LDAP_OTHER;
    106          1.1      tron 		rs->sr_text = "internal error";
    107          1.1      tron 		goto return_results;
    108          1.1      tron 	}
    109          1.1      tron 	txn = moi->moi_txn;
    110          1.1      tron 
    111          1.1      tron 	/* allocate CSN */
    112          1.1      tron 	if ( BER_BVISNULL( &op->o_csn ) ) {
    113          1.1      tron 		struct berval csn;
    114          1.1      tron 		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
    115          1.1      tron 
    116          1.1      tron 		csn.bv_val = csnbuf;
    117          1.1      tron 		csn.bv_len = sizeof(csnbuf);
    118          1.1      tron 		slap_get_csn( op, &csn, 1 );
    119          1.1      tron 	}
    120          1.1      tron 
    121          1.1      tron 	if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
    122          1.1      tron 		dnParent( &op->o_req_ndn, &pdn );
    123          1.1      tron 	}
    124          1.1      tron 
    125          1.1      tron 	rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc );
    126          1.1      tron 	if ( rs->sr_err ) {
    127          1.1      tron 		rs->sr_err = LDAP_OTHER;
    128          1.1      tron 		rs->sr_text = "internal error";
    129          1.1      tron 		goto return_results;
    130          1.1      tron 	}
    131          1.1      tron 	/* get parent */
    132          1.1      tron 	rs->sr_err = mdb_dn2entry( op, txn, mc, &pdn, &p, NULL, 1 );
    133          1.1      tron 	switch( rs->sr_err ) {
    134          1.1      tron 	case 0:
    135          1.1      tron 	case MDB_NOTFOUND:
    136          1.1      tron 		break;
    137          1.1      tron 	case LDAP_BUSY:
    138          1.1      tron 		rs->sr_text = "ldap server busy";
    139          1.1      tron 		goto return_results;
    140          1.1      tron 	default:
    141          1.1      tron 		rs->sr_err = LDAP_OTHER;
    142          1.1      tron 		rs->sr_text = "internal error";
    143          1.1      tron 		goto return_results;
    144          1.1      tron 	}
    145          1.1      tron 	if ( rs->sr_err == MDB_NOTFOUND ) {
    146          1.1      tron 		Debug( LDAP_DEBUG_ARGS,
    147          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
    148          1.1      tron 			op->o_req_dn.bv_val, 0, 0);
    149          1.1      tron 
    150          1.1      tron 		if ( p && !BER_BVISEMPTY( &p->e_name )) {
    151          1.1      tron 			rs->sr_matched = ch_strdup( p->e_name.bv_val );
    152          1.1      tron 			if ( is_entry_referral( p )) {
    153          1.1      tron 				BerVarray ref = get_entry_referrals( op, p );
    154          1.1      tron 				rs->sr_ref = referral_rewrite( ref, &p->e_name,
    155          1.1      tron 					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
    156          1.1      tron 				ber_bvarray_free( ref );
    157          1.1      tron 			} else {
    158          1.1      tron 				rs->sr_ref = NULL;
    159          1.1      tron 			}
    160          1.1      tron 		} else {
    161          1.1      tron 			rs->sr_ref = referral_rewrite( default_referral, NULL,
    162          1.1      tron 					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
    163          1.1      tron 		}
    164          1.1      tron 		if ( p ) {
    165          1.1      tron 			mdb_entry_return( op, p );
    166          1.1      tron 			p = NULL;
    167          1.1      tron 		}
    168          1.1      tron 
    169          1.1      tron 		rs->sr_err = LDAP_REFERRAL;
    170          1.1      tron 		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
    171          1.1      tron 		goto return_results;
    172          1.1      tron 	}
    173          1.1      tron 
    174          1.1      tron 	/* get entry */
    175          1.1      tron 	rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, NULL, 0 );
    176          1.1      tron 	switch( rs->sr_err ) {
    177          1.1      tron 	case MDB_NOTFOUND:
    178          1.1      tron 		e = p;
    179          1.1      tron 		p = NULL;
    180          1.1      tron 	case 0:
    181          1.1      tron 		break;
    182          1.1      tron 	case LDAP_BUSY:
    183          1.1      tron 		rs->sr_text = "ldap server busy";
    184          1.1      tron 		goto return_results;
    185          1.1      tron 	default:
    186          1.1      tron 		rs->sr_err = LDAP_OTHER;
    187          1.1      tron 		rs->sr_text = "internal error";
    188          1.1      tron 		goto return_results;
    189          1.1      tron 	}
    190          1.1      tron 
    191          1.1      tron 	/* FIXME : dn2entry() should return non-glue entry */
    192          1.1      tron 	if ( rs->sr_err == MDB_NOTFOUND || ( !manageDSAit && is_entry_glue( e ))) {
    193          1.1      tron 		Debug( LDAP_DEBUG_ARGS,
    194          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
    195          1.1      tron 			op->o_req_dn.bv_val, 0, 0);
    196          1.1      tron 
    197          1.1      tron 		rs->sr_matched = ch_strdup( e->e_dn );
    198          1.1      tron 		if ( is_entry_referral( e )) {
    199          1.1      tron 			BerVarray ref = get_entry_referrals( op, e );
    200          1.1      tron 			rs->sr_ref = referral_rewrite( ref, &e->e_name,
    201          1.1      tron 				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
    202          1.1      tron 			ber_bvarray_free( ref );
    203          1.1      tron 		} else {
    204          1.1      tron 			rs->sr_ref = NULL;
    205          1.1      tron 		}
    206          1.1      tron 		mdb_entry_return( op, e );
    207          1.1      tron 		e = NULL;
    208          1.1      tron 
    209          1.1      tron 		rs->sr_err = LDAP_REFERRAL;
    210          1.1      tron 		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
    211          1.1      tron 		goto return_results;
    212          1.1      tron 	}
    213          1.1      tron 
    214          1.1      tron 	if ( pdn.bv_len != 0 ) {
    215          1.1      tron 		/* check parent for "children" acl */
    216          1.1      tron 		rs->sr_err = access_allowed( op, p,
    217          1.1      tron 			children, NULL, ACL_WDEL, NULL );
    218          1.1      tron 
    219          1.1      tron 		if ( !rs->sr_err  ) {
    220          1.1      tron 			Debug( LDAP_DEBUG_TRACE,
    221          1.1      tron 				"<=- " LDAP_XSTRING(mdb_delete) ": no write "
    222          1.1      tron 				"access to parent\n", 0, 0, 0 );
    223          1.1      tron 			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
    224          1.1      tron 			rs->sr_text = "no write access to parent";
    225          1.1      tron 			goto return_results;
    226          1.1      tron 		}
    227          1.1      tron 
    228          1.1      tron 	} else {
    229          1.1      tron 		/* no parent, must be root to delete */
    230          1.1      tron 		if( ! be_isroot( op ) ) {
    231          1.1      tron 			if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
    232          1.1      tron 				|| be_shadow_update( op ) ) {
    233          1.1      tron 				p = (Entry *)&slap_entry_root;
    234          1.1      tron 
    235          1.1      tron 				/* check parent for "children" acl */
    236          1.1      tron 				rs->sr_err = access_allowed( op, p,
    237          1.1      tron 					children, NULL, ACL_WDEL, NULL );
    238          1.1      tron 
    239          1.1      tron 				p = NULL;
    240          1.1      tron 
    241          1.1      tron 				if ( !rs->sr_err  ) {
    242          1.1      tron 					Debug( LDAP_DEBUG_TRACE,
    243          1.1      tron 						"<=- " LDAP_XSTRING(mdb_delete)
    244          1.1      tron 						": no access to parent\n",
    245          1.1      tron 						0, 0, 0 );
    246          1.1      tron 					rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
    247          1.1      tron 					rs->sr_text = "no write access to parent";
    248          1.1      tron 					goto return_results;
    249          1.1      tron 				}
    250          1.1      tron 
    251          1.1      tron 			} else {
    252          1.1      tron 				Debug( LDAP_DEBUG_TRACE,
    253          1.1      tron 					"<=- " LDAP_XSTRING(mdb_delete)
    254          1.1      tron 					": no parent and not root\n", 0, 0, 0 );
    255          1.1      tron 				rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
    256          1.1      tron 				goto return_results;
    257          1.1      tron 			}
    258          1.1      tron 		}
    259          1.1      tron 	}
    260          1.1      tron 
    261          1.1      tron 	if ( get_assert( op ) &&
    262          1.1      tron 		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
    263          1.1      tron 	{
    264          1.1      tron 		rs->sr_err = LDAP_ASSERTION_FAILED;
    265          1.1      tron 		goto return_results;
    266          1.1      tron 	}
    267          1.1      tron 
    268          1.1      tron 	rs->sr_err = access_allowed( op, e,
    269          1.1      tron 		entry, NULL, ACL_WDEL, NULL );
    270          1.1      tron 
    271          1.1      tron 	if ( !rs->sr_err  ) {
    272          1.1      tron 		Debug( LDAP_DEBUG_TRACE,
    273          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": no write access "
    274          1.1      tron 			"to entry\n", 0, 0, 0 );
    275          1.1      tron 		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
    276          1.1      tron 		rs->sr_text = "no write access to entry";
    277          1.1      tron 		goto return_results;
    278          1.1      tron 	}
    279          1.1      tron 
    280          1.1      tron 	if ( !manageDSAit && is_entry_referral( e ) ) {
    281          1.1      tron 		/* entry is a referral, don't allow delete */
    282          1.1      tron 		rs->sr_ref = get_entry_referrals( op, e );
    283          1.1      tron 
    284          1.1      tron 		Debug( LDAP_DEBUG_TRACE,
    285          1.1      tron 			LDAP_XSTRING(mdb_delete) ": entry is referral\n",
    286          1.1      tron 			0, 0, 0 );
    287          1.1      tron 
    288          1.1      tron 		rs->sr_err = LDAP_REFERRAL;
    289          1.1      tron 		rs->sr_matched = ch_strdup( e->e_name.bv_val );
    290          1.1      tron 		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
    291          1.1      tron 		goto return_results;
    292          1.1      tron 	}
    293          1.1      tron 
    294          1.1      tron 	/* pre-read */
    295          1.1      tron 	if( op->o_preread ) {
    296          1.1      tron 		if( preread_ctrl == NULL ) {
    297          1.1      tron 			preread_ctrl = &ctrls[num_ctrls++];
    298          1.1      tron 			ctrls[num_ctrls] = NULL;
    299          1.1      tron 		}
    300          1.1      tron 		if( slap_read_controls( op, rs, e,
    301          1.1      tron 			&slap_pre_read_bv, preread_ctrl ) )
    302          1.1      tron 		{
    303          1.1      tron 			Debug( LDAP_DEBUG_TRACE,
    304          1.1      tron 				"<=- " LDAP_XSTRING(mdb_delete) ": pre-read "
    305          1.1      tron 				"failed!\n", 0, 0, 0 );
    306          1.1      tron 			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
    307          1.1      tron 				/* FIXME: is it correct to abort
    308          1.1      tron 				 * operation if control fails? */
    309          1.1      tron 				goto return_results;
    310          1.1      tron 			}
    311          1.1      tron 		}
    312          1.1      tron 	}
    313          1.1      tron 
    314          1.1      tron 	rs->sr_text = NULL;
    315          1.1      tron 
    316          1.1      tron 	/* Can't do it if we have kids */
    317          1.1      tron 	rs->sr_err = mdb_dn2id_children( op, txn, e );
    318          1.1      tron 	if( rs->sr_err != MDB_NOTFOUND ) {
    319          1.1      tron 		switch( rs->sr_err ) {
    320          1.1      tron 		case 0:
    321          1.1      tron 			Debug(LDAP_DEBUG_ARGS,
    322          1.1      tron 				"<=- " LDAP_XSTRING(mdb_delete)
    323          1.1      tron 				": non-leaf %s\n",
    324          1.1      tron 				op->o_req_dn.bv_val, 0, 0);
    325          1.1      tron 			rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
    326          1.1      tron 			rs->sr_text = "subordinate objects must be deleted first";
    327          1.1      tron 			break;
    328          1.1      tron 		default:
    329          1.1      tron 			Debug(LDAP_DEBUG_ARGS,
    330          1.1      tron 				"<=- " LDAP_XSTRING(mdb_delete)
    331          1.1      tron 				": has_children failed: %s (%d)\n",
    332          1.1      tron 				mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    333          1.1      tron 			rs->sr_err = LDAP_OTHER;
    334          1.1      tron 			rs->sr_text = "internal error";
    335          1.1      tron 		}
    336          1.1      tron 		goto return_results;
    337          1.1      tron 	}
    338          1.1      tron 
    339          1.1      tron 	/* delete from dn2id */
    340          1.1      tron 	rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id, 1 );
    341          1.1      tron 	mdb_cursor_close( mc );
    342          1.1      tron 	if ( rs->sr_err != 0 ) {
    343          1.1      tron 		Debug(LDAP_DEBUG_TRACE,
    344          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": dn2id failed: "
    345          1.1      tron 			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    346          1.1      tron 		rs->sr_text = "DN index delete failed";
    347          1.1      tron 		rs->sr_err = LDAP_OTHER;
    348          1.1      tron 		goto return_results;
    349          1.1      tron 	}
    350          1.1      tron 
    351          1.1      tron 	/* delete indices for old attributes */
    352          1.1      tron 	rs->sr_err = mdb_index_entry_del( op, txn, e );
    353          1.1      tron 	if ( rs->sr_err != LDAP_SUCCESS ) {
    354          1.1      tron 		Debug(LDAP_DEBUG_TRACE,
    355          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": index failed: "
    356          1.1      tron 			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    357          1.1      tron 		rs->sr_text = "entry index delete failed";
    358          1.1      tron 		rs->sr_err = LDAP_OTHER;
    359          1.1      tron 		goto return_results;
    360          1.1      tron 	}
    361          1.1      tron 
    362          1.1      tron 	/* fixup delete CSN */
    363          1.1      tron 	if ( !SLAP_SHADOW( op->o_bd )) {
    364          1.1      tron 		struct berval vals[2];
    365          1.1      tron 
    366          1.1      tron 		assert( !BER_BVISNULL( &op->o_csn ) );
    367          1.1      tron 		vals[0] = op->o_csn;
    368          1.1      tron 		BER_BVZERO( &vals[1] );
    369          1.1      tron 		rs->sr_err = mdb_index_values( op, txn, slap_schema.si_ad_entryCSN,
    370          1.1      tron 			vals, 0, SLAP_INDEX_ADD_OP );
    371          1.1      tron 		if ( rs->sr_err != LDAP_SUCCESS ) {
    372          1.1      tron 			rs->sr_text = "entryCSN index update failed";
    373          1.1      tron 			rs->sr_err = LDAP_OTHER;
    374          1.1      tron 			goto return_results;
    375          1.1      tron 		}
    376          1.1      tron 	}
    377          1.1      tron 
    378          1.1      tron 	/* delete from id2entry */
    379          1.1      tron 	rs->sr_err = mdb_id2entry_delete( op->o_bd, txn, e );
    380          1.1      tron 	if ( rs->sr_err != 0 ) {
    381          1.1      tron 		Debug( LDAP_DEBUG_TRACE,
    382          1.1      tron 			"<=- " LDAP_XSTRING(mdb_delete) ": id2entry failed: "
    383          1.1      tron 			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    384          1.1      tron 		rs->sr_text = "entry delete failed";
    385          1.1      tron 		rs->sr_err = LDAP_OTHER;
    386          1.1      tron 		goto return_results;
    387          1.1      tron 	}
    388          1.1      tron 
    389          1.1      tron 	if ( pdn.bv_len != 0 ) {
    390          1.1      tron 		parent_is_glue = is_entry_glue(p);
    391          1.1      tron 		rs->sr_err = mdb_dn2id_children( op, txn, p );
    392          1.1      tron 		if ( rs->sr_err != MDB_NOTFOUND ) {
    393          1.1      tron 			switch( rs->sr_err ) {
    394          1.1      tron 			case 0:
    395          1.1      tron 				break;
    396          1.1      tron 			default:
    397          1.1      tron 				Debug(LDAP_DEBUG_ARGS,
    398          1.1      tron 					"<=- " LDAP_XSTRING(mdb_delete)
    399          1.1      tron 					": has_children failed: %s (%d)\n",
    400          1.1      tron 					mdb_strerror(rs->sr_err), rs->sr_err, 0 );
    401          1.1      tron 				rs->sr_err = LDAP_OTHER;
    402          1.1      tron 				rs->sr_text = "internal error";
    403          1.1      tron 				goto return_results;
    404          1.1      tron 			}
    405          1.1      tron 			parent_is_leaf = 1;
    406          1.1      tron 		}
    407          1.1      tron 		mdb_entry_return( op, p );
    408          1.1      tron 		p = NULL;
    409          1.1      tron 	}
    410          1.1      tron 
    411          1.1      tron 	if( moi == &opinfo ) {
    412          1.1      tron 		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
    413          1.1      tron 		opinfo.moi_oe.oe_key = NULL;
    414          1.1      tron 		if( op->o_noop ) {
    415          1.1      tron 			mdb_txn_abort( txn );
    416          1.1      tron 			rs->sr_err = LDAP_X_NO_OPERATION;
    417          1.1      tron 			txn = NULL;
    418          1.1      tron 			goto return_results;
    419          1.1      tron 		} else {
    420          1.1      tron 			rs->sr_err = mdb_txn_commit( txn );
    421          1.1      tron 		}
    422          1.1      tron 		txn = NULL;
    423          1.1      tron 	}
    424          1.1      tron 
    425          1.1      tron 	if( rs->sr_err != 0 ) {
    426          1.1      tron 		Debug( LDAP_DEBUG_ANY,
    427          1.1      tron 			LDAP_XSTRING(mdb_delete) ": txn_%s failed: %s (%d)\n",
    428          1.1      tron 			op->o_noop ? "abort (no-op)" : "commit",
    429          1.1      tron 			mdb_strerror(rs->sr_err), rs->sr_err );
    430          1.1      tron 		rs->sr_err = LDAP_OTHER;
    431          1.1      tron 		rs->sr_text = "commit failed";
    432          1.1      tron 
    433          1.1      tron 		goto return_results;
    434          1.1      tron 	}
    435          1.1      tron 
    436          1.1      tron 	Debug( LDAP_DEBUG_TRACE,
    437          1.1      tron 		LDAP_XSTRING(mdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
    438          1.1      tron 		op->o_noop ? " (no-op)" : "",
    439          1.1      tron 		e->e_id, op->o_req_dn.bv_val );
    440          1.1      tron 	rs->sr_err = LDAP_SUCCESS;
    441          1.1      tron 	rs->sr_text = NULL;
    442          1.1      tron 	if( num_ctrls ) rs->sr_ctrls = ctrls;
    443          1.1      tron 
    444          1.1      tron return_results:
    445          1.1      tron 	if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
    446          1.1      tron 		op->o_delete_glue_parent = 1;
    447          1.1      tron 	}
    448          1.1      tron 
    449          1.1      tron 	if ( p != NULL ) {
    450          1.1      tron 		mdb_entry_return( op, p );
    451          1.1      tron 	}
    452          1.1      tron 
    453          1.1      tron 	/* free entry */
    454          1.1      tron 	if( e != NULL ) {
    455          1.1      tron 		mdb_entry_return( op, e );
    456          1.1      tron 	}
    457          1.1      tron 
    458          1.1      tron 	if( moi == &opinfo ) {
    459          1.1      tron 		if( txn != NULL ) {
    460          1.1      tron 			mdb_txn_abort( txn );
    461          1.1      tron 		}
    462          1.1      tron 		if ( opinfo.moi_oe.oe_key ) {
    463          1.1      tron 			LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
    464          1.1      tron 		}
    465          1.1      tron 	} else {
    466          1.1      tron 		moi->moi_ref--;
    467          1.1      tron 	}
    468          1.1      tron 
    469          1.1      tron 	send_ldap_result( op, rs );
    470          1.1      tron 	slap_graduate_commit_csn( op );
    471          1.1      tron 
    472          1.1      tron 	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
    473          1.1      tron 		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
    474          1.1      tron 		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
    475          1.1      tron 	}
    476          1.1      tron 
    477          1.1      tron #if 0
    478          1.1      tron 	if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
    479          1.1      tron 		TXN_CHECKPOINT( mdb->bi_dbenv,
    480          1.1      tron 			mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
    481          1.1      tron 	}
    482          1.1      tron #endif
    483          1.1      tron 	return rs->sr_err;
    484          1.1      tron }
    485