Back to index

openldap  2.4.31
dn2id.c
Go to the documentation of this file.
00001 /* dn2id.c - routines to deal with the dn2id index */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 
00022 #include "back-bdb.h"
00023 #include "idl.h"
00024 #include "lutil.h"
00025 
00026 #ifndef BDB_HIER
00027 int
00028 bdb_dn2id_add(
00029        Operation *op,
00030        DB_TXN *txn,
00031        EntryInfo *eip,
00032        Entry         *e )
00033 {
00034        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00035        DB *db = bdb->bi_dn2id->bdi_db;
00036        int           rc;
00037        DBT           key, data;
00038        ID            nid;
00039        char          *buf;
00040        struct berval ptr, pdn;
00041 
00042        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add 0x%lx: \"%s\"\n",
00043               e->e_id, e->e_ndn, 0 );
00044        assert( e->e_id != NOID );
00045 
00046        DBTzero( &key );
00047        key.size = e->e_nname.bv_len + 2;
00048        key.ulen = key.size;
00049        key.flags = DB_DBT_USERMEM;
00050        buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
00051        key.data = buf;
00052        buf[0] = DN_BASE_PREFIX;
00053        ptr.bv_val = buf + 1;
00054        ptr.bv_len = e->e_nname.bv_len;
00055        AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
00056        ptr.bv_val[ptr.bv_len] = '\0';
00057 
00058        DBTzero( &data );
00059        data.data = &nid;
00060        data.size = sizeof( nid );
00061        BDB_ID2DISK( e->e_id, &nid );
00062 
00063        /* store it -- don't override */
00064        rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
00065        if( rc != 0 ) {
00066               char buf[ SLAP_TEXT_BUFLEN ];
00067               snprintf( buf, sizeof( buf ), "%s => bdb_dn2id_add dn=\"%s\" ID=0x%lx",
00068                      op->o_log_prefix, e->e_name.bv_val, e->e_id );
00069               Debug( LDAP_DEBUG_ANY, "%s: put failed: %s %d\n",
00070                      buf, db_strerror(rc), rc );
00071               goto done;
00072        }
00073 
00074 #ifndef BDB_MULTIPLE_SUFFIXES
00075        if( !be_issuffix( op->o_bd, &ptr ))
00076 #endif
00077        {
00078               buf[0] = DN_SUBTREE_PREFIX;
00079               rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
00080               if( rc != 0 ) {
00081                      Debug( LDAP_DEBUG_ANY,
00082                      "=> bdb_dn2id_add 0x%lx: subtree (%s) put failed: %d\n",
00083                      e->e_id, ptr.bv_val, rc );
00084                      goto done;
00085               }
00086               
00087 #ifdef BDB_MULTIPLE_SUFFIXES
00088        if( !be_issuffix( op->o_bd, &ptr ))
00089 #endif
00090        {
00091               dnParent( &ptr, &pdn );
00092        
00093               key.size = pdn.bv_len + 2;
00094               key.ulen = key.size;
00095               pdn.bv_val[-1] = DN_ONE_PREFIX;
00096               key.data = pdn.bv_val-1;
00097               ptr = pdn;
00098 
00099               rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
00100 
00101               if( rc != 0 ) {
00102                      Debug( LDAP_DEBUG_ANY,
00103                             "=> bdb_dn2id_add 0x%lx: parent (%s) insert failed: %d\n",
00104                                    e->e_id, ptr.bv_val, rc );
00105                      goto done;
00106               }
00107        }
00108 
00109 #ifndef BDB_MULTIPLE_SUFFIXES
00110        while( !be_issuffix( op->o_bd, &ptr ))
00111 #else
00112        for (;;)
00113 #endif
00114        {
00115               ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
00116 
00117               rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
00118 
00119               if( rc != 0 ) {
00120                      Debug( LDAP_DEBUG_ANY,
00121                             "=> bdb_dn2id_add 0x%lx: subtree (%s) insert failed: %d\n",
00122                                    e->e_id, ptr.bv_val, rc );
00123                      break;
00124               }
00125 #ifdef BDB_MULTIPLE_SUFFIXES
00126               if( be_issuffix( op->o_bd, &ptr )) break;
00127 #endif
00128               dnParent( &ptr, &pdn );
00129 
00130               key.size = pdn.bv_len + 2;
00131               key.ulen = key.size;
00132               key.data = pdn.bv_val - 1;
00133               ptr = pdn;
00134        }
00135        }
00136 
00137 done:
00138        op->o_tmpfree( buf, op->o_tmpmemctx );
00139        Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 );
00140        return rc;
00141 }
00142 
00143 int
00144 bdb_dn2id_delete(
00145        Operation *op,
00146        DB_TXN *txn,
00147        EntryInfo     *eip,
00148        Entry         *e )
00149 {
00150        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00151        DB *db = bdb->bi_dn2id->bdi_db;
00152        char          *buf;
00153        DBT           key;
00154        struct berval pdn, ptr;
00155        int           rc;
00156 
00157        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete 0x%lx: \"%s\"\n",
00158               e->e_id, e->e_ndn, 0 );
00159 
00160        DBTzero( &key );
00161        key.size = e->e_nname.bv_len + 2;
00162        buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
00163        key.data = buf;
00164        key.flags = DB_DBT_USERMEM;
00165        buf[0] = DN_BASE_PREFIX;
00166        ptr.bv_val = buf+1;
00167        ptr.bv_len = e->e_nname.bv_len;
00168        AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
00169        ptr.bv_val[ptr.bv_len] = '\0';
00170 
00171        /* delete it */
00172        rc = db->del( db, txn, &key, 0 );
00173        if( rc != 0 ) {
00174               Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: delete failed: %s %d\n",
00175                      e->e_id, db_strerror(rc), rc );
00176               goto done;
00177        }
00178 
00179 #ifndef BDB_MULTIPLE_SUFFIXES
00180        if( !be_issuffix( op->o_bd, &ptr ))
00181 #endif
00182        {
00183               buf[0] = DN_SUBTREE_PREFIX;
00184               rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
00185               if( rc != 0 ) {
00186                      Debug( LDAP_DEBUG_ANY,
00187                      "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n",
00188                      e->e_id, ptr.bv_val, rc );
00189                      goto done;
00190               }
00191 
00192 #ifdef BDB_MULTIPLE_SUFFIXES
00193        if( !be_issuffix( op->o_bd, &ptr ))
00194 #endif
00195        {
00196               dnParent( &ptr, &pdn );
00197 
00198               key.size = pdn.bv_len + 2;
00199               key.ulen = key.size;
00200               pdn.bv_val[-1] = DN_ONE_PREFIX;
00201               key.data = pdn.bv_val - 1;
00202               ptr = pdn;
00203 
00204               rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
00205 
00206               if( rc != 0 ) {
00207                      Debug( LDAP_DEBUG_ANY,
00208                             "=> bdb_dn2id_delete 0x%lx: parent (%s) delete failed: %d\n",
00209                             e->e_id, ptr.bv_val, rc );
00210                      goto done;
00211               }
00212        }
00213 
00214 #ifndef BDB_MULTIPLE_SUFFIXES
00215        while( !be_issuffix( op->o_bd, &ptr ))
00216 #else
00217        for (;;)
00218 #endif
00219        {
00220               ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
00221 
00222               rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
00223               if( rc != 0 ) {
00224                      Debug( LDAP_DEBUG_ANY,
00225                             "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n",
00226                             e->e_id, ptr.bv_val, rc );
00227                      goto done;
00228               }
00229 #ifdef BDB_MULTIPLE_SUFFIXES
00230               if( be_issuffix( op->o_bd, &ptr )) break;
00231 #endif
00232               dnParent( &ptr, &pdn );
00233 
00234               key.size = pdn.bv_len + 2;
00235               key.ulen = key.size;
00236               key.data = pdn.bv_val - 1;
00237               ptr = pdn;
00238        }
00239        }
00240 
00241 done:
00242        op->o_tmpfree( buf, op->o_tmpmemctx );
00243        Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
00244        return rc;
00245 }
00246 
00247 int
00248 bdb_dn2id(
00249        Operation *op,
00250        struct berval *dn,
00251        EntryInfo *ei,
00252        DB_TXN *txn,
00253        DBC **cursor )
00254 {
00255        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00256        DB *db = bdb->bi_dn2id->bdi_db;
00257        int           rc;
00258        DBT           key, data;
00259        ID            nid;
00260 
00261        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id(\"%s\")\n", dn->bv_val, 0, 0 );
00262 
00263        DBTzero( &key );
00264        key.size = dn->bv_len + 2;
00265        key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
00266        ((char *)key.data)[0] = DN_BASE_PREFIX;
00267        AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
00268 
00269        /* store the ID */
00270        DBTzero( &data );
00271        data.data = &nid;
00272        data.ulen = sizeof(ID);
00273        data.flags = DB_DBT_USERMEM;
00274 
00275        rc = db->cursor( db, txn, cursor, bdb->bi_db_opflags );
00276 
00277        /* fetch it */
00278        if ( !rc )
00279               rc = (*cursor)->c_get( *cursor, &key, &data, DB_SET );
00280 
00281        if( rc != 0 ) {
00282               Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
00283                      db_strerror( rc ), rc, 0 );
00284        } else {
00285               BDB_DISK2ID( &nid, &ei->bei_id );
00286               Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%lx\n",
00287                      ei->bei_id, 0, 0 );
00288        }
00289        op->o_tmpfree( key.data, op->o_tmpmemctx );
00290        return rc;
00291 }
00292 
00293 int
00294 bdb_dn2id_children(
00295        Operation *op,
00296        DB_TXN *txn,
00297        Entry *e )
00298 {
00299        DBT           key, data;
00300        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00301        DB *db = bdb->bi_dn2id->bdi_db;
00302        ID            id;
00303        int           rc;
00304 
00305        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children(\"%s\")\n",
00306               e->e_nname.bv_val, 0, 0 );
00307        DBTzero( &key );
00308        key.size = e->e_nname.bv_len + 2;
00309        key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
00310        ((char *)key.data)[0] = DN_ONE_PREFIX;
00311        AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
00312 
00313        if ( bdb->bi_idl_cache_size ) {
00314               rc = bdb_idl_cache_get( bdb, db, &key, NULL );
00315               if ( rc != LDAP_NO_SUCH_OBJECT ) {
00316                      op->o_tmpfree( key.data, op->o_tmpmemctx );
00317                      return rc;
00318               }
00319        }
00320        /* we actually could do a empty get... */
00321        DBTzero( &data );
00322        data.data = &id;
00323        data.ulen = sizeof(id);
00324        data.flags = DB_DBT_USERMEM;
00325        data.doff = 0;
00326        data.dlen = sizeof(id);
00327 
00328        rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
00329        op->o_tmpfree( key.data, op->o_tmpmemctx );
00330 
00331        Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children(\"%s\"): %s (%d)\n",
00332               e->e_nname.bv_val,
00333               rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
00334                      db_strerror(rc) ), rc );
00335 
00336        return rc;
00337 }
00338 
00339 int
00340 bdb_dn2idl(
00341        Operation *op,
00342        DB_TXN *txn,
00343        struct berval *ndn,
00344        EntryInfo *ei,
00345        ID *ids,
00346        ID *stack )
00347 {
00348        int           rc;
00349        DBT           key;
00350        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00351        DB *db = bdb->bi_dn2id->bdi_db;
00352        int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
00353               ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
00354 
00355        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl(\"%s\")\n",
00356               ndn->bv_val, 0, 0 );
00357 
00358 #ifndef       BDB_MULTIPLE_SUFFIXES
00359        if ( prefix == DN_SUBTREE_PREFIX
00360               && ( ei->bei_id == 0 ||
00361               ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len ))) {
00362               BDB_IDL_ALL(bdb, ids);
00363               return 0;
00364        }
00365 #endif
00366 
00367        DBTzero( &key );
00368        key.size = ndn->bv_len + 2;
00369        key.ulen = key.size;
00370        key.flags = DB_DBT_USERMEM;
00371        key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
00372        ((char *)key.data)[0] = prefix;
00373        AC_MEMCPY( &((char *)key.data)[1], ndn->bv_val, key.size - 1 );
00374 
00375        BDB_IDL_ZERO( ids );
00376        rc = bdb_idl_fetch_key( op->o_bd, db, txn, &key, ids, NULL, 0 );
00377 
00378        if( rc != 0 ) {
00379               Debug( LDAP_DEBUG_TRACE,
00380                      "<= bdb_dn2idl: get failed: %s (%d)\n",
00381                      db_strerror( rc ), rc, 0 );
00382 
00383        } else {
00384               Debug( LDAP_DEBUG_TRACE,
00385                      "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
00386                      (long) ids[0],
00387                      (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
00388        }
00389 
00390        op->o_tmpfree( key.data, op->o_tmpmemctx );
00391        return rc;
00392 }
00393 
00394 #else  /* BDB_HIER */
00395 /* Management routines for a hierarchically structured database.
00396  *
00397  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
00398  * entry in this database is a struct diskNode, keyed by entryID and with
00399  * the data containing the RDN and entryID of the node's children. We use
00400  * a B-Tree with sorted duplicates to store all the children of a node under
00401  * the same key. Also, the first item under the key contains the entry's own
00402  * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
00403  * well as top-down. To keep this info first in the list, the high bit of all
00404  * subsequent nrdnlen's is always set. This means we can only accomodate
00405  * RDNs up to length 32767, but that's fine since full DNs are already
00406  * restricted to 8192.
00407  *
00408  * The diskNode is a variable length structure. This definition is not
00409  * directly usable for in-memory manipulation.
00410  */
00411 typedef struct diskNode {
00412        unsigned char nrdnlen[2];
00413        char nrdn[1];
00414        char rdn[1];                        /* variable placement */
00415        unsigned char entryID[sizeof(ID)];  /* variable placement */
00416 } diskNode;
00417 
00418 /* Sort function for the sorted duplicate data items of a dn2id key.
00419  * Sorts based on normalized RDN, in length order.
00420  */
00421 int
00422 hdb_dup_compare(
00423        DB *db, 
00424        const DBT *usrkey,
00425        const DBT *curkey
00426 )
00427 {
00428        diskNode *un, *cn;
00429        int rc;
00430 
00431        un = (diskNode *)usrkey->data;
00432        cn = (diskNode *)curkey->data;
00433 
00434        /* data is not aligned, cannot compare directly */
00435        rc = un->nrdnlen[0] - cn->nrdnlen[0];
00436        if ( rc ) return rc;
00437        rc = un->nrdnlen[1] - cn->nrdnlen[1];
00438        if ( rc ) return rc;
00439 
00440        return strcmp( un->nrdn, cn->nrdn );
00441 }
00442 
00443 /* This function constructs a full DN for a given entry.
00444  */
00445 int hdb_fix_dn(
00446        Entry *e,
00447        int checkit )
00448 {
00449        EntryInfo *ei;
00450        int rlen = 0, nrlen = 0;
00451        char *ptr, *nptr;
00452        int max = 0;
00453 
00454        if ( !e->e_id )
00455               return 0;
00456 
00457        /* count length of all DN components */
00458        for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
00459               rlen += ei->bei_rdn.bv_len + 1;
00460               nrlen += ei->bei_nrdn.bv_len + 1;
00461               if (ei->bei_modrdns > max) max = ei->bei_modrdns;
00462        }
00463 
00464        /* See if the entry DN was invalidated by a subtree rename */
00465        if ( checkit ) {
00466               if ( BEI(e)->bei_modrdns >= max ) {
00467                      return 0;
00468               }
00469               /* We found a mismatch, tell the caller to lock it */
00470               if ( checkit == 1 ) {
00471                      return 1;
00472               }
00473               /* checkit == 2. do the fix. */
00474               free( e->e_name.bv_val );
00475               free( e->e_nname.bv_val );
00476        }
00477 
00478        e->e_name.bv_len = rlen - 1;
00479        e->e_nname.bv_len = nrlen - 1;
00480        e->e_name.bv_val = ch_malloc(rlen);
00481        e->e_nname.bv_val = ch_malloc(nrlen);
00482        ptr = e->e_name.bv_val;
00483        nptr = e->e_nname.bv_val;
00484        for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
00485               ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
00486               nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
00487               if ( ei->bei_parent ) {
00488                      *ptr++ = ',';
00489                      *nptr++ = ',';
00490               }
00491        }
00492        BEI(e)->bei_modrdns = max;
00493        if ( ptr > e->e_name.bv_val ) ptr[-1] = '\0';
00494        if ( nptr > e->e_nname.bv_val ) nptr[-1] = '\0';
00495 
00496        return 0;
00497 }
00498 
00499 /* We add two elements to the DN2ID database - a data item under the parent's
00500  * entryID containing the child's RDN and entryID, and an item under the
00501  * child's entryID containing the parent's entryID.
00502  */
00503 int
00504 hdb_dn2id_add(
00505        Operation     *op,
00506        DB_TXN *txn,
00507        EntryInfo     *eip,
00508        Entry         *e )
00509 {
00510        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00511        DB *db = bdb->bi_dn2id->bdi_db;
00512        DBT           key, data;
00513        ID            nid;
00514        int           rc, rlen, nrlen;
00515        diskNode *d;
00516        char *ptr;
00517 
00518        Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_add 0x%lx: \"%s\"\n",
00519               e->e_id, e->e_ndn, 0 );
00520 
00521        nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
00522        if (nrlen) {
00523               rlen = dn_rdnlen( op->o_bd, &e->e_name );
00524        } else {
00525               nrlen = e->e_nname.bv_len;
00526               rlen = e->e_name.bv_len;
00527        }
00528 
00529        d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
00530        d->nrdnlen[1] = nrlen & 0xff;
00531        d->nrdnlen[0] = (nrlen >> 8) | 0x80;
00532        ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
00533        *ptr++ = '\0';
00534        ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
00535        *ptr++ = '\0';
00536        BDB_ID2DISK( e->e_id, ptr );
00537 
00538        DBTzero(&key);
00539        DBTzero(&data);
00540        key.size = sizeof(ID);
00541        key.flags = DB_DBT_USERMEM;
00542        BDB_ID2DISK( eip->bei_id, &nid );
00543 
00544        key.data = &nid;
00545 
00546        /* Need to make dummy root node once. Subsequent attempts
00547         * will fail harmlessly.
00548         */
00549        if ( eip->bei_id == 0 ) {
00550               diskNode dummy = {{0, 0}, "", "", ""};
00551               data.data = &dummy;
00552               data.size = sizeof(diskNode);
00553               data.flags = DB_DBT_USERMEM;
00554 
00555               db->put( db, txn, &key, &data, DB_NODUPDATA );
00556        }
00557 
00558        data.data = d;
00559        data.size = sizeof(diskNode) + rlen + nrlen;
00560        data.flags = DB_DBT_USERMEM;
00561 
00562        rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
00563 
00564        if (rc == 0) {
00565               BDB_ID2DISK( e->e_id, &nid );
00566               BDB_ID2DISK( eip->bei_id, ptr );
00567               d->nrdnlen[0] ^= 0x80;
00568 
00569               rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
00570        }
00571 
00572        /* Update all parents' IDL cache entries */
00573        if ( rc == 0 && bdb->bi_idl_cache_size ) {
00574               ID tmp[2];
00575               char *ptr = ((char *)&tmp[1])-1;
00576               key.data = ptr;
00577               key.size = sizeof(ID)+1;
00578               tmp[1] = eip->bei_id;
00579               *ptr = DN_ONE_PREFIX;
00580               bdb_idl_cache_add_id( bdb, db, &key, e->e_id );
00581               if ( eip->bei_parent ) {
00582                      *ptr = DN_SUBTREE_PREFIX;
00583                      for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) {
00584                             tmp[1] = eip->bei_id;
00585                             bdb_idl_cache_add_id( bdb, db, &key, e->e_id );
00586                      }
00587                      /* Handle DB with empty suffix */
00588                      if ( !op->o_bd->be_suffix[0].bv_len && eip ) {
00589                             tmp[1] = eip->bei_id;
00590                             bdb_idl_cache_add_id( bdb, db, &key, e->e_id );
00591                      }
00592               }
00593        }
00594 
00595        op->o_tmpfree( d, op->o_tmpmemctx );
00596        Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 );
00597 
00598        return rc;
00599 }
00600 
00601 int
00602 hdb_dn2id_delete(
00603        Operation     *op,
00604        DB_TXN *txn,
00605        EntryInfo     *eip,
00606        Entry  *e )
00607 {
00608        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00609        DB *db = bdb->bi_dn2id->bdi_db;
00610        DBT           key, data;
00611        DBC    *cursor;
00612        diskNode *d;
00613        int rc;
00614        ID     nid;
00615        unsigned char dlen[2];
00616 
00617        Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_delete 0x%lx: \"%s\"\n",
00618               e->e_id, e->e_ndn, 0 );
00619 
00620        DBTzero(&key);
00621        key.size = sizeof(ID);
00622        key.ulen = key.size;
00623        key.flags = DB_DBT_USERMEM;
00624        BDB_ID2DISK( eip->bei_id, &nid );
00625 
00626        DBTzero(&data);
00627        data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len - sizeof(ID) - 1;
00628        data.ulen = data.size;
00629        data.dlen = data.size;
00630        data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00631 
00632        key.data = &nid;
00633 
00634        d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
00635        d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff;
00636        d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80;
00637        dlen[0] = d->nrdnlen[0];
00638        dlen[1] = d->nrdnlen[1];
00639        memcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val, BEI(e)->bei_nrdn.bv_len+1 );
00640        data.data = d;
00641 
00642        rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
00643        if ( rc ) goto func_leave;
00644 
00645        /* Delete our ID from the parent's list */
00646        rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
00647        if ( rc == 0 ) {
00648               if ( dlen[1] == d->nrdnlen[1] && dlen[0] == d->nrdnlen[0] &&
00649                      !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val ))
00650                      rc = cursor->c_del( cursor, 0 );
00651               else
00652                      rc = DB_NOTFOUND;
00653        }
00654 
00655        /* Delete our ID from the tree. With sorted duplicates, this
00656         * will leave any child nodes still hanging around. This is OK
00657         * for modrdn, which will add our info back in later.
00658         */
00659        if ( rc == 0 ) {
00660               BDB_ID2DISK( e->e_id, &nid );
00661               rc = cursor->c_get( cursor, &key, &data, DB_SET );
00662               if ( rc == 0 )
00663                      rc = cursor->c_del( cursor, 0 );
00664        }
00665 
00666        cursor->c_close( cursor );
00667 func_leave:
00668        op->o_tmpfree( d, op->o_tmpmemctx );
00669 
00670        /* Delete IDL cache entries */
00671        if ( rc == 0 && bdb->bi_idl_cache_size ) {
00672               ID tmp[2];
00673               char *ptr = ((char *)&tmp[1])-1;
00674               key.data = ptr;
00675               key.size = sizeof(ID)+1;
00676               tmp[1] = eip->bei_id;
00677               *ptr = DN_ONE_PREFIX;
00678               bdb_idl_cache_del_id( bdb, db, &key, e->e_id );
00679               if ( eip ->bei_parent ) {
00680                      *ptr = DN_SUBTREE_PREFIX;
00681                      for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) {
00682                             tmp[1] = eip->bei_id;
00683                             bdb_idl_cache_del_id( bdb, db, &key, e->e_id );
00684                      }
00685                      /* Handle DB with empty suffix */
00686                      if ( !op->o_bd->be_suffix[0].bv_len && eip ) {
00687                             tmp[1] = eip->bei_id;
00688                             bdb_idl_cache_del_id( bdb, db, &key, e->e_id );
00689                      }
00690               }
00691        }
00692        Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
00693        return rc;
00694 }
00695 
00696 
00697 int
00698 hdb_dn2id(
00699        Operation     *op,
00700        struct berval *in,
00701        EntryInfo     *ei,
00702        DB_TXN *txn,
00703        DBC **cursor )
00704 {
00705        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00706        DB *db = bdb->bi_dn2id->bdi_db;
00707        DBT           key, data;
00708        int           rc = 0, nrlen;
00709        diskNode *d;
00710        char   *ptr;
00711        unsigned char dlen[2];
00712        ID idp, parentID;
00713 
00714        Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id(\"%s\")\n", in->bv_val, 0, 0 );
00715 
00716        nrlen = dn_rdnlen( op->o_bd, in );
00717        if (!nrlen) nrlen = in->bv_len;
00718 
00719        DBTzero(&key);
00720        key.size = sizeof(ID);
00721        key.data = &idp;
00722        key.ulen = sizeof(ID);
00723        key.flags = DB_DBT_USERMEM;
00724        parentID = ( ei->bei_parent != NULL ) ? ei->bei_parent->bei_id : 0;
00725        BDB_ID2DISK( parentID, &idp );
00726 
00727        DBTzero(&data);
00728        data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1;
00729        data.ulen = data.size * 3;
00730        data.dlen = data.ulen;
00731        data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00732 
00733        rc = db->cursor( db, txn, cursor, bdb->bi_db_opflags );
00734        if ( rc ) return rc;
00735 
00736        d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
00737        d->nrdnlen[1] = nrlen & 0xff;
00738        d->nrdnlen[0] = (nrlen >> 8) | 0x80;
00739        dlen[0] = d->nrdnlen[0];
00740        dlen[1] = d->nrdnlen[1];
00741        ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
00742        *ptr = '\0';
00743        data.data = d;
00744 
00745        rc = (*cursor)->c_get( *cursor, &key, &data, DB_GET_BOTH_RANGE );
00746        if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] ||
00747               strncmp( d->nrdn, in->bv_val, nrlen ))) {
00748               rc = DB_NOTFOUND;
00749        }
00750        if ( rc == 0 ) {
00751               ptr = (char *) data.data + data.size - sizeof(ID);
00752               BDB_DISK2ID( ptr, &ei->bei_id );
00753               ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
00754               ptr = d->nrdn + nrlen + 1;
00755               ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
00756               if ( ei->bei_parent != NULL && !ei->bei_parent->bei_dkids ) {
00757                      db_recno_t dkids;
00758                      /* How many children does the parent have? */
00759                      /* FIXME: do we need to lock the parent
00760                       * entryinfo? Seems safe...
00761                       */
00762                      (*cursor)->c_count( *cursor, &dkids, 0 );
00763                      ei->bei_parent->bei_dkids = dkids;
00764               }
00765        }
00766 
00767        op->o_tmpfree( d, op->o_tmpmemctx );
00768        if( rc != 0 ) {
00769               Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: get failed: %s (%d)\n",
00770                      db_strerror( rc ), rc, 0 );
00771        } else {
00772               Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: got id=0x%lx\n",
00773                      ei->bei_id, 0, 0 );
00774        }
00775 
00776        return rc;
00777 }
00778 
00779 int
00780 hdb_dn2id_parent(
00781        Operation *op,
00782        DB_TXN *txn,
00783        EntryInfo *ei,
00784        ID *idp )
00785 {
00786        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00787        DB *db = bdb->bi_dn2id->bdi_db;
00788        DBT           key, data;
00789        DBC    *cursor;
00790        int           rc = 0;
00791        diskNode *d;
00792        char   *ptr;
00793        ID     nid;
00794 
00795        DBTzero(&key);
00796        key.size = sizeof(ID);
00797        key.data = &nid;
00798        key.ulen = sizeof(ID);
00799        key.flags = DB_DBT_USERMEM;
00800        BDB_ID2DISK( ei->bei_id, &nid );
00801 
00802        DBTzero(&data);
00803        data.flags = DB_DBT_USERMEM;
00804 
00805        rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
00806        if ( rc ) return rc;
00807 
00808        data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
00809        d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
00810        data.data = d;
00811 
00812        rc = cursor->c_get( cursor, &key, &data, DB_SET );
00813        if ( rc == 0 ) {
00814               if (d->nrdnlen[0] & 0x80) {
00815                      rc = LDAP_OTHER;
00816               } else {
00817                      db_recno_t dkids;
00818                      ptr = (char *) data.data + data.size - sizeof(ID);
00819                      BDB_DISK2ID( ptr, idp );
00820                      ei->bei_nrdn.bv_len = (d->nrdnlen[0] << 8) | d->nrdnlen[1];
00821                      ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
00822                      ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
00823                             ei->bei_nrdn.bv_len;
00824                      ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
00825                      ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
00826                      /* How many children does this node have? */
00827                      cursor->c_count( cursor, &dkids, 0 );
00828                      ei->bei_dkids = dkids;
00829               }
00830        }
00831        cursor->c_close( cursor );
00832        op->o_tmpfree( d, op->o_tmpmemctx );
00833        return rc;
00834 }
00835 
00836 int
00837 hdb_dn2id_children(
00838        Operation *op,
00839        DB_TXN *txn,
00840        Entry *e )
00841 {
00842        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00843        DB *db = bdb->bi_dn2id->bdi_db;
00844        DBT           key, data;
00845        DBC           *cursor;
00846        int           rc;
00847        ID            id;
00848        diskNode d;
00849 
00850        DBTzero(&key);
00851        key.size = sizeof(ID);
00852        key.data = &e->e_id;
00853        key.flags = DB_DBT_USERMEM;
00854        BDB_ID2DISK( e->e_id, &id );
00855 
00856        /* IDL cache is in host byte order */
00857        if ( bdb->bi_idl_cache_size ) {
00858               rc = bdb_idl_cache_get( bdb, db, &key, NULL );
00859               if ( rc != LDAP_NO_SUCH_OBJECT ) {
00860                      return rc;
00861               }
00862        }
00863 
00864        key.data = &id;
00865        DBTzero(&data);
00866        data.data = &d;
00867        data.ulen = sizeof(d);
00868        data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00869        data.dlen = sizeof(d);
00870 
00871        rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
00872        if ( rc ) return rc;
00873 
00874        rc = cursor->c_get( cursor, &key, &data, DB_SET );
00875        if ( rc == 0 ) {
00876               db_recno_t dkids;
00877               rc = cursor->c_count( cursor, &dkids, 0 );
00878               if ( rc == 0 ) {
00879                      BEI(e)->bei_dkids = dkids;
00880                      if ( dkids < 2 ) rc = DB_NOTFOUND;
00881               }
00882        }
00883        cursor->c_close( cursor );
00884        return rc;
00885 }
00886 
00887 /* bdb_dn2idl:
00888  * We can't just use bdb_idl_fetch_key because
00889  * 1 - our data items are longer than just an entry ID
00890  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
00891  *
00892  * We descend the tree recursively, so we define this cookie
00893  * to hold our necessary state information. The bdb_dn2idl_internal
00894  * function uses this cookie when calling itself.
00895  */
00896 
00897 struct dn2id_cookie {
00898        struct bdb_info *bdb;
00899        Operation *op;
00900        DB_TXN *txn;
00901        EntryInfo *ei;
00902        ID *ids;
00903        ID *tmp;
00904        ID *buf;
00905        DB *db;
00906        DBC *dbc;
00907        DBT key;
00908        DBT data;
00909        ID dbuf;
00910        ID id;
00911        ID nid;
00912        int rc;
00913        int depth;
00914        char need_sort;
00915        char prefix;
00916 };
00917 
00918 static int
00919 apply_func(
00920        void *data,
00921        void *arg )
00922 {
00923        EntryInfo *ei = data;
00924        ID *idl = arg;
00925 
00926        bdb_idl_append_one( idl, ei->bei_id );
00927        return 0;
00928 }
00929 
00930 static int
00931 hdb_dn2idl_internal(
00932        struct dn2id_cookie *cx
00933 )
00934 {
00935        BDB_IDL_ZERO( cx->tmp );
00936 
00937        if ( cx->bdb->bi_idl_cache_size ) {
00938               char *ptr = ((char *)&cx->id)-1;
00939 
00940               cx->key.data = ptr;
00941               cx->key.size = sizeof(ID)+1;
00942               if ( cx->prefix == DN_SUBTREE_PREFIX ) {
00943                      ID *ids = cx->depth ? cx->tmp : cx->ids;
00944                      *ptr = cx->prefix;
00945                      cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, ids);
00946                      if ( cx->rc == LDAP_SUCCESS ) {
00947                             if ( cx->depth ) {
00948                                    bdb_idl_delete( cx->tmp, cx->id ); /* ITS#6983, drop our own ID */
00949                                    bdb_idl_append( cx->ids, cx->tmp );
00950                                    cx->need_sort = 1;
00951                             }
00952                             return cx->rc;
00953                      }
00954               }
00955               *ptr = DN_ONE_PREFIX;
00956               cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
00957               if ( cx->rc == LDAP_SUCCESS ) {
00958                      goto gotit;
00959               }
00960               if ( cx->rc == DB_NOTFOUND ) {
00961                      return cx->rc;
00962               }
00963        }
00964 
00965        bdb_cache_entryinfo_lock( cx->ei );
00966 
00967        /* If number of kids in the cache differs from on-disk, load
00968         * up all the kids from the database
00969         */
00970        if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
00971               EntryInfo ei;
00972               db_recno_t dkids = cx->ei->bei_dkids;
00973               ei.bei_parent = cx->ei;
00974 
00975               /* Only one thread should load the cache */
00976               while ( cx->ei->bei_state & CACHE_ENTRY_ONELEVEL ) {
00977                      bdb_cache_entryinfo_unlock( cx->ei );
00978                      ldap_pvt_thread_yield();
00979                      bdb_cache_entryinfo_lock( cx->ei );
00980                      if ( cx->ei->bei_ckids+1 == cx->ei->bei_dkids ) {
00981                             goto synced;
00982                      }
00983               }
00984 
00985               cx->ei->bei_state |= CACHE_ENTRY_ONELEVEL;
00986 
00987               bdb_cache_entryinfo_unlock( cx->ei );
00988 
00989               cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
00990                      cx->bdb->bi_db_opflags );
00991               if ( cx->rc )
00992                      goto done_one;
00993 
00994               cx->data.data = &cx->dbuf;
00995               cx->data.ulen = sizeof(ID);
00996               cx->data.dlen = sizeof(ID);
00997               cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00998 
00999               /* The first item holds the parent ID. Ignore it. */
01000               cx->key.data = &cx->nid;
01001               cx->key.size = sizeof(ID);
01002               cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
01003               if ( cx->rc ) {
01004                      cx->dbc->c_close( cx->dbc );
01005                      goto done_one;
01006               }
01007 
01008               /* If the on-disk count is zero we've never checked it.
01009                * Count it now.
01010                */
01011               if ( !dkids ) {
01012                      cx->dbc->c_count( cx->dbc, &dkids, 0 );
01013                      cx->ei->bei_dkids = dkids;
01014               }
01015 
01016               cx->data.data = cx->buf;
01017               cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
01018               cx->data.flags = DB_DBT_USERMEM;
01019 
01020               if ( dkids > 1 ) {
01021                      /* Fetch the rest of the IDs in a loop... */
01022                      while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
01023                             DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
01024                             u_int8_t *j;
01025                             size_t len;
01026                             void *ptr;
01027                             DB_MULTIPLE_INIT( ptr, &cx->data );
01028                             while (ptr) {
01029                                    DB_MULTIPLE_NEXT( ptr, &cx->data, j, len );
01030                                    if (j) {
01031                                           EntryInfo *ei2;
01032                                           diskNode *d = (diskNode *)j;
01033                                           short nrlen;
01034 
01035                                           BDB_DISK2ID( j + len - sizeof(ID), &ei.bei_id );
01036                                           nrlen = ((d->nrdnlen[0] ^ 0x80) << 8) | d->nrdnlen[1];
01037                                           ei.bei_nrdn.bv_len = nrlen;
01038                                           /* nrdn/rdn are set in-place.
01039                                            * hdb_cache_load will copy them as needed
01040                                            */
01041                                           ei.bei_nrdn.bv_val = d->nrdn;
01042                                           ei.bei_rdn.bv_len = len - sizeof(diskNode)
01043                                                  - ei.bei_nrdn.bv_len;
01044                                           ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
01045                                           bdb_idl_append_one( cx->tmp, ei.bei_id );
01046                                           hdb_cache_load( cx->bdb, &ei, &ei2 );
01047                                    }
01048                             }
01049                      }
01050               }
01051 
01052               cx->rc = cx->dbc->c_close( cx->dbc );
01053 done_one:
01054               bdb_cache_entryinfo_lock( cx->ei );
01055               cx->ei->bei_state &= ~CACHE_ENTRY_ONELEVEL;
01056               bdb_cache_entryinfo_unlock( cx->ei );
01057               if ( cx->rc )
01058                      return cx->rc;
01059 
01060        } else {
01061               /* The in-memory cache is in sync with the on-disk data.
01062                * do we have any kids?
01063                */
01064 synced:
01065               cx->rc = 0;
01066               if ( cx->ei->bei_ckids > 0 ) {
01067                      /* Walk the kids tree; order is irrelevant since bdb_idl_sort
01068                       * will sort it later.
01069                       */
01070                      avl_apply( cx->ei->bei_kids, apply_func,
01071                             cx->tmp, -1, AVL_POSTORDER );
01072               }
01073               bdb_cache_entryinfo_unlock( cx->ei );
01074        }
01075 
01076        if ( !BDB_IDL_IS_RANGE( cx->tmp ) && cx->tmp[0] > 3 )
01077               bdb_idl_sort( cx->tmp, cx->buf );
01078        if ( cx->bdb->bi_idl_cache_max_size && !BDB_IDL_IS_ZERO( cx->tmp )) {
01079               char *ptr = ((char *)&cx->id)-1;
01080               cx->key.data = ptr;
01081               cx->key.size = sizeof(ID)+1;
01082               *ptr = DN_ONE_PREFIX;
01083               bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
01084        }
01085 
01086 gotit:
01087        if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
01088               if ( cx->prefix == DN_SUBTREE_PREFIX ) {
01089                      bdb_idl_append( cx->ids, cx->tmp );
01090                      cx->need_sort = 1;
01091                      if ( !(cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS)) {
01092                             ID *save, idcurs;
01093                             EntryInfo *ei = cx->ei;
01094                             int nokids = 1;
01095                             save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
01096                                    cx->op->o_tmpmemctx );
01097                             BDB_IDL_CPY( save, cx->tmp );
01098 
01099                             idcurs = 0;
01100                             cx->depth++;
01101                             for ( cx->id = bdb_idl_first( save, &idcurs );
01102                                    cx->id != NOID;
01103                                    cx->id = bdb_idl_next( save, &idcurs )) {
01104                                    EntryInfo *ei2;
01105                                    cx->ei = NULL;
01106                                    if ( bdb_cache_find_id( cx->op, cx->txn, cx->id, &cx->ei,
01107                                           ID_NOENTRY, NULL ))
01108                                           continue;
01109                                    if ( cx->ei ) {
01110                                           ei2 = cx->ei;
01111                                           if ( !( ei2->bei_state & CACHE_ENTRY_NO_KIDS )) {
01112                                                  BDB_ID2DISK( cx->id, &cx->nid );
01113                                                  hdb_dn2idl_internal( cx );
01114                                                  if ( !BDB_IDL_IS_ZERO( cx->tmp ))
01115                                                         nokids = 0;
01116                                           }
01117                                           bdb_cache_entryinfo_lock( ei2 );
01118                                           ei2->bei_finders--;
01119                                           bdb_cache_entryinfo_unlock( ei2 );
01120                                    }
01121                             }
01122                             cx->depth--;
01123                             cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
01124                             if ( nokids ) {
01125                                    bdb_cache_entryinfo_lock( ei );
01126                                    ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS;
01127                                    bdb_cache_entryinfo_unlock( ei );
01128                             }
01129                      }
01130                      /* Make sure caller knows it had kids! */
01131                      cx->tmp[0]=1;
01132 
01133                      cx->rc = 0;
01134               } else {
01135                      BDB_IDL_CPY( cx->ids, cx->tmp );
01136               }
01137        }
01138        return cx->rc;
01139 }
01140 
01141 int
01142 hdb_dn2idl(
01143        Operation     *op,
01144        DB_TXN *txn,
01145        struct berval *ndn,
01146        EntryInfo     *ei,
01147        ID *ids,
01148        ID *stack )
01149 {
01150        struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
01151        struct dn2id_cookie cx;
01152 
01153        Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl(\"%s\")\n",
01154               ndn->bv_val, 0, 0 );
01155 
01156 #ifndef BDB_MULTIPLE_SUFFIXES
01157        if ( op->ors_scope != LDAP_SCOPE_ONELEVEL && 
01158               ( ei->bei_id == 0 ||
01159               ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len )))
01160        {
01161               BDB_IDL_ALL( bdb, ids );
01162               return 0;
01163        }
01164 #endif
01165 
01166        cx.id = ei->bei_id;
01167        BDB_ID2DISK( cx.id, &cx.nid );
01168        cx.ei = ei;
01169        cx.bdb = bdb;
01170        cx.db = cx.bdb->bi_dn2id->bdi_db;
01171        cx.prefix = (op->ors_scope == LDAP_SCOPE_ONELEVEL) ?
01172               DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
01173        cx.ids = ids;
01174        cx.tmp = stack;
01175        cx.buf = stack + BDB_IDL_UM_SIZE;
01176        cx.op = op;
01177        cx.txn = txn;
01178        cx.need_sort = 0;
01179        cx.depth = 0;
01180 
01181        if ( cx.prefix == DN_SUBTREE_PREFIX ) {
01182               ids[0] = 1;
01183               ids[1] = cx.id;
01184        } else {
01185               BDB_IDL_ZERO( ids );
01186        }
01187        if ( cx.ei->bei_state & CACHE_ENTRY_NO_KIDS )
01188               return LDAP_SUCCESS;
01189 
01190        DBTzero(&cx.key);
01191        cx.key.ulen = sizeof(ID);
01192        cx.key.size = sizeof(ID);
01193        cx.key.flags = DB_DBT_USERMEM;
01194 
01195        DBTzero(&cx.data);
01196 
01197        hdb_dn2idl_internal(&cx);
01198        if ( cx.need_sort ) {
01199               char *ptr = ((char *)&cx.id)-1;
01200               if ( !BDB_IDL_IS_RANGE( cx.ids ) && cx.ids[0] > 3 ) 
01201                      bdb_idl_sort( cx.ids, cx.tmp );
01202               cx.key.data = ptr;
01203               cx.key.size = sizeof(ID)+1;
01204               *ptr = cx.prefix;
01205               cx.id = ei->bei_id;
01206               if ( cx.bdb->bi_idl_cache_max_size )
01207                      bdb_idl_cache_put( cx.bdb, cx.db, &cx.key, cx.ids, cx.rc );
01208        }
01209 
01210        if ( cx.rc == DB_NOTFOUND )
01211               cx.rc = LDAP_SUCCESS;
01212 
01213        return cx.rc;
01214 }
01215 #endif /* BDB_HIER */