From 46d6f994cd77ecd0764c8c616dfec99551664d9d Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Sat, 26 Jan 2013 20:32:46 +0000
Subject: [PATCH] ITS#7473 Add mdb_dn2id_walk() to walk subtree

Non-recursive tree walker.
---
 servers/slapd/back-mdb/dn2id.c     | 88 ++++++++++++++++++++++++++++++
 servers/slapd/back-mdb/proto-mdb.h |  4 ++
 2 files changed, 92 insertions(+)

diff --git a/servers/slapd/back-mdb/dn2id.c b/servers/slapd/back-mdb/dn2id.c
index abbeee8c1b..af003648af 100644
--- a/servers/slapd/back-mdb/dn2id.c
+++ b/servers/slapd/back-mdb/dn2id.c
@@ -756,3 +756,91 @@ mdb_idscopes(
 	}
 	return MDB_SUCCESS;
 }
+
+int
+mdb_dn2id_walk(
+	Operation *op,
+	IdScopes *isc
+)
+{
+	MDB_val key, data;
+	diskNode *d;
+	char *ptr;
+	int rc, n;
+	ID nsubs;
+
+	if ( !isc->numrdns ) {
+		key.mv_data = &isc->id;
+		key.mv_size = sizeof(ID);
+		rc = mdb_cursor_get( isc->mc, &key, &data, MDB_SET );
+		isc->scopes[0].mid = isc->id;
+		isc->numrdns++;
+		isc->nscope = 0;
+		/* skip base if not a subtree walk */
+		if ( op->ors_scope == LDAP_SCOPE_SUBTREE ||
+			op->ors_scope == LDAP_SCOPE_BASE )
+			return rc;
+	}
+	if ( op->ors_scope == LDAP_SCOPE_BASE )
+		return MDB_NOTFOUND;
+
+	for (;;) {
+		/* Get next sibling */
+		rc = mdb_cursor_get( isc->mc, &key, &data, MDB_NEXT_DUP );
+		if ( !rc ) {
+			ptr = data.mv_data + data.mv_size - 2*sizeof(ID);
+			d = data.mv_data;
+			memcpy( &isc->id, ptr, sizeof(ID));
+
+			/* If we're pushing down, see if there's any children to find */
+			if ( isc->nscope ) {
+				ptr += sizeof(ID);
+				memcpy( &nsubs, ptr, sizeof(ID));
+				/* No children, go to next sibling */
+				if ( nsubs < 2 )
+					continue;
+			}
+			n = isc->numrdns;
+			isc->scopes[n].mid = isc->id;
+			n--;
+			isc->nrdns[n].bv_len = ((d->nrdnlen[0] & 0x7f) << 8) | d->nrdnlen[1];
+			isc->nrdns[n].bv_val = d->nrdn;
+			isc->rdns[n].bv_val = d->nrdn+isc->nrdns[n].bv_len+1;
+			isc->rdns[n].bv_len = data.mv_size - sizeof(diskNode) - isc->nrdns[n].bv_len - sizeof(ID);
+			/* return this ID to caller */
+			if ( !isc->nscope )
+				break;
+
+			/* push down to child */
+			key.mv_data = &isc->id;
+			mdb_cursor_get( isc->mc, &key, &data, MDB_SET );
+			isc->nscope = 0;
+			isc->numrdns++;
+			continue;
+
+		} else if ( rc == MDB_NOTFOUND ) {
+			if ( !isc->nscope && op->ors_scope != LDAP_SCOPE_ONELEVEL ) {
+				/* reset to first dup */
+				mdb_cursor_get( isc->mc, &key, NULL, MDB_GET_CURRENT );
+				mdb_cursor_get( isc->mc, &key, &data, MDB_SET );
+				isc->nscope = 1;
+				continue;
+			} else {
+				isc->numrdns--;
+				/* stack is empty? */
+				if ( !isc->numrdns )
+					break;
+				/* pop up to prev node */
+				n = isc->numrdns - 1;
+				key.mv_data = &isc->scopes[n].mid;
+				key.mv_size = sizeof(ID);
+				data.mv_data = isc->nrdns[n].bv_val - 2;
+				mdb_cursor_get( isc->mc, &key, &data, MDB_GET_BOTH );
+				continue;
+			}
+		} else {
+			break;
+		}
+	}
+	return rc;
+}
diff --git a/servers/slapd/back-mdb/proto-mdb.h b/servers/slapd/back-mdb/proto-mdb.h
index ec67769713..a0d84da3eb 100644
--- a/servers/slapd/back-mdb/proto-mdb.h
+++ b/servers/slapd/back-mdb/proto-mdb.h
@@ -137,6 +137,10 @@ int mdb_idscopes(
 	Operation *op,
 	struct IdScopes *isc );
 
+int mdb_dn2id_walk(
+	Operation *op,
+	struct IdScopes *isc );
+
 MDB_cmp_func mdb_dup_compare;
 
 /*
-- 
GitLab