]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-mdb/dn2id.c
Plug memleak
[openldap] / servers / slapd / back-mdb / dn2id.c
index 1e9ca02165235d046f28f3ef7d054649c56bfd48..82ec07b7f1c8b5df96b9529f755655b8d2f9a164 100644 (file)
@@ -51,16 +51,15 @@ typedef struct diskNode {
  */
 int
 mdb_dup_compare(
-       DB *db, 
-       const DBT *usrkey,
-       const DBT *curkey
+       const MDB_val *usrkey,
+       const MDB_val *curkey
 )
 {
        diskNode *un, *cn;
-       int rc;
+       int rc, nrlen;
 
-       un = (diskNode *)usrkey->data;
-       cn = (diskNode *)curkey->data;
+       un = (diskNode *)usrkey->mv_data;
+       cn = (diskNode *)curkey->mv_data;
 
        /* data is not aligned, cannot compare directly */
        rc = un->nrdnlen[0] - cn->nrdnlen[0];
@@ -68,9 +67,11 @@ mdb_dup_compare(
        rc = un->nrdnlen[1] - cn->nrdnlen[1];
        if ( rc ) return rc;
 
-       return strcmp( un->nrdn, cn->nrdn );
+       nrlen = (un->nrdnlen[0] << 8) | un->nrdnlen[1];
+       return strncmp( un->nrdn, cn->nrdn, nrlen );
 }
 
+#if 0
 /* This function constructs a full DN for a given entry.
  */
 int mdb_fix_dn(
@@ -126,6 +127,7 @@ int mdb_fix_dn(
 
        return 0;
 }
+#endif
 
 /* We add two elements to the DN2ID database - a data item under the parent's
  * entryID containing the child's RDN and entryID, and an item under the
@@ -134,13 +136,13 @@ int mdb_fix_dn(
 int
 mdb_dn2id_add(
        Operation       *op,
-       DB_TXN *txn,
-       EntryInfo       *eip,
+       MDB_txn *txn,
+       ID pid,
        Entry           *e )
 {
        struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-       DB *db = mdb->bi_dn2id->bdi_db;
-       DBT             key, data;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
        ID              nid;
        int             rc, rlen, nrlen;
        diskNode *d;
@@ -164,63 +166,35 @@ mdb_dn2id_add(
        *ptr++ = '\0';
        ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
        *ptr++ = '\0';
-       MDB_ID2DISK( e->e_id, ptr );
+       memcpy( ptr, &e->e_id, sizeof( ID ));
 
-       DBTzero(&key);
-       DBTzero(&data);
-       key.size = sizeof(ID);
-       key.flags = DB_DBT_USERMEM;
-       MDB_ID2DISK( eip->bei_id, &nid );
+       key.mv_size = sizeof(ID);
+       key.mv_data = &nid;
 
-       key.data = &nid;
+       nid = pid;
 
        /* Need to make dummy root node once. Subsequent attempts
         * will fail harmlessly.
         */
-       if ( eip->bei_id == 0 ) {
+       if ( pid == 0 ) {
                diskNode dummy = {{0, 0}, "", "", ""};
-               data.data = &dummy;
-               data.size = sizeof(diskNode);
-               data.flags = DB_DBT_USERMEM;
+               data.mv_data = &dummy;
+               data.mv_size = sizeof(diskNode);
 
-               db->put( db, txn, &key, &data, DB_NODUPDATA );
+               mdb_put( txn, dbi, &key, &data, MDB_NODUPDATA );
        }
 
-       data.data = d;
-       data.size = sizeof(diskNode) + rlen + nrlen;
-       data.flags = DB_DBT_USERMEM;
+       data.mv_data = d;
+       data.mv_size = sizeof(diskNode) + rlen + nrlen;
 
-       rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
+       rc = mdb_put( txn, dbi, &key, &data, MDB_NODUPDATA );
 
        if (rc == 0) {
-               MDB_ID2DISK( e->e_id, &nid );
-               MDB_ID2DISK( eip->bei_id, ptr );
+               nid = e->e_id;
+               memcpy( ptr, &pid, sizeof( ID ));
                d->nrdnlen[0] ^= 0x80;
 
-               rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
-       }
-
-       /* Update all parents' IDL cache entries */
-       if ( rc == 0 && mdb->bi_idl_cache_size ) {
-               ID tmp[2];
-               char *ptr = ((char *)&tmp[1])-1;
-               key.data = ptr;
-               key.size = sizeof(ID)+1;
-               tmp[1] = eip->bei_id;
-               *ptr = DN_ONE_PREFIX;
-               mdb_idl_cache_add_id( mdb, db, &key, e->e_id );
-               if ( eip->bei_parent ) {
-                       *ptr = DN_SUBTREE_PREFIX;
-                       for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) {
-                               tmp[1] = eip->bei_id;
-                               mdb_idl_cache_add_id( mdb, db, &key, e->e_id );
-                       }
-                       /* Handle DB with empty suffix */
-                       if ( !op->o_bd->be_suffix[0].bv_len && eip ) {
-                               tmp[1] = eip->bei_id;
-                               mdb_idl_cache_add_id( mdb, db, &key, e->e_id );
-                       }
-               }
+               rc = mdb_put( txn, dbi, &key, &data, MDB_NODUPDATA );
        }
 
        op->o_tmpfree( d, op->o_tmpmemctx );
@@ -232,181 +206,241 @@ mdb_dn2id_add(
 int
 mdb_dn2id_delete(
        Operation       *op,
-       DB_TXN *txn,
-       EntryInfo       *eip,
+       MDB_txn *txn,
+       ID pid,
        Entry   *e )
 {
        struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-       DB *db = mdb->bi_dn2id->bdi_db;
-       DBT             key, data;
-       DBC     *cursor;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val key, data;
        diskNode *d;
-       int rc;
+       int rc, nrlen;
        ID      nid;
-       unsigned char dlen[2];
 
        Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2id_delete 0x%lx: \"%s\"\n",
                e->e_id, e->e_ndn, 0 );
 
-       DBTzero(&key);
-       key.size = sizeof(ID);
-       key.ulen = key.size;
-       key.flags = DB_DBT_USERMEM;
-       MDB_ID2DISK( eip->bei_id, &nid );
+       key.mv_size = sizeof(ID);
+       key.mv_data = &nid;
+       nid = pid;
 
-       DBTzero(&data);
-       data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len - sizeof(ID) - 1;
-       data.ulen = data.size;
-       data.dlen = data.size;
-       data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
-
-       key.data = &nid;
-
-       d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
-       d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff;
-       d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80;
-       dlen[0] = d->nrdnlen[0];
-       dlen[1] = d->nrdnlen[1];
-       memcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val, BEI(e)->bei_nrdn.bv_len+1 );
-       data.data = d;
+       nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
+       data.mv_size = sizeof(diskNode) + nrlen - sizeof(ID) - 1;
 
-       rc = db->cursor( db, txn, &cursor, mdb->bi_db_opflags );
-       if ( rc ) goto func_leave;
+       d = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
+       d->nrdnlen[1] = nrlen & 0xff;
+       d->nrdnlen[0] = (nrlen >> 8) | 0x80;
+       memcpy( d->nrdn, e->e_nname.bv_val, nrlen );
+       data.mv_data = d;
 
        /* Delete our ID from the parent's list */
-       rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
-       if ( rc == 0 ) {
-               if ( dlen[1] == d->nrdnlen[1] && dlen[0] == d->nrdnlen[0] &&
-                       !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val ))
-                       rc = cursor->c_del( cursor, 0 );
-               else
-                       rc = DB_NOTFOUND;
-       }
+       rc = mdb_del( txn, dbi, &key, &data, MDB_DEL_DUP );
 
        /* Delete our ID from the tree. With sorted duplicates, this
         * will leave any child nodes still hanging around. This is OK
         * for modrdn, which will add our info back in later.
         */
        if ( rc == 0 ) {
-               MDB_ID2DISK( e->e_id, &nid );
-               rc = cursor->c_get( cursor, &key, &data, DB_SET );
-               if ( rc == 0 )
-                       rc = cursor->c_del( cursor, 0 );
+               nid = e->e_id;
+               d->nrdnlen[0] ^= 0x80;
+               rc = mdb_del( txn, dbi, &key, &data, MDB_DEL_DUP );
        }
 
-       cursor->c_close( cursor );
-func_leave:
        op->o_tmpfree( d, op->o_tmpmemctx );
 
-       /* Delete IDL cache entries */
-       if ( rc == 0 && mdb->bi_idl_cache_size ) {
-               ID tmp[2];
-               char *ptr = ((char *)&tmp[1])-1;
-               key.data = ptr;
-               key.size = sizeof(ID)+1;
-               tmp[1] = eip->bei_id;
-               *ptr = DN_ONE_PREFIX;
-               mdb_idl_cache_del_id( mdb, db, &key, e->e_id );
-               if ( eip ->bei_parent ) {
-                       *ptr = DN_SUBTREE_PREFIX;
-                       for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) {
-                               tmp[1] = eip->bei_id;
-                               mdb_idl_cache_del_id( mdb, db, &key, e->e_id );
-                       }
-                       /* Handle DB with empty suffix */
-                       if ( !op->o_bd->be_suffix[0].bv_len && eip ) {
-                               tmp[1] = eip->bei_id;
-                               mdb_idl_cache_del_id( mdb, db, &key, e->e_id );
-                       }
-               }
-       }
        Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
        return rc;
 }
 
-
+/* return last found ID in *id if no match */
 int
 mdb_dn2id(
        Operation       *op,
+       MDB_txn *txn,
        struct berval   *in,
-       EntryInfo       *ei,
-       DB_TXN *txn,
-       DBC **cursor )
+       ID      *id,
+       struct berval   *matched )
 {
        struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-       DB *db = mdb->bi_dn2id->bdi_db;
-       DBT             key, data;
+       MDB_cursor *cursor;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
        int             rc = 0, nrlen;
        diskNode *d;
        char    *ptr;
-       unsigned char dlen[2];
-       ID idp, parentID;
+       char dn[SLAP_LDAPDN_MAXLEN];
+       ID pid, nid;
+       struct berval tmp;
 
        Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2id(\"%s\")\n", in->bv_val, 0, 0 );
 
-       nrlen = dn_rdnlen( op->o_bd, in );
-       if (!nrlen) nrlen = in->bv_len;
+       if ( !in->bv_len ) {
+               *id = 0;
+               nid = 0;
+               goto done;
+       }
 
-       DBTzero(&key);
-       key.size = sizeof(ID);
-       key.data = &idp;
-       key.ulen = sizeof(ID);
-       key.flags = DB_DBT_USERMEM;
-       parentID = ( ei->bei_parent != NULL ) ? ei->bei_parent->bei_id : 0;
-       MDB_ID2DISK( parentID, &idp );
+       tmp = *in;
 
-       DBTzero(&data);
-       data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1;
-       data.ulen = data.size * 3;
-       data.dlen = data.ulen;
-       data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
+       if ( matched ) {
+               matched->bv_val = dn + sizeof(dn) - 1;
+               matched->bv_len = 0;
+               *matched->bv_val-- = '\0';
+       }
 
-       rc = db->cursor( db, txn, cursor, mdb->bi_db_opflags );
-       if ( rc ) return rc;
+       nrlen = tmp.bv_len - op->o_bd->be_nsuffix[0].bv_len;
+       tmp.bv_val += nrlen;
+       tmp.bv_len = op->o_bd->be_nsuffix[0].bv_len;
+       nid = 0;
+       key.mv_size = sizeof(ID);
 
-       d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
-       d->nrdnlen[1] = nrlen & 0xff;
-       d->nrdnlen[0] = (nrlen >> 8) | 0x80;
-       dlen[0] = d->nrdnlen[0];
-       dlen[1] = d->nrdnlen[1];
-       ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
-       *ptr = '\0';
-       data.data = d;
+       rc = mdb_cursor_open( txn, dbi, &cursor );
+       if ( rc ) return rc;
 
-       rc = (*cursor)->c_get( *cursor, &key, &data, DB_GET_BOTH_RANGE );
-       if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] ||
-               strncmp( d->nrdn, in->bv_val, nrlen ))) {
-               rc = DB_NOTFOUND;
-       }
-       if ( rc == 0 ) {
-               ptr = (char *) data.data + data.size - sizeof(ID);
-               MDB_DISK2ID( ptr, &ei->bei_id );
-               ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
-               ptr = d->nrdn + nrlen + 1;
-               ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
-               if ( ei->bei_parent != NULL && !ei->bei_parent->bei_dkids ) {
-                       db_recno_t dkids;
-                       /* How many children does the parent have? */
-                       /* FIXME: do we need to lock the parent
-                        * entryinfo? Seems safe...
-                        */
-                       (*cursor)->c_count( *cursor, &dkids, 0 );
-                       ei->bei_parent->bei_dkids = dkids;
+       for (;;) {
+               key.mv_data = &pid;
+               pid = nid;
+
+               data.mv_size = sizeof(diskNode) + tmp.bv_len;
+               d = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
+               d->nrdnlen[1] = tmp.bv_len & 0xff;
+               d->nrdnlen[0] = (tmp.bv_len >> 8) | 0x80;
+               ptr = lutil_strncopy( d->nrdn, tmp.bv_val, tmp.bv_len );
+               *ptr = '\0';
+               data.mv_data = d;
+               rc = mdb_cursor_get( cursor, &key, &data, MDB_GET_BOTH );
+               op->o_tmpfree( d, op->o_tmpmemctx );
+               if ( rc )
+                       break;
+               ptr = (char *) data.mv_data + data.mv_size - sizeof(ID);
+               memcpy( &nid, ptr, sizeof(ID));
+
+               /* grab the non-normalized RDN */
+               if ( matched ) {
+                       int rlen;
+                       d = data.mv_data;
+                       rlen = data.mv_size - sizeof(diskNode) - tmp.bv_len;
+                       matched->bv_len += rlen;
+                       matched->bv_val -= rlen + 1;
+                       ptr = lutil_strcopy( matched->bv_val, d->rdn + tmp.bv_len );
+                       if ( pid ) {
+                               *ptr = ',';
+                               matched->bv_len++;
+                       }
+               }
+               if ( tmp.bv_val > in->bv_val ) {
+                       for (ptr = tmp.bv_val - 2; ptr > in->bv_val &&
+                               !DN_SEPARATOR(*ptr); ptr--)     /* empty */;
+                       if ( ptr >= in->bv_val ) {
+                               if (DN_SEPARATOR(*ptr)) ptr++;
+                               tmp.bv_len = tmp.bv_val - ptr - 1;
+                               tmp.bv_val = ptr;
+                       }
+               } else {
+                       break;
                }
        }
+       *id = nid; 
+       mdb_cursor_close( cursor );
+       if ( matched && matched->bv_len ) {
+               ptr = op->o_tmpalloc( matched->bv_len+1, op->o_tmpmemctx );
+               strcpy( ptr, matched->bv_val );
+               matched->bv_val = ptr;
+       }
 
-       op->o_tmpfree( d, op->o_tmpmemctx );
+done:
        if( rc != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2id: get failed: %s (%d)\n",
-                       db_strerror( rc ), rc, 0 );
+                       mdb_strerror( rc ), rc, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2id: got id=0x%lx\n",
-                       ei->bei_id, 0, 0 );
+                       nid, 0, 0 );
        }
 
        return rc;
 }
 
+/* return IDs from root to parent of DN */
+int
+mdb_dn2sups(
+       Operation       *op,
+       MDB_txn *txn,
+       struct berval   *in,
+       ID      *ids )
+{
+       struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+       MDB_cursor *cursor;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
+       int             rc = 0, nrlen;
+       diskNode *d;
+       char    *ptr;
+       ID pid, nid;
+       struct berval tmp;
+
+       Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2sups(\"%s\")\n", in->bv_val, 0, 0 );
+
+       if ( !in->bv_len ) {
+               goto done;
+       }
+
+       tmp = *in;
+
+       nrlen = tmp.bv_len - op->o_bd->be_nsuffix[0].bv_len;
+       tmp.bv_val += nrlen;
+       tmp.bv_len = op->o_bd->be_nsuffix[0].bv_len;
+       nid = 0;
+       key.mv_size = sizeof(ID);
+
+       rc = mdb_cursor_open( txn, dbi, &cursor );
+       if ( rc ) return rc;
+
+       for (;;) {
+               key.mv_data = &pid;
+               pid = nid;
+
+               data.mv_size = sizeof(diskNode) + tmp.bv_len;
+               d = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
+               d->nrdnlen[1] = tmp.bv_len & 0xff;
+               d->nrdnlen[0] = (tmp.bv_len >> 8) | 0x80;
+               ptr = lutil_strncopy( d->nrdn, tmp.bv_val, tmp.bv_len );
+               *ptr = '\0';
+               data.mv_data = d;
+               rc = mdb_cursor_get( cursor, &key, &data, MDB_GET_BOTH );
+               op->o_tmpfree( d, op->o_tmpmemctx );
+               if ( rc ) {
+                       mdb_cursor_close( cursor );
+                       break;
+               }
+               ptr = (char *) data.mv_data + data.mv_size - sizeof(ID);
+               memcpy( &nid, ptr, sizeof(ID));
+
+               if ( pid )
+                       mdb_idl_insert( ids, pid );
+
+               if ( tmp.bv_val > in->bv_val ) {
+                       for (ptr = tmp.bv_val - 2; ptr > in->bv_val &&
+                               !DN_SEPARATOR(*ptr); ptr--)     /* empty */;
+                       if ( ptr >= in->bv_val ) {
+                               if (DN_SEPARATOR(*ptr)) ptr++;
+                               tmp.bv_len = tmp.bv_val - ptr - 1;
+                               tmp.bv_val = ptr;
+                       }
+               } else {
+                       break;
+               }
+       }
+
+done:
+       if( rc != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2sups: get failed: %s (%d)\n",
+                       mdb_strerror( rc ), rc, 0 );
+       }
+
+       return rc;
+}
+
+#if 0
 int
 mdb_dn2id_parent(
        Operation *op,
@@ -463,58 +497,227 @@ mdb_dn2id_parent(
        op->o_tmpfree( d, op->o_tmpmemctx );
        return rc;
 }
+#endif
 
 int
 mdb_dn2id_children(
        Operation *op,
-       DB_TXN *txn,
+       MDB_txn *txn,
        Entry *e )
 {
        struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-       DB *db = mdb->bi_dn2id->bdi_db;
-       DBT             key, data;
-       DBC             *cursor;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
+       MDB_cursor      *cursor;
        int             rc;
        ID              id;
-       diskNode d;
 
-       DBTzero(&key);
-       key.size = sizeof(ID);
-       key.data = &e->e_id;
-       key.flags = DB_DBT_USERMEM;
-       MDB_ID2DISK( e->e_id, &id );
+       key.mv_size = sizeof(ID);
+       key.mv_data = &id;
+       id = e->e_id;
+
+       rc = mdb_cursor_open( txn, dbi, &cursor );
+       if ( rc ) return rc;
 
-       /* IDL cache is in host byte order */
-       if ( mdb->bi_idl_cache_size ) {
-               rc = mdb_idl_cache_get( mdb, db, &key, NULL );
-               if ( rc != LDAP_NO_SUCH_OBJECT ) {
-                       return rc;
+       rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
+       if ( rc == 0 ) {
+               unsigned long dkids;
+               rc = mdb_cursor_count( cursor, &dkids );
+               if ( rc == 0 ) {
+                       if ( dkids < 2 ) rc = MDB_NOTFOUND;
                }
        }
+       mdb_cursor_close( cursor );
+       return rc;
+}
 
-       key.data = &id;
-       DBTzero(&data);
-       data.data = &d;
-       data.ulen = sizeof(d);
-       data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
-       data.dlen = sizeof(d);
+int
+mdb_id2name(
+       Operation *op,
+       MDB_txn *txn,
+       MDB_cursor **cursp,
+       ID id,
+       struct berval *name,
+       struct berval *nname )
+{
+       struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
+       MDB_cursor      *cursor;
+       int             rc, len, nlen;
+       char dn[SLAP_LDAPDN_MAXLEN], ndn[SLAP_LDAPDN_MAXLEN], *ptr;
+       char *dptr, *nptr;
+       diskNode *d;
 
-       rc = db->cursor( db, txn, &cursor, mdb->bi_db_opflags );
-       if ( rc ) return rc;
+       key.mv_size = sizeof(ID);
 
-       rc = cursor->c_get( cursor, &key, &data, DB_SET );
+       if ( !*cursp ) {
+               rc = mdb_cursor_open( txn, dbi, cursp );
+               if ( rc ) return rc;
+       }
+       cursor = *cursp;
+
+       len = 0;
+       nlen = 0;
+       dptr = dn;
+       nptr = ndn;
+       while (id) {
+               int nrlen, rlen;
+               key.mv_data = &id;
+               data.mv_size = 0;
+               data.mv_data = "";
+               rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
+               if ( rc ) break;
+               ptr = data.mv_data;
+               ptr += data.mv_size - sizeof(ID);
+               memcpy( &id, ptr, sizeof(ID) );
+               d = data.mv_data;
+               nrlen = (d->nrdnlen[0] << 8) | d->nrdnlen[1];
+               if (nptr > ndn) {
+                       *nptr++ = ',';
+                       *dptr++ = ',';
+               }
+               /* copy name and trailing NUL */
+               memcpy( nptr, d->nrdn, nrlen+1 );
+               rlen = data.mv_size - sizeof(diskNode) - nrlen;
+               memcpy( dptr, d->nrdn+nrlen+1, rlen+1 );
+               nptr += nrlen;
+               dptr += rlen;
+       }
        if ( rc == 0 ) {
-               db_recno_t dkids;
-               rc = cursor->c_count( cursor, &dkids, 0 );
-               if ( rc == 0 ) {
-                       BEI(e)->bei_dkids = dkids;
-                       if ( dkids < 2 ) rc = DB_NOTFOUND;
+               name->bv_len = dptr - dn;
+               nname->bv_len = nptr - ndn;
+               name->bv_val = op->o_tmpalloc( name->bv_len + 1, op->o_tmpmemctx );
+               nname->bv_val = op->o_tmpalloc( nname->bv_len + 1, op->o_tmpmemctx );
+               memcpy( name->bv_val, dn, name->bv_len );
+               name->bv_val[name->bv_len] = '\0';
+               memcpy( nname->bv_val, ndn, nname->bv_len );
+               nname->bv_val[nname->bv_len] = '\0';
+       }
+       return rc;
+}
+
+/* Find each id in ids that is a child of base and move it to res.
+ */
+int
+mdb_idscope(
+       Operation *op,
+       MDB_txn *txn,
+       ID base,
+       ID *ids,
+       ID *res )
+{
+       struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
+       MDB_cursor      *cursor;
+       ID ida, id, cid, ci0, idc = 0;
+       char    *ptr;
+       int             rc;
+
+       key.mv_size = sizeof(ID);
+
+       MDB_IDL_ZERO( res );
+
+       rc = mdb_cursor_open( txn, dbi, &cursor );
+       if ( rc ) return rc;
+
+       ida = mdb_idl_first( ids, &cid );
+
+       /* Don't bother moving out of ids if it's a range */
+       if (!MDB_IDL_IS_RANGE(ids)) {
+               idc = ids[0];
+               ci0 = cid;
+       }
+
+       while (ida != NOID) {
+               id = ida;
+               while (id) {
+                       key.mv_data = &id;
+                       rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
+                       if ( rc ) {
+                               /* not found, move on to next */
+                               if (idc) {
+                                       if (ci0 != cid)
+                                               ids[ci0] = ids[cid];
+                                       ci0++;
+                               }
+                               break;
+                       }
+                       ptr = data.mv_data;
+                       ptr += data.mv_size - sizeof(ID);
+                       memcpy( &id, ptr, sizeof(ID) );
+                       if ( id == base ) {
+                               res[0]++;
+                               res[res[0]] = ida;
+                               if (idc)
+                                       idc--;
+                               break;
+                       } else {
+                               if (idc) {
+                                       if (ci0 != cid)
+                                               ids[ci0] = ids[cid];
+                                       ci0++;
+                               }
+                       }
+                       if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
+                               break;
                }
+               ida = mdb_idl_next( ids, &cid );
        }
-       cursor->c_close( cursor );
+       if (!MDB_IDL_IS_RANGE( ids ))
+               ids[0] = idc;
+
+       mdb_cursor_close( cursor );
        return rc;
 }
 
+/* See if base is a child of any of the scopes
+ */
+int
+mdb_idscopes(
+       Operation *op,
+       MDB_txn *txn,
+       MDB_cursor **cursp,
+       ID base,
+       ID *scopes )
+{
+       struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
+       MDB_dbi dbi = mdb->mi_dn2id;
+       MDB_val         key, data;
+       MDB_cursor      *cursor;
+       ID id;
+       char    *ptr;
+       int             rc;
+       unsigned int x;
+
+       key.mv_size = sizeof(ID);
+
+       if ( !*cursp ) {
+               rc = mdb_cursor_open( txn, dbi, cursp );
+               if ( rc ) return rc;
+       }
+       cursor = *cursp;
+
+       id = base;
+       while (id) {
+               key.mv_data = &id;
+               rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
+               if ( rc )
+                       break;
+               ptr = data.mv_data;
+               ptr += data.mv_size - sizeof(ID);
+               memcpy( &id, ptr, sizeof(ID) );
+               x = mdb_idl_search( scopes, id );
+               if ( scopes[x] == id )
+                       return MDB_SUCCESS;
+               if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
+                       break;
+       }
+       return MDB_NOTFOUND;
+}
+
+#if 0
 /* mdb_dn2idl:
  * We can't just use mdb_idl_fetch_key because
  * 1 - our data items are longer than just an entry ID
@@ -842,3 +1045,4 @@ mdb_dn2idl(
 
        return cx.rc;
 }
+#endif