/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2000-2011 The OpenLDAP Foundation.
+ * Copyright 2000-2014 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Operation *op,
SlapReply *rs,
Entry *e,
- MDB_txn *txn,
+ IdScopes *isc,
+ MDB_cursor *mci,
ID *ids,
- ID *scopes );
+ ID *stack );
static int parse_paged_cookie( Operation *op, SlapReply *rs );
break;
}
- rs->sr_err = mdb_dn2entry( op, txn, &ndn, &e, 0 );
+ rs->sr_err = mdb_dn2entry( op, txn, NULL, &ndn, &e, NULL, 0 );
if (rs->sr_err) {
rs->sr_err = LDAP_ALIAS_PROBLEM;
rs->sr_text = "aliasedObject not found";
/* Free the previous entry, continue to work with the
* one we just retrieved.
*/
- mdb_entry_return( *matched );
+ mdb_entry_return( op, *matched );
/* We found a regular entry. Return this to the caller.
*/
static int search_aliases(
Operation *op,
SlapReply *rs,
- Entry *e,
- MDB_txn *txn,
- ID *scopes,
+ ID e_id,
+ IdScopes *isc,
+ MDB_cursor *mci,
ID *stack )
{
ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp;
/* Find all aliases in database */
MDB_IDL_ZERO( aliases );
- rs->sr_err = mdb_filter_candidates( op, txn, &af, aliases,
+ rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases,
curscop, visited );
- if (rs->sr_err != LDAP_SUCCESS) {
+ if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) {
return rs->sr_err;
}
oldsubs[0] = 1;
- oldsubs[1] = e->e_id;
+ oldsubs[1] = e_id;
MDB_IDL_ZERO( visited );
MDB_IDL_ZERO( newsubs );
/* Set curscop to only the aliases in the current scope. Start with
* all the aliases, then get the intersection with the scope.
*/
- rs->sr_err = mdb_idscope( op, txn, e->e_id, aliases, curscop );
-
- if (first) {
- first = 0;
- } else {
- mdb_entry_return( e );
- }
+ rs->sr_err = mdb_idscope( op, isc->mt, e_id, aliases, curscop );
/* Dereference all of the aliases in the current scope. */
cursora = 0;
for (ida = mdb_idl_first(curscop, &cursora); ida != NOID;
ida = mdb_idl_next(curscop, &cursora))
{
- rs->sr_err = mdb_id2entry(op, txn, ida, &a);
+ rs->sr_err = mdb_id2entry(op, mci, ida, &a);
if (rs->sr_err != LDAP_SUCCESS) {
continue;
}
* turned into a range that spans IDs indiscriminately
*/
if (!is_entry_alias(a)) {
- mdb_entry_return (a);
+ mdb_entry_return(op, a);
continue;
}
/* Actually dereference the alias */
MDB_IDL_ZERO(tmp);
- a = deref_base( op, rs, a, &matched, txn,
+ a = deref_base( op, rs, a, &matched, isc->mt,
tmp, visited );
if (a) {
/* If the target was not already in our current scopes,
* make note of it in the newsubs list.
*/
- if (mdb_idl_insert(scopes, a->e_id) == 0) {
+ ID2 mid;
+ mid.mid = a->e_id;
+ mid.mval.mv_data = NULL;
+ if (op->ors_scope == LDAP_SCOPE_SUBTREE) {
+ isc->id = a->e_id;
+ /* if ID is a child of any of our current scopes,
+ * ignore it, it's already included.
+ */
+ if (mdb_idscopechk(op, isc))
+ goto skip;
+ }
+ if (mdb_id2l_insert(isc->scopes, &mid) == 0) {
mdb_idl_insert(newsubs, a->e_id);
}
- mdb_entry_return( a );
+skip: mdb_entry_return( op, a );
} else if (matched) {
/* Alias could not be dereferenced, or it deref'd to
* an ID we've already seen. Ignore it.
*/
- mdb_entry_return( matched );
+ mdb_entry_return( op, matched );
rs->sr_text = NULL;
+ rs->sr_err = 0;
}
}
/* If this is a OneLevel search, we're done; oldsubs only had one
* be found, ignore it and move on. This should never happen;
* we should never see the ID of an entry that doesn't exist.
*/
- rs->sr_err = mdb_id2entry(op, txn, ido, &e);
- if ( rs->sr_err != LDAP_SUCCESS ) {
- goto nextido;
+ {
+ MDB_val edata;
+ rs->sr_err = mdb_id2edata(op, mci, ido, &edata);
+ if ( rs->sr_err != MDB_SUCCESS ) {
+ goto nextido;
+ }
+ e_id = ido;
}
}
return rs->sr_err;
* a range and simple iteration hits missing entryIDs
*/
static int
-mdb_get_nextid(struct mdb_info *mdb, MDB_txn *txn, ID *cursor)
+mdb_get_nextid(MDB_cursor *mci, ID *cursor)
{
- MDB_cursor *curs;
MDB_val key;
ID id;
int rc;
id = *cursor + 1;
- rc = mdb_cursor_open( txn, mdb->mi_id2entry, &curs );
- if ( rc )
- return rc;
key.mv_data = &id;
key.mv_size = sizeof(ID);
- rc = mdb_cursor_get( curs, &key, NULL, MDB_SET_RANGE );
- mdb_cursor_close( curs );
+ rc = mdb_cursor_get( mci, &key, NULL, MDB_SET_RANGE );
if ( rc )
return rc;
memcpy( cursor, key.mv_data, sizeof(ID));
return 0;
}
+static void scope_chunk_free( void *key, void *data )
+{
+ ID2 *p1, *p2;
+ for (p1 = data; p1; p1 = p2) {
+ p2 = p1[0].mval.mv_data;
+ ber_memfree_x(p1, NULL);
+ }
+}
+
+static ID2 *scope_chunk_get( Operation *op )
+{
+ struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+ ID2 *ret = NULL;
+
+ ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)scope_chunk_get,
+ (void *)&ret, NULL );
+ if ( !ret ) {
+ ret = ch_malloc( MDB_IDL_UM_SIZE * sizeof( ID2 ));
+ } else {
+ void *r2 = ret[0].mval.mv_data;
+ ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)scope_chunk_get,
+ r2, scope_chunk_free, NULL, NULL );
+ }
+ return ret;
+}
+
+static void scope_chunk_ret( Operation *op, ID2 *scopes )
+{
+ struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+ void *ret = NULL;
+
+ ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)scope_chunk_get,
+ &ret, NULL );
+ scopes[0].mval.mv_data = ret;
+ ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)scope_chunk_get,
+ (void *)scopes, scope_chunk_free, NULL, NULL );
+}
+
+static void *search_stack( Operation *op );
+
+typedef struct ww_ctx {
+ MDB_txn *txn;
+ MDB_cursor *mcd; /* if set, save cursor context */
+ ID key;
+ MDB_val data;
+ int flag;
+} ww_ctx;
+
+/* ITS#7904 if we get blocked while writing results to client,
+ * release the current reader txn and reacquire it after we
+ * unblock.
+ * Slight problem - if we're doing a scope-based walk (mdb_dn2id_walk)
+ * to return results, we need to remember the state of the mcd cursor.
+ * If the node that cursor was pointing to gets deleted while we're
+ * blocked, we may be unable to restore the cursor position. In that
+ * case return an LDAP_BUSY error - let the client know this search
+ * couldn't succeed, but might succeed on a retry.
+ */
+static void
+mdb_writewait( Operation *op, slap_callback *sc )
+{
+ ww_ctx *ww = sc->sc_private;
+ if ( !ww->flag ) {
+ if ( ww->mcd ) {
+ MDB_val key, data;
+ mdb_cursor_get( ww->mcd, &key, &data, MDB_GET_CURRENT );
+ memcpy( &ww->key, key.mv_data, sizeof(ID) );
+ ww->data.mv_size = data.mv_size;
+ ww->data.mv_data = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
+ memcpy(ww->data.mv_data, data.mv_data, data.mv_size);
+ }
+ mdb_txn_reset( ww->txn );
+ ww->flag = 1;
+ }
+}
+
+static int
+mdb_waitfixup( Operation *op, ww_ctx *ww, MDB_cursor *mci, MDB_cursor *mcd )
+{
+ int rc = 0;
+ ww->flag = 0;
+ mdb_txn_renew( ww->txn );
+ mdb_cursor_renew( ww->txn, mci );
+ mdb_cursor_renew( ww->txn, mcd );
+ if ( ww->mcd ) {
+ MDB_val key, data;
+ key.mv_size = sizeof(ID);
+ key.mv_data = &ww->key;
+ data = ww->data;
+ rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH );
+ if ( rc == MDB_NOTFOUND ) {
+ data = ww->data;
+ rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH_RANGE );
+ /* the loop will skip this node using NEXT_DUP but we want it
+ * sent, so go back one space first
+ */
+ if ( rc == MDB_SUCCESS )
+ mdb_cursor_get( mcd, &key, &data, MDB_PREV_DUP );
+ else
+ rc = LDAP_BUSY;
+ } else if ( rc ) {
+ rc = LDAP_OTHER;
+ }
+ op->o_tmpfree( ww->data.mv_data, op->o_tmpmemctx );
+ ww->data.mv_data = NULL;
+ }
+ return rc;
+}
+
int
mdb_search( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
- ID id, cursor;
+ ID id, cursor, nsubs, ncand, cscope;
ID lastid = NOID;
ID candidates[MDB_IDL_UM_SIZE];
- ID scopes[MDB_IDL_DB_SIZE];
+ ID iscopes[MDB_IDL_DB_SIZE];
+ ID2 *scopes;
+ void *stack;
Entry *e = NULL, *base = NULL;
Entry *matched = NULL;
AttributeName *attrs;
int manageDSAit;
int tentries = 0;
IdScopes isc;
+ MDB_cursor *mci, *mcd;
+ ww_ctx wwctx;
+ slap_callback cb = { 0 };
- mdb_op_info opinfo = {0}, *moi = &opinfo;
+ mdb_op_info opinfo = {{{0}}}, *moi = &opinfo;
MDB_txn *ltid = NULL;
Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_search) "\n", 0, 0, 0);
}
ltid = moi->moi_txn;
+
+ rs->sr_err = mdb_cursor_open( ltid, mdb->mi_id2entry, &mci );
+ if ( rs->sr_err ) {
+ send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
+ return rs->sr_err;
+ }
+
+ rs->sr_err = mdb_cursor_open( ltid, mdb->mi_dn2id, &mcd );
+ if ( rs->sr_err ) {
+ mdb_cursor_close( mci );
+ send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
+ return rs->sr_err;
+ }
+
+ scopes = scope_chunk_get( op );
+ stack = search_stack( op );
isc.mt = ltid;
- isc.mc = NULL;
+ isc.mc = mcd;
+ isc.scopes = scopes;
+ isc.oscope = op->ors_scope;
+ isc.sctmp = stack;
if ( op->ors_deref & LDAP_DEREF_FINDING ) {
MDB_IDL_ZERO(candidates);
}
dn2entry_retry:
/* get entry with reader lock */
- rs->sr_err = mdb_dn2entry( op, ltid, &op->o_req_ndn, &e, 1 );
+ rs->sr_err = mdb_dn2entry( op, ltid, mcd, &op->o_req_ndn, &e, &nsubs, 1 );
switch(rs->sr_err) {
case MDB_NOTFOUND:
if ( e ) {
build_new_dn( &op->o_req_ndn, &e->e_nname, &stub,
op->o_tmpmemctx );
- mdb_entry_return (e);
+ mdb_entry_return(op, e);
matched = NULL;
goto dn2entry_retry;
}
rs->sr_matched = matched_dn.bv_val;
}
- mdb_entry_return (matched);
+ mdb_entry_return(op, matched);
matched = NULL;
if ( erefs ) {
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
}
- mdb_entry_return(e);
+ mdb_entry_return( op,e);
send_ldap_result( op, rs );
goto done;
}
rs->sr_err = LDAP_REFERRAL;
- mdb_entry_return( e );
+ mdb_entry_return( op, e );
e = NULL;
if ( erefs ) {
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
{
rs->sr_err = LDAP_ASSERTION_FAILED;
- mdb_entry_return(e);
+ mdb_entry_return( op,e);
send_ldap_result( op, rs );
goto done;
}
/* select candidates */
if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
rs->sr_err = base_candidate( op->o_bd, base, candidates );
-
+ scopes[0].mid = 0;
+ ncand = 1;
} else {
+ if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
+ size_t nkids;
+ MDB_val key, data;
+ key.mv_data = &base->e_id;
+ key.mv_size = sizeof( ID );
+ mdb_cursor_get( mcd, &key, &data, MDB_SET );
+ mdb_cursor_count( mcd, &nkids );
+ nsubs = nkids - 1;
+ } else if ( !base->e_id ) {
+ /* we don't maintain nsubs for entryID 0.
+ * just grab entry count from id2entry stat
+ */
+ MDB_stat ms;
+ mdb_stat( ltid, mdb->mi_id2entry, &ms );
+ nsubs = ms.ms_entries;
+ }
MDB_IDL_ZERO( candidates );
- MDB_IDL_ZERO( scopes );
- mdb_idl_insert( scopes, base->e_id );
+ scopes[0].mid = 1;
+ scopes[1].mid = base->e_id;
+ scopes[1].mval.mv_data = NULL;
rs->sr_err = search_candidates( op, rs, base,
- ltid, candidates, scopes );
+ &isc, mci, candidates, stack );
+ ncand = MDB_IDL_N( candidates );
+ if ( !base->e_id || ncand == NOID ) {
+ /* grab entry count from id2entry stat
+ */
+ MDB_stat ms;
+ mdb_stat( ltid, mdb->mi_id2entry, &ms );
+ if ( !base->e_id )
+ nsubs = ms.ms_entries;
+ if ( ncand == NOID )
+ ncand = ms.ms_entries;
+ }
}
/* start cursor at beginning of candidates.
/* if not root and candidates exceed to-be-checked entries, abort */
if ( op->ors_limit /* isroot == FALSE */ &&
op->ors_limit->lms_s_unchecked != -1 &&
- MDB_IDL_N(candidates) > (unsigned) op->ors_limit->lms_s_unchecked )
+ ncand > (unsigned) op->ors_limit->lms_s_unchecked )
{
rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
send_ldap_result( op, rs );
if ( op->ors_limit == NULL /* isroot == TRUE */ ||
!op->ors_limit->lms_s_pr_hide )
{
- tentries = MDB_IDL_N(candidates);
+ tentries = ncand;
+ }
+
+ wwctx.flag = 0;
+ /* If we're running in our own read txn */
+ if ( moi == &opinfo ) {
+ cb.sc_writewait = mdb_writewait;
+ cb.sc_private = &wwctx;
+ wwctx.txn = ltid;
+ wwctx.mcd = NULL;
+ cb.sc_next = op->o_callback;
+ op->o_callback = &cb;
}
if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
}
if ( id == (ID)ps->ps_cookie )
id = mdb_idl_next( candidates, &cursor );
+ nsubs = ncand; /* always bypass scope'd search */
goto loop_begin;
}
+ if ( nsubs < ncand ) {
+ int rc;
+ /* Do scope-based search */
+
+ /* if any alias scopes were set, save them */
+ if (scopes[0].mid > 1) {
+ cursor = 1;
+ for (cscope = 1; cscope <= scopes[0].mid; cscope++) {
+ /* Ignore the original base */
+ if (scopes[cscope].mid == base->e_id)
+ continue;
+ iscopes[cursor++] = scopes[cscope].mid;
+ }
+ iscopes[0] = scopes[0].mid - 1;
+ } else {
+ iscopes[0] = 0;
+ }
- isc.scopes = scopes;
+ wwctx.mcd = mcd;
+ isc.id = base->e_id;
+ isc.numrdns = 0;
+ rc = mdb_dn2id_walk( op, &isc );
+ if ( rc )
+ id = NOID;
+ else
+ id = isc.id;
+ cscope = 0;
+ } else {
+ id = mdb_idl_first( candidates, &cursor );
+ }
- for ( id = mdb_idl_first( candidates, &cursor );
- id != NOID ; id = mdb_idl_next( candidates, &cursor ) )
+ while (id != NOID)
{
int scopeok;
+ MDB_val edata;
loop_begin:
goto done;
}
+
+ if ( nsubs < ncand ) {
+ unsigned i;
+ /* Is this entry in the candidate list? */
+ scopeok = 0;
+ if (MDB_IDL_IS_RANGE( candidates )) {
+ if ( id >= MDB_IDL_RANGE_FIRST( candidates ) &&
+ id <= MDB_IDL_RANGE_LAST( candidates ))
+ scopeok = 1;
+ } else {
+ i = mdb_idl_search( candidates, id );
+ if ( candidates[i] == id )
+ scopeok = 1;
+ }
+ if ( scopeok )
+ goto scopeok;
+ goto loop_continue;
+ }
+
+ /* Does this candidate actually satisfy the search scope?
+ */
+ scopeok = 0;
+ isc.numrdns = 0;
+ switch( op->ors_scope ) {
+ case LDAP_SCOPE_BASE:
+ /* This is always true, yes? */
+ if ( id == base->e_id ) scopeok = 1;
+ break;
+
+#ifdef LDAP_SCOPE_CHILDREN
+ case LDAP_SCOPE_CHILDREN:
+ if ( id == base->e_id ) break;
+ /* Fall-thru */
+#endif
+ case LDAP_SCOPE_SUBTREE:
+ if ( id == base->e_id ) {
+ scopeok = 1;
+ break;
+ }
+ /* Fall-thru */
+ case LDAP_SCOPE_ONELEVEL:
+ isc.id = id;
+ isc.nscope = 0;
+ rs->sr_err = mdb_idscopes( op, &isc );
+ if ( rs->sr_err == MDB_SUCCESS ) {
+ if ( isc.nscope )
+ scopeok = 1;
+ } else {
+ if ( rs->sr_err == MDB_NOTFOUND )
+ goto notfound;
+ }
+ break;
+ }
+
+ /* Not in scope, ignore it */
+ if ( !scopeok )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(mdb_search)
+ ": %ld scope not okay\n",
+ (long) id, 0, 0 );
+ goto loop_continue;
+ }
+
+scopeok:
if ( id == base->e_id ) {
e = base;
} else {
/* get the entry */
- rs->sr_err = mdb_id2entry( op, ltid, id, &e );
-
- if (rs->sr_err == LDAP_BUSY) {
- rs->sr_text = "ldap server busy";
- send_ldap_result( op, rs );
- goto done;
-
- } else if ( rs->sr_err == LDAP_OTHER ) {
- rs->sr_text = "internal error";
- send_ldap_result( op, rs );
- goto done;
- }
+ rs->sr_err = mdb_id2edata( op, mci, id, &edata );
+ if ( rs->sr_err == MDB_NOTFOUND ) {
+notfound:
+ if( nsubs < ncand )
+ goto loop_continue;
- if ( e == NULL ) {
if( !MDB_IDL_IS_RANGE(candidates) ) {
/* only complain for non-range IDLs */
Debug( LDAP_DEBUG_TRACE,
(long) id, 0, 0 );
} else {
/* get the next ID from the DB */
- rs->sr_err = mdb_get_nextid( mdb, ltid, &cursor );
+ rs->sr_err = mdb_get_nextid( mci, &cursor );
if ( rs->sr_err == MDB_NOTFOUND ) {
break;
}
}
goto loop_continue;
+ } else if ( rs->sr_err ) {
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error in mdb_id2edata";
+ send_ldap_result( op, rs );
+ goto done;
}
+
+ rs->sr_err = mdb_entry_decode( op, ltid, &edata, &e );
+ if ( rs->sr_err ) {
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error in mdb_entry_decode";
+ send_ldap_result( op, rs );
+ goto done;
+ }
+ e->e_id = id;
+ e->e_name.bv_val = NULL;
+ e->e_nname.bv_val = NULL;
}
if ( is_entry_subentry( e ) ) {
goto loop_continue;
}
- /* Does this candidate actually satisfy the search scope?
- */
- scopeok = 0;
- isc.numrdns = 0;
- switch( op->ors_scope ) {
- case LDAP_SCOPE_BASE:
- /* This is always true, yes? */
- if ( id == base->e_id ) scopeok = 1;
- break;
-
-#ifdef LDAP_SCOPE_CHILDREN
- case LDAP_SCOPE_CHILDREN:
- if ( id == base->e_id ) break;
- /* Fall-thru */
-#endif
- case LDAP_SCOPE_SUBTREE:
- if ( id == base->e_id ) {
- scopeok = 1;
- break;
- }
- /* Fall-thru */
- case LDAP_SCOPE_ONELEVEL:
- isc.id = id;
- if ( mdb_idscopes( op, &isc ) == MDB_SUCCESS ) scopeok = 1;
- break;
- }
-
/* aliases were already dereferenced in candidate list */
if ( op->ors_deref & LDAP_DEREF_SEARCHING ) {
/* but if the search base is an alias, and we didn't
* deref it when finding, return it.
*/
if ( is_entry_alias(e) &&
- ((op->ors_deref & LDAP_DEREF_FINDING) ||
- !bvmatch(&e->e_nname, &op->o_req_ndn)))
+ ((op->ors_deref & LDAP_DEREF_FINDING) || e != base ))
{
goto loop_continue;
}
}
- /* Not in scope, ignore it */
- if ( !scopeok )
- {
- Debug( LDAP_DEBUG_TRACE,
- LDAP_XSTRING(mdb_search)
- ": %ld scope not okay\n",
- (long) id, 0, 0 );
- goto loop_continue;
- }
-
if ( !manageDSAit && is_entry_glue( e )) {
goto loop_continue;
}
struct berval pdn, pndn;
char *d, *n;
int i;
+
/* child of base, just append RDNs to base->e_name */
- if ( isc.nscope == 1 ) {
+ if ( nsubs < ncand || isc.scopes[isc.nscope].mid == base->e_id ) {
pdn = base->e_name;
pndn = base->e_nname;
} else {
- mdb_id2name( op, ltid, &isc.mc, scopes[isc.nscope], &pdn, &pndn );
+ mdb_id2name( op, ltid, &isc.mc, scopes[isc.nscope].mid, &pdn, &pndn );
}
e->e_name.bv_len = pdn.bv_len;
e->e_nname.bv_len = pndn.bv_len;
e->e_nname.bv_val = op->o_tmpalloc(e->e_nname.bv_len + 1, op->o_tmpmemctx);
d = e->e_name.bv_val;
n = e->e_nname.bv_val;
- for (i=0; i<isc.numrdns; i++) {
- memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len);
- d += isc.rdns[i].bv_len;
- *d++ = ',';
- memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len);
- n += isc.nrdns[i].bv_len;
- *n++ = ',';
+ if (nsubs < ncand) {
+ /* RDNs are in top-down order */
+ for (i=isc.numrdns-1; i>=0; i--) {
+ memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len);
+ d += isc.rdns[i].bv_len;
+ *d++ = ',';
+ memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len);
+ n += isc.nrdns[i].bv_len;
+ *n++ = ',';
+ }
+ } else {
+ /* RDNs are in bottom-up order */
+ for (i=0; i<isc.numrdns; i++) {
+ memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len);
+ d += isc.rdns[i].bv_len;
+ *d++ = ',';
+ memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len);
+ n += isc.nrdns[i].bv_len;
+ *n++ = ',';
+ }
+ }
+
+ if (pdn.bv_len) {
+ memcpy(d, pdn.bv_val, pdn.bv_len+1);
+ memcpy(n, pndn.bv_val, pndn.bv_len+1);
+ } else {
+ *--d = '\0';
+ *--n = '\0';
+ e->e_name.bv_len--;
+ e->e_nname.bv_len--;
}
- memcpy(d, pdn.bv_val, pdn.bv_len+1);
- memcpy(n, pndn.bv_val, pndn.bv_len+1);
- if (isc.nscope != 1) {
+ if (pndn.bv_val != base->e_nname.bv_val) {
op->o_tmpfree(pndn.bv_val, op->o_tmpmemctx);
op->o_tmpfree(pdn.bv_val, op->o_tmpmemctx);
}
send_search_reference( op, rs );
- mdb_entry_return( e );
+ if (e != base)
+ mdb_entry_return( op, e );
rs->sr_entry = NULL;
e = NULL;
ber_bvarray_free( erefs );
rs->sr_ref = NULL;
+ if ( wwctx.flag ) {
+ rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd );
+ if ( rs->sr_err ) {
+ send_ldap_result( op, rs );
+ goto done;
+ }
+ }
+
goto loop_continue;
}
/* check size limit */
if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) {
- mdb_entry_return( e );
+ mdb_entry_return( op, e );
e = NULL;
send_paged_response( op, rs, &lastid, tentries );
goto done;
rs->sr_attrs = NULL;
rs->sr_entry = NULL;
if (e != base)
- mdb_entry_return( e );
+ mdb_entry_return( op, e );
e = NULL;
switch ( rs->sr_err ) {
break;
default: /* entry not sent */
break;
+ case LDAP_BUSY:
+ send_ldap_result( op, rs );
+ goto done;
case LDAP_UNAVAILABLE:
case LDAP_SIZELIMIT_EXCEEDED:
if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
}
goto done;
}
+ if ( wwctx.flag ) {
+ rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd );
+ if ( rs->sr_err ) {
+ send_ldap_result( op, rs );
+ goto done;
+ }
+ }
}
} else {
loop_continue:
if( e != NULL ) {
if ( e != base )
- mdb_entry_return( e );
+ mdb_entry_return( op, e );
RS_ASSERT( rs->sr_entry == NULL );
e = NULL;
rs->sr_entry = NULL;
}
+
+ if ( nsubs < ncand ) {
+ int rc = mdb_dn2id_walk( op, &isc );
+ if (rc) {
+ id = NOID;
+ /* We got to the end of a subtree. If there are any
+ * alias scopes left, search them too.
+ */
+ while (iscopes[0] && cscope < iscopes[0]) {
+ cscope++;
+ isc.id = iscopes[cscope];
+ if ( base )
+ mdb_entry_return( op, base );
+ rs->sr_err = mdb_id2entry(op, mci, isc.id, &base);
+ if ( !rs->sr_err ) {
+ mdb_id2name( op, ltid, &isc.mc, isc.id, &base->e_name, &base->e_nname );
+ isc.numrdns = 0;
+ if (isc.oscope == LDAP_SCOPE_ONELEVEL)
+ isc.oscope = LDAP_SCOPE_BASE;
+ rc = mdb_dn2id_walk( op, &isc );
+ if ( !rc ) {
+ id = isc.id;
+ break;
+ }
+ }
+ }
+ } else
+ id = isc.id;
+ } else {
+ id = mdb_idl_next( candidates, &cursor );
+ }
}
nochange:
rs->sr_err = LDAP_SUCCESS;
done:
+ if ( cb.sc_private ) {
+ /* remove our writewait callback */
+ slap_callback **scp = &op->o_callback;
+ while ( *scp ) {
+ if ( *scp == &cb ) {
+ *scp = cb.sc_next;
+ cb.sc_private = NULL;
+ break;
+ }
+ }
+ }
+ mdb_cursor_close( mcd );
+ mdb_cursor_close( mci );
if ( moi == &opinfo ) {
mdb_txn_reset( moi->moi_txn );
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
+ } else {
+ moi->moi_ref--;
}
- if( isc.mc )
- mdb_cursor_close( isc.mc );
if( rs->sr_v2ref ) {
ber_bvarray_free( rs->sr_v2ref );
rs->sr_v2ref = NULL;
}
if (base)
- mdb_entry_return(base);
+ mdb_entry_return( op, base );
+ scope_chunk_ret( op, scopes );
return rs->sr_err;
}
Operation *op,
SlapReply *rs,
Entry *e,
- MDB_txn *txn,
+ IdScopes *isc,
+ MDB_cursor *mci,
ID *ids,
- ID *scopes )
+ ID *stack )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
int rc, depth = 1;
Filter *f, rf, xf, nf, sf;
- ID *stack;
AttributeAssertion aa_ref = ATTRIBUTEASSERTION_INIT;
AttributeAssertion aa_subentry = ATTRIBUTEASSERTION_INIT;
/* Allocate IDL stack, plus 1 more for former tmp */
if ( depth+1 > mdb->mi_search_stack_depth ) {
stack = ch_malloc( (depth + 1) * MDB_IDL_UM_SIZE * sizeof( ID ) );
- } else {
- stack = search_stack( op );
}
if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
- rc = search_aliases( op, rs, e, txn, scopes, stack );
+ rc = search_aliases( op, rs, e->e_id, isc, mci, stack );
} else {
rc = LDAP_SUCCESS;
}
if ( rc == LDAP_SUCCESS ) {
- rc = mdb_filter_candidates( op, txn, f, ids,
+ rc = mdb_filter_candidates( op, isc->mt, f, ids,
stack, stack+MDB_IDL_UM_SIZE );
}