static void send_result( Operation *op, SlapReply *rs, sort_op *so) { LDAPControl *ctrls[3]; int rc, i = 0; rc = pack_sss_response_control( op, rs, ctrls ); if ( rc == LDAP_SUCCESS ) { i++; rc = -1; if ( so->so_paged > SLAP_CONTROL_IGNORED ) { rc = pack_pagedresult_response_control( op, rs, so, ctrls+1 ); } else if ( so->so_vlv > SLAP_CONTROL_IGNORED ) { rc = pack_vlv_response_control( op, rs, so, ctrls+1 ); } if ( rc == LDAP_SUCCESS ) i++; } ctrls[i] = NULL; if ( ctrls[0] != NULL ) slap_add_ctrls( op, rs, ctrls ); send_ldap_result( op, rs ); if ( so->so_tree == NULL ) { /* Search finished, so clean up */ free_sort_op( op->o_conn, so ); } else { so->so_running = 0; } }
static void send_paged_response( Operation *op, SlapReply *rs, ID *lastid, int tentries ) { LDAPControl *ctrls[2]; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; PagedResultsCookie respcookie; struct berval cookie; Debug(LDAP_DEBUG_ARGS, "send_paged_response: lastid=0x%08lx nentries=%d\n", lastid ? *lastid : 0, rs->sr_nentries, NULL ); ctrls[1] = NULL; ber_init2( ber, NULL, LBER_USE_DER ); if ( lastid ) { respcookie = ( PagedResultsCookie )(*lastid); cookie.bv_len = sizeof( respcookie ); cookie.bv_val = (char *)&respcookie; } else { respcookie = ( PagedResultsCookie )0; BER_BVSTR( &cookie, "" ); } op->o_conn->c_pagedresults_state.ps_cookie = respcookie; op->o_conn->c_pagedresults_state.ps_count = ((PagedResultsState *)op->o_pagedresults_state)->ps_count + rs->sr_nentries; /* return size of 0 -- no estimate */ ber_printf( ber, "{iO}", 0, &cookie ); ctrls[0] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx ); if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { goto done; } ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; ctrls[0]->ldctl_iscritical = 0; slap_add_ctrls( op, rs, ctrls ); rs->sr_err = LDAP_SUCCESS; send_ldap_result( op, rs ); done: (void) ber_free_buf( ber ); }
static int dupent_response_entry_1level( Operation *op, SlapReply *rs, Entry *e, valnum_t *valnum, int nattrs, int level ) { int i, rc = LDAP_SUCCESS; for ( i = 0; i < valnum[level].ap->a_numvals; i++ ) { LDAPControl *ctrl = NULL, *ctrlsp[2]; valnum[level].a.a_vals[0] = valnum[level].ap->a_vals[i]; if ( valnum[level].ap->a_nvals != valnum[level].ap->a_vals ) { valnum[level].a.a_nvals[0] = valnum[level].ap->a_nvals[i]; } if ( level < nattrs - 1 ) { rc = dupent_response_entry_1level( op, rs, e, valnum, nattrs, level + 1 ); if ( rc != LDAP_SUCCESS ) { break; } continue; } /* NOTE: add the control all times, under the assumption * send_search_entry() honors the REP_CTRLS_MUSTBEFREED * set by slap_add_ctrls(); this is not true (ITS#6629) */ ctrl = op->o_tmpcalloc( 1, sizeof( LDAPControl ), op->o_tmpmemctx ); ctrl->ldctl_oid = LDAP_CONTROL_DUPENT_ENTRY; ctrl->ldctl_iscritical = 0; ctrlsp[0] = ctrl; ctrlsp[1] = NULL; slap_add_ctrls( op, rs, ctrlsp ); /* do the real send */ rs->sr_entry = e; rc = send_search_entry( op, rs ); if ( rc != LDAP_SUCCESS ) { break; } } return rc; }
static int dupent_response_done( Operation *op, SlapReply *rs ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *) &berbuf; struct berval ctrlval; LDAPControl *ctrl, *ctrlsp[2]; ber_init2( ber, NULL, LBER_USE_DER ); /* DuplicateEntryResponseDone ::= SEQUENCE { resultCode, -- From [RFC2251] errorMessage [0] LDAPString OPTIONAL, attribute [1] AttributeDescription OPTIONAL } */ ber_printf( ber, "{i}", rs->sr_err ); if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { ber_free_buf( ber ); if ( op->o_dupent == SLAP_CONTROL_CRITICAL ) { return LDAP_CONSTRAINT_VIOLATION; } return SLAP_CB_CONTINUE; } ctrl = op->o_tmpcalloc( 1, sizeof( LDAPControl ) + ctrlval.bv_len + 1, op->o_tmpmemctx ); ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; ctrl->ldctl_oid = LDAP_CONTROL_DUPENT_RESPONSE; ctrl->ldctl_iscritical = 0; ctrl->ldctl_value.bv_len = ctrlval.bv_len; AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; ber_free_buf( ber ); ctrlsp[0] = ctrl; ctrlsp[1] = NULL; slap_add_ctrls( op, rs, ctrlsp ); return SLAP_CB_CONTINUE; }
static int deref_response( Operation *op, SlapReply *rs ) { int rc = SLAP_CB_CONTINUE; if ( rs->sr_type == REP_SEARCH ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *) &berbuf; deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private; DerefSpec *ds; DerefRes *dr, *drhead = NULL, **drp = &drhead; struct berval bv = BER_BVNULL; int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0; struct berval ctrlval; LDAPControl *ctrl, *ctrlsp[2]; AccessControlState acl_state = ACL_STATE_INIT; static char dummy = '\0'; Entry *ebase; int i; rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on ); if ( rc != LDAP_SUCCESS || ebase == NULL ) { return SLAP_CB_CONTINUE; } for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) { Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr ); if ( a != NULL ) { DerefVal *dv; BerVarray *bva; if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL, ACL_READ, &acl_state ) ) { continue; } dr = op->o_tmpcalloc( 1, sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ), op->o_tmpmemctx ); dr->dr_spec = *ds; dv = dr->dr_vals = (DerefVal *)&dr[ 1 ]; bva = (BerVarray *)&dv[ a->a_numvals + 1 ]; bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len; nAttrs++; nDerefRes++; for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { Entry *e = NULL; dv[ i ].dv_attrVals = bva; bva += ds->ds_nattrs; if ( !access_allowed( op, rs->sr_entry, a->a_desc, &a->a_nvals[ i ], ACL_READ, &acl_state ) ) { dv[ i ].dv_derefSpecVal.bv_val = &dummy; continue; } ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx ); bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len; nVals++; nDerefVals++; rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on ); if ( rc == LDAP_SUCCESS && e != NULL ) { int j; if ( access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_READ, NULL ) ) { for ( j = 0; j < ds->ds_nattrs; j++ ) { Attribute *aa; if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL, ACL_READ, &acl_state ) ) { continue; } aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] ); if ( aa != NULL ) { unsigned k, h, last = aa->a_numvals; ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ], aa->a_vals, op->o_tmpmemctx ); bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len; for ( k = 0, h = 0; k < aa->a_numvals; k++ ) { if ( !access_allowed( op, e, aa->a_desc, &aa->a_nvals[ k ], ACL_READ, &acl_state ) ) { op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val, op->o_tmpmemctx ); dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ]; BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] ); continue; } bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len; nVals++; h++; } nAttrs++; } } } overlay_entry_release_ov( op, e, 0, dc->dc_on ); } } *drp = dr; drp = &dr->dr_next; } } overlay_entry_release_ov( op, ebase, 0, dc->dc_on ); if ( drhead == NULL ) { return SLAP_CB_CONTINUE; } /* cook the control value */ bv.bv_len += nVals * sizeof(struct berval) + nAttrs * sizeof(struct berval) + nDerefVals * sizeof(DerefVal) + nDerefRes * sizeof(DerefRes); bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx ); ber_init2( ber, &bv, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); rc = ber_printf( ber, "{" /*}*/ ); for ( dr = drhead; dr != NULL; dr = dr->dr_next ) { for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) { int j, first = 1; if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) { continue; } rc = ber_printf( ber, "{OO" /*}*/, &dr->dr_spec.ds_derefAttr->ad_cname, &dr->dr_vals[ i ].dv_derefSpecVal ); op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx ); for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) { if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) { if ( first ) { rc = ber_printf( ber, "t{" /*}*/, (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ); first = 0; } rc = ber_printf( ber, "{O[W]}", &dr->dr_spec.ds_attributes[ j ]->ad_cname, dr->dr_vals[ i ].dv_attrVals[ j ] ); op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ], op->o_tmpmemctx ); } } if ( !first ) { rc = ber_printf( ber, /*{{*/ "}N}" ); } else { rc = ber_printf( ber, /*{*/ "}" ); } } } rc = ber_printf( ber, /*{*/ "}" ); if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { if ( op->o_deref == SLAP_CONTROL_CRITICAL ) { rc = LDAP_CONSTRAINT_VIOLATION; } else { rc = SLAP_CB_CONTINUE; } goto cleanup; } ctrl = op->o_tmpcalloc( 1, sizeof( LDAPControl ) + ctrlval.bv_len + 1, op->o_tmpmemctx ); ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF; ctrl->ldctl_iscritical = 0; ctrl->ldctl_value.bv_len = ctrlval.bv_len; memcpy( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; ber_free_buf( ber ); ctrlsp[0] = ctrl; ctrlsp[1] = NULL; slap_add_ctrls( op, rs, ctrlsp ); rc = SLAP_CB_CONTINUE; cleanup:; /* release all */ for ( ; drhead != NULL; ) { DerefRes *drnext = drhead->dr_next; op->o_tmpfree( drhead, op->o_tmpmemctx ); drhead = drnext; } } else if ( rs->sr_type == REP_RESULT ) { rc = deref_cleanup( op, rs ); } return rc; }
static int sssvlv_op_search( Operation *op, SlapReply *rs) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; sssvlv_info *si = on->on_bi.bi_private; int rc = SLAP_CB_CONTINUE; int ok, need_unlock = 0; sort_ctrl *sc; PagedResultsState *ps; vlv_ctrl *vc; int sess_id; if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) { if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) { sort_op so; memset(&so, 0, sizeof(so)); so.so_vlv_rc = LDAP_VLV_SSS_MISSING; so.so_vlv = op->o_ctrlflag[vlv_cid]; LDAPControl *ctrls[2]; rc = pack_vlv_response_control( op, rs, &so, ctrls ); if ( rc == LDAP_SUCCESS ) { ctrls[1] = NULL; slap_add_ctrls( op, rs, ctrls ); } rs->sr_err = LDAP_VLV_ERROR; rs->sr_text = "Sort control is required with VLV"; goto leave; } /* Not server side sort so just continue */ return SLAP_CB_CONTINUE; } Debug(LDAP_DEBUG_TRACE, "==> sssvlv_search: <%s> %s, control flag: %d\n", op->o_req_dn.bv_val, op->ors_filterstr.bv_val, op->o_ctrlflag[sss_cid]); sc = op->o_controls[sss_cid]; if ( sc->sc_nkeys > si->svi_max_keys ) { rs->sr_text = "Too many sort keys"; rs->sr_err = LDAP_UNWILLING_TO_PERFORM; goto leave; } ps = ( op->o_pagedresults > SLAP_CONTROL_IGNORED ) ? (PagedResultsState*)(op->o_pagedresults_state) : NULL; vc = op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ? op->o_controls[vlv_cid] : NULL; if ( ps && vc ) { rs->sr_text = "VLV incompatible with PagedResults"; rs->sr_err = LDAP_UNWILLING_TO_PERFORM; goto leave; } ldap_pvt_thread_mutex_lock( &sort_conns_mutex ); ok = need_unlock = 1; sort_op *so = NULL; /* Is there already a sort running on this conn? */ sess_id = find_session_by_context( si->svi_max_percon, op->o_conn->c_conn_idx, vc ? vc->vc_context : NO_VC_CONTEXT, ps ? ps->ps_cookie : NO_PS_COOKIE ); if ( sess_id >= 0 ) { so = sort_conns[op->o_conn->c_conn_idx][sess_id]; if (so->so_running) { /* another thread is handling, response busy to client */ ok = 0; so = NULL; } else { /* Is it a continuation of a VLV search? */ if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED || vc->vc_context != so->so_vcontext ) { /* Is it a continuation of a paged search? */ if ( !ps || so->so_paged <= SLAP_CONTROL_IGNORED || op->o_conn->c_pagedresults_state.ps_cookie != ps->ps_cookie ) { ok = 0; } else if ( !ps->ps_size ) { /* Abandoning current request */ ok = 0; so->so_nentries = 0; rs->sr_err = LDAP_SUCCESS; } } if (( vc && so->so_paged > SLAP_CONTROL_IGNORED ) || ( ps && so->so_vlv > SLAP_CONTROL_IGNORED )) { /* changed from paged to vlv or vice versa, abandon */ ok = 0; so->so_nentries = 0; rs->sr_err = LDAP_UNWILLING_TO_PERFORM; } if ( ok ) { /* occupy before mutex unlock */ so->so_running = 1; } } /* Are there too many running overall? */ } else if ( si->svi_num >= si->svi_max ) { ok = 0; } else if ( ( sess_id = find_next_session(si->svi_max_percon, op->o_conn->c_conn_idx ) ) < 0 ) { ok = 0; } else { /* OK, this connection going a sort running as the sess_id */ } if (! ok || so != NULL) { assert(need_unlock != 0); ldap_pvt_thread_mutex_unlock( &sort_conns_mutex ); need_unlock = 0; } if ( ok ) { /* If we're a global overlay, this check got bypassed */ if ( !op->ors_limit && limits_check( op, rs )) { if (need_unlock) { ldap_pvt_thread_mutex_unlock( &sort_conns_mutex ); need_unlock = 0; } if (so) free_sort_op( op->o_conn, so ); return rs->sr_err; } /* are we continuing a VLV search? */ if ( so && vc && vc->vc_context ) { assert(need_unlock == 0); so->so_ctrl = sc; send_list( op, rs, so ); send_result( op, rs, so ); rc = LDAP_SUCCESS; /* are we continuing a paged search? */ } else if ( so && ps && ps->ps_cookie ) { assert(need_unlock == 0); so->so_ctrl = sc; send_page( op, rs, so ); send_result( op, rs, so ); rc = LDAP_SUCCESS; } else { /* Install serversort response callback to handle a new search */ assert(need_unlock != 0); assert(so == NULL); so = ch_calloc( 1, sizeof(sort_op)); slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx ); LDAP_ENSURE(so != NULL && cb != NULL); /* FIXME: LDAP_OTHER */ cb->sc_response = sssvlv_op_response; cb->sc_next = op->o_callback; cb->sc_private = so; assert(so->so_tree == NULL); so->so_ctrl = sc; so->so_info = si; if ( ps ) { so->so_paged = op->o_pagedresults; so->so_page_size = ps->ps_size; op->o_pagedresults = SLAP_CONTROL_IGNORED; assert(so->so_page_size != 0); } else { if ( vc ) { so->so_vlv = op->o_ctrlflag[vlv_cid]; assert(so->so_vlv_target == 0); assert(so->so_vlv_rc == 0); assert(so->so_vlv != SLAP_CONTROL_NONE); } else { assert(so->so_vlv == SLAP_CONTROL_NONE); } } so->so_session = sess_id; so->so_vlv = op->o_ctrlflag[vlv_cid]; so->so_vcontext = (size_t)so; assert(so->so_nentries == 0); op->o_callback = cb; assert(sess_id >= 0); so->so_running = 1; sort_conns[op->o_conn->c_conn_idx][sess_id] = so; si->svi_num++; ldap_pvt_thread_mutex_unlock( &sort_conns_mutex ); need_unlock = 0; } assert(need_unlock == 0); } else { assert(need_unlock == 0); if ( so && !so->so_nentries ) { free_sort_op( op->o_conn, so ); } else { rs->sr_text = "Other sort requests already in progress"; rs->sr_err = LDAP_BUSY; } leave: assert(need_unlock == 0); rc = rs->sr_err; send_ldap_result( op, rs ); } assert(need_unlock == 0); return rc; }
static void send_list( Operation *op, SlapReply *rs, sort_op *so) { TAvlnode *cur_node, *tmp_node; vlv_ctrl *vc = op->o_controls[vlv_cid]; int i, j, dir, rc; BackendDB *be; Entry *e; LDAPControl *ctrls[2]; rs->sr_attrs = op->ors_attrs; /* FIXME: it may be better to just flatten the tree into * an array before doing all of this... */ /* Are we just counting an offset? */ if ( BER_BVISNULL( &vc->vc_value )) { if ( vc->vc_offset == vc->vc_count ) { /* wants the last entry in the list */ cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); so->so_vlv_target = so->so_nentries; } else if ( vc->vc_offset == 1 ) { /* wants the first entry in the list */ cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); so->so_vlv_target = 1; } else { int target; /* Just iterate to the right spot */ if ( vc->vc_count && vc->vc_count != so->so_nentries ) { if ( vc->vc_offset > vc->vc_count ) goto range_err; target = so->so_nentries * vc->vc_offset / vc->vc_count; } else { if ( vc->vc_offset > so->so_nentries ) { range_err: so->so_vlv_rc = LDAP_VLV_RANGE_ERROR; pack_vlv_response_control( op, rs, so, ctrls ); ctrls[1] = NULL; slap_add_ctrls( op, rs, ctrls ); rs->sr_err = LDAP_VLV_ERROR; return; } target = vc->vc_offset; } so->so_vlv_target = target; /* Start at left and go right, or start at right and go left? */ if ( target < so->so_nentries / 2 ) { cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); dir = TAVL_DIR_RIGHT; } else { cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); dir = TAVL_DIR_LEFT; target = so->so_nentries - target + 1; } for ( i=1; i<target; i++ ) cur_node = tavl_next( cur_node, dir ); } } else { /* we're looking for a specific value */ sort_ctrl *sc = so->so_ctrl; MatchingRule *mr = sc->sc_keys[0].sk_ordering; sort_node *sn; struct berval bv; if ( mr->smr_normalize ) { rc = mr->smr_normalize( SLAP_MR_VALUE_OF_SYNTAX, mr->smr_syntax, mr, &vc->vc_value, &bv, op->o_tmpmemctx ); if ( rc ) { so->so_vlv_rc = LDAP_INAPPROPRIATE_MATCHING; pack_vlv_response_control( op, rs, so, ctrls ); ctrls[1] = NULL; slap_add_ctrls( op, rs, ctrls ); rs->sr_err = LDAP_VLV_ERROR; return; } } else { bv = vc->vc_value; } sn = op->o_tmpalloc( sizeof(sort_node) + sc->sc_nkeys * sizeof(struct berval), op->o_tmpmemctx ); sn->sn_vals = (struct berval *)(sn+1); sn->sn_conn = op->o_conn->c_conn_idx; sn->sn_session = find_session_by_so( so->so_info->svi_max_percon, op->o_conn->c_conn_idx, so ); sn->sn_vals[0] = bv; for (i=1; i<sc->sc_nkeys; i++) { BER_BVZERO( &sn->sn_vals[i] ); } cur_node = tavl_find3( so->so_tree, sn, node_cmp, &j ); /* didn't find >= match */ if ( j > 0 ) { if ( cur_node ) cur_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); } op->o_tmpfree( sn, op->o_tmpmemctx ); if ( !cur_node ) { so->so_vlv_target = so->so_nentries + 1; } else { sort_node *sn = so->so_tree->avl_data; /* start from the left or the right side? */ mr->smr_match( &i, 0, mr->smr_syntax, mr, &bv, &sn->sn_vals[0] ); if ( i > 0 ) { tmp_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); dir = TAVL_DIR_LEFT; } else { tmp_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); dir = TAVL_DIR_RIGHT; } for (i=0; tmp_node != cur_node; tmp_node = tavl_next( tmp_node, dir ), i++); so->so_vlv_target = (dir == TAVL_DIR_RIGHT) ? i+1 : so->so_nentries - i; } if ( bv.bv_val != vc->vc_value.bv_val ) op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); } if ( !cur_node ) { i = 1; cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); } else { i = 0; } for ( ; i<vc->vc_before; i++ ) { tmp_node = tavl_next( cur_node, TAVL_DIR_LEFT ); if ( !tmp_node ) break; cur_node = tmp_node; } j = i + vc->vc_after + 1; be = op->o_bd; for ( i=0; i<j; i++ ) { sort_node *sn = cur_node->avl_data; if ( slapd_shutdown ) break; op->o_bd = select_backend( &sn->sn_dn, 0 ); e = NULL; rc = be_entry_get_rw( op, &sn->sn_dn, NULL, NULL, 0, &e ); if ( e && rc == LDAP_SUCCESS ) { rs->sr_entry = e; rs->sr_flags = REP_ENTRY_MUSTRELEASE; rs->sr_err = send_search_entry( op, rs ); if ( rs->sr_err == LDAP_UNAVAILABLE ) break; } cur_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); if ( !cur_node ) break; } so->so_vlv_rc = LDAP_SUCCESS; op->o_bd = be; }