+static int bdb_tool_next_id(
+ Operation *op,
+ DB_TXN *tid,
+ Entry *e,
+ struct berval *text,
+ int hole )
+{
+ struct berval dn = e->e_name;
+ struct berval ndn = e->e_nname;
+ struct berval pdn, npdn;
+ EntryInfo *ei = NULL, eidummy;
+ int rc;
+
+ if (ndn.bv_len == 0) {
+ e->e_id = 0;
+ return 0;
+ }
+
+ rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
+ if ( ei ) bdb_cache_entryinfo_unlock( ei );
+ if ( rc == DB_NOTFOUND ) {
+ if ( !be_issuffix( op->o_bd, &ndn ) ) {
+ ID eid = e->e_id;
+ dnParent( &dn, &pdn );
+ dnParent( &ndn, &npdn );
+ e->e_name = pdn;
+ e->e_nname = npdn;
+ rc = bdb_tool_next_id( op, tid, e, text, 1 );
+ e->e_name = dn;
+ e->e_nname = ndn;
+ if ( rc ) {
+ return rc;
+ }
+ /* If parent didn't exist, it was created just now
+ * and its ID is now in e->e_id. Make sure the current
+ * entry gets added under the new parent ID.
+ */
+ if ( eid != e->e_id ) {
+ eidummy.bei_id = e->e_id;
+ ei = &eidummy;
+ }
+ }
+ rc = bdb_next_id( op->o_bd, tid, &e->e_id );
+ if ( rc ) {
+ snprintf( text->bv_val, text->bv_len,
+ "next_id failed: %s (%d)",
+ db_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ return rc;
+ }
+ rc = bdb_dn2id_add( op, tid, ei, e );
+ if ( rc ) {
+ snprintf( text->bv_val, text->bv_len,
+ "dn2id_add failed: %s (%d)",
+ db_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ } else if ( hole ) {
+ if ( nholes == nhmax - 1 ) {
+ if ( holes == hbuf ) {
+ holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
+ AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
+ } else {
+ holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
+ }
+ nhmax *= 2;
+ }
+ ber_dupbv( &holes[nholes].dn, &ndn );
+ holes[nholes++].id = e->e_id;
+ }
+ } else if ( !hole ) {
+ unsigned i;
+
+ e->e_id = ei->bei_id;
+
+ for ( i=0; i<nholes; i++) {
+ if ( holes[i].id == e->e_id ) {
+ int j;
+ free(holes[i].dn.bv_val);
+ for (j=i;j<nholes;j++) holes[j] = holes[j+1];
+ holes[j].id = 0;
+ nholes--;
+ break;
+ } else if ( holes[i].id > e->e_id ) {
+ break;
+ }
+ }
+ }
+ return rc;
+}
+