/* See if base is a child of any of the scopes */ int mdb_idscopes( Operation *op, IdScopes *isc ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; MDB_dbi dbi = mdb->mi_dn2id; MDB_val key, data; ID id, prev; ID2 id2; char *ptr; int rc = 0; unsigned int x; unsigned int nrlen, rlen; diskNode *d; key.mv_size = sizeof(ID); if ( !isc->mc ) { rc = mdb_cursor_open( isc->mt, dbi, &isc->mc ); if ( rc ) return rc; } id = isc->id; /* Catch entries from deref'd aliases */ x = mdb_id2l_search( isc->scopes, id ); if ( x <= isc->scopes[0].mid && isc->scopes[x].mid == id ) { isc->nscope = x; return MDB_SUCCESS; } isc->sctmp[0].mid = 0; while (id) { if ( !rc ) { key.mv_data = &id; rc = mdb_cursor_get( isc->mc, &key, &data, MDB_SET ); if ( rc ) return rc; /* save RDN info */ } d = data.mv_data; nrlen = (d->nrdnlen[0] << 8) | d->nrdnlen[1]; rlen = data.mv_size - sizeof(diskNode) - nrlen; isc->nrdns[isc->numrdns].bv_len = nrlen; isc->nrdns[isc->numrdns].bv_val = d->nrdn; isc->rdns[isc->numrdns].bv_len = rlen; isc->rdns[isc->numrdns].bv_val = d->nrdn+nrlen+1; isc->numrdns++; if (!rc && id != isc->id) { /* remember our chain of parents */ id2.mid = id; id2.mval = data; rc = mdb_id2l_insert( isc->sctmp, &id2 ); assert(rc == 0); } ptr = data.mv_data; ptr += data.mv_size - sizeof(ID); prev = id; memcpy( &id, ptr, sizeof(ID) ); /* If we didn't advance, some parent is missing */ if ( id == prev ) return MDB_NOTFOUND; x = mdb_id2l_search( isc->scopes, id ); if ( x <= isc->scopes[0].mid && isc->scopes[x].mid == id ) { if ( !isc->scopes[x].mval.mv_data ) { /* This node is in scope, add parent chain to scope */ int i; for ( i = 1; i <= isc->sctmp[0].mid; i++ ) { rc = mdb_id2l_insert( isc->scopes, &isc->sctmp[i] ); if ( rc ) break; } /* check id again since inserts may have changed its position */ if ( isc->scopes[x].mid != id ) x = mdb_id2l_search( isc->scopes, id ); isc->nscope = x; return MDB_SUCCESS; } data = isc->scopes[x].mval; rc = 1; } if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; } return MDB_SUCCESS; }
/* Look for and dereference all aliases within the search scope. * Requires "stack" to be able to hold 6 levels of DB_SIZE IDLs. * Of course we're hardcoded to require a minimum of 8 UM_SIZE * IDLs so this is never a problem. */ static int search_aliases( Operation *op, SlapReply *rs, ID e_id, IdScopes *isc, MDB_cursor *mci, ID *stack ) { ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp; ID cursora, ida, cursoro, ido; Entry *matched, *a; struct berval bv_alias = BER_BVC( "alias" ); AttributeAssertion aa_alias = ATTRIBUTEASSERTION_INIT; Filter af; int first = 1; aliases = stack; /* IDL of all aliases in the database */ curscop = aliases + MDB_IDL_DB_SIZE; /* Aliases in the current scope */ visited = curscop + MDB_IDL_DB_SIZE; /* IDs we've seen in this search */ newsubs = visited + MDB_IDL_DB_SIZE; /* New subtrees we've added */ oldsubs = newsubs + MDB_IDL_DB_SIZE; /* Subtrees added previously */ tmp = oldsubs + MDB_IDL_DB_SIZE; /* Scratch space for deref_base() */ af.f_choice = LDAP_FILTER_EQUALITY; af.f_ava = &aa_alias; af.f_av_desc = slap_schema.si_ad_objectClass; af.f_av_value = bv_alias; af.f_next = NULL; /* Find all aliases in database */ MDB_IDL_ZERO( aliases ); rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases, curscop, visited ); if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) { return rs->sr_err; } oldsubs[0] = 1; oldsubs[1] = e_id; MDB_IDL_ZERO( visited ); MDB_IDL_ZERO( newsubs ); cursoro = 0; ido = mdb_idl_first( oldsubs, &cursoro ); for (;;) { /* 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, 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, mci, ida, &a); if (rs->sr_err != LDAP_SUCCESS) { continue; } /* This should only happen if the curscop IDL has maxed out and * turned into a range that spans IDs indiscriminately */ if (!is_entry_alias(a)) { mdb_entry_return(op, a); continue; } /* Actually dereference the alias */ MDB_IDL_ZERO(tmp); 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. */ 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); } 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( op, matched ); rs->sr_text = NULL; rs->sr_err = 0; } } /* If this is a OneLevel search, we're done; oldsubs only had one * ID in it. For a Subtree search, oldsubs may be a list of scope IDs. */ if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; nextido: ido = mdb_idl_next( oldsubs, &cursoro ); /* If we're done processing the old scopes, did we add any new * scopes in this iteration? If so, go back and do those now. */ if (ido == NOID) { if (MDB_IDL_IS_ZERO(newsubs)) break; MDB_IDL_CPY(oldsubs, newsubs); MDB_IDL_ZERO(newsubs); cursoro = 0; ido = mdb_idl_first( oldsubs, &cursoro ); } /* Find the entry corresponding to the next scope. If it can't * be found, ignore it and move on. This should never happen; * we should never see the ID of an entry that doesn't exist. */ { 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; }
/* See if base is a child of any of the scopes */ int mdb_idscopes( Operation *op, IdScopes *isc ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; MDB_dbi dbi = mdb->mi_dn2id; MDB_val key, data; ID id; ID2 id2; char *ptr; int rc = 0; unsigned int x; unsigned int nrlen, rlen; diskNode *d; key.mv_size = sizeof(ID); if ( !isc->mc ) { rc = mdb_cursor_open( isc->mt, dbi, &isc->mc ); if ( rc ) return rc; } id = isc->id; while (id) { if ( !rc ) { key.mv_data = &id; rc = mdb_cursor_get( isc->mc, &key, &data, MDB_SET ); if ( rc ) return rc; /* save RDN info */ } d = data.mv_data; nrlen = (d->nrdnlen[0] << 8) | d->nrdnlen[1]; rlen = data.mv_size - sizeof(diskNode) - nrlen; isc->nrdns[isc->numrdns].bv_len = nrlen; isc->nrdns[isc->numrdns].bv_val = d->nrdn; isc->rdns[isc->numrdns].bv_len = rlen; isc->rdns[isc->numrdns].bv_val = d->nrdn+nrlen+1; isc->numrdns++; if (!rc && id != isc->id) { id2.mid = id; id2.mval = data; mdb_id2l_insert( isc->scopes, &id2 ); } ptr = data.mv_data; ptr += data.mv_size - sizeof(ID); memcpy( &id, ptr, sizeof(ID) ); x = mdb_id2l_search( isc->scopes, id ); if ( x <= isc->scopes[0].mid && isc->scopes[x].mid == id ) { if ( !isc->scopes[x].mval.mv_data ) { isc->nscope = x; return MDB_SUCCESS; } data = isc->scopes[x].mval; rc = 1; } if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; } return MDB_SUCCESS; }