summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldap/servers/slapd/back-ldbm/dn2entry.c12
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c272
2 files changed, 271 insertions, 13 deletions
diff --git a/ldap/servers/slapd/back-ldbm/dn2entry.c b/ldap/servers/slapd/back-ldbm/dn2entry.c
index d309eff1..4d6dc7c3 100644
--- a/ldap/servers/slapd/back-ldbm/dn2entry.c
+++ b/ldap/servers/slapd/back-ldbm/dn2entry.c
@@ -73,7 +73,7 @@ dn2entry(
e = cache_find_dn(&inst->inst_cache, ndnv.bv_val, ndnv.bv_len);
if (e == NULL)
{
- ID id = 0;
+ ID id = ALLID;
/* convert dn to entry id */
if (entryrdn_get_switch())
{ /* subtree-rename: on */
@@ -90,6 +90,16 @@ dn2entry(
/* There's no entry with this DN. */
goto bail;
}
+ if (0 == id) {
+ /*
+ * Note: A special entry such as RUV could be added
+ * to entryrdn even if the suffix does not exist in
+ * the index. At that time, fake ID 0 is used as the
+ * parent id.
+ */
+ /* There's no entry with this suffix. */
+ goto bail;
+ }
indexname = LDBM_ENTRYRDN_STR;
}
else
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 8b0a0056..36fbe933 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -83,6 +83,14 @@ typedef struct _rdn_elem {
((elem)->rdn_elem_nrdn_rdn + \
sizeushort_stored_to_internal((elem)->rdn_elem_nrdn_len))
+#define TMPID 0 /* Used for the fake ID */
+
+/* RDN(s) which can be added even if no suffix exists in the entryrdn index */
+const char *rdn_exceptions[] = {
+ "nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff",
+ NULL
+};
+
/* helper functions */
static rdn_elem *_entryrdn_new_rdn_elem(backend *be, ID id, Slapi_RDN *srdn, size_t *length);
static void _entryrdn_dup_rdn_elem(const void *raw, rdn_elem **new);
@@ -1224,7 +1232,6 @@ entryrdn_get_parent(backend *be,
slapi_ch_free_string(&orignrdn);
}
- /* Setting the bulk fetch buffer */
memset(&data, 0, sizeof(data));
data.flags = DB_DBT_MALLOC;
@@ -1593,12 +1600,11 @@ _entryrdn_put_data(DBC *cursor, DBT *key, DBT *data, char type)
rc = cursor->c_put(cursor, key, data, DB_NODUPDATA);
if (rc) {
if (DB_KEYEXIST == rc) {
- /* this is okay; this won't happen, tho */
- slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ /* this is okay */
+ slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
"_entryrdn_put_data: The same key (%s) and the "
"data exists in index\n",
(char *)key->data);
- rc = 0;
} else {
char *keyword = NULL;
if (type == RDN_INDEX_CHILD) {
@@ -1748,6 +1754,182 @@ bail:
}
/*
+ * Helper function to replace a temporary id assigned to suffix id.
+ */
+static int
+_entryrdn_replace_suffix_id(DBC *cursor, DBT *key, DBT *adddata,
+ ID id, const char *normsuffix)
+{
+ int rc = 0;
+ char *keybuf = NULL;
+ char *realkeybuf = NULL;
+ DBT realkey;
+ static char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
+ DBT data;
+ DBT moddata;
+ rdn_elem **childelems = NULL;
+ rdn_elem **cep = NULL;
+ rdn_elem *childelem = NULL;
+ size_t childnum = 4;
+ size_t curr_childnum = 0;
+
+ /* temporary id added for the non exisiting suffix */
+ /* Let's replace it with the real entry ID */
+ /* SELF */
+ rc = cursor->c_put(cursor, key, adddata, DB_CURRENT);
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Adding suffix %s failed: "
+ "%s (%d)\n", normsuffix, dblayer_strerror(rc), rc);
+ goto bail;
+ }
+
+ /*
+ * Fixing Child link:
+ * key: C0:Suffix --> C<realID>:Suffix
+ */
+ /* E.g., C1:dc=example,dc=com */
+ keybuf = slapi_ch_smprintf("%c%u:%s", RDN_INDEX_CHILD, TMPID, normsuffix);
+ key->data = keybuf;
+ key->size = key->ulen = strlen(keybuf) + 1;
+ key->flags = DB_DBT_USERMEM;
+
+ /* Setting the bulk fetch buffer */
+ memset(&data, 0, sizeof(data));
+ data.ulen = sizeof(buffer);
+ data.size = sizeof(buffer);
+ data.data = buffer;
+ data.flags = DB_DBT_USERMEM;
+
+ realkeybuf = slapi_ch_smprintf("%c%u:%s", RDN_INDEX_CHILD, id, normsuffix);
+ realkey.data = realkeybuf;
+ realkey.size = realkey.ulen = strlen(realkeybuf) + 1;
+ realkey.flags = DB_DBT_USERMEM;
+
+ memset(&moddata, 0, sizeof(moddata));
+ moddata.flags = DB_DBT_USERMEM;
+retry_get0:
+ rc = cursor->c_get(cursor, key, &data, DB_SET|DB_MULTIPLE);
+ if (DB_LOCK_DEADLOCK == rc) {
+ /* try again */
+ goto retry_get0;
+ } else if (DB_NOTFOUND == rc) {
+ _entryrdn_cursor_print_error("_entryrdn_insert_key",
+ key->data, data.size, data.ulen, rc);
+ goto bail;
+ } else if (rc) {
+ _entryrdn_cursor_print_error("_entryrdn_insert_key",
+ key->data, data.size, data.ulen, rc);
+ goto bail;
+ }
+ childelems = (rdn_elem **)slapi_ch_calloc(childnum, sizeof(rdn_elem *));
+ do {
+ DBT dataret;
+ void *ptr;
+ DB_MULTIPLE_INIT(ptr, &data);
+ do {
+ memset(&dataret, 0, sizeof(dataret));
+ DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
+ if (NULL == dataret.data || NULL == ptr) {
+ break;
+ }
+ _entryrdn_dup_rdn_elem((const void *)dataret.data, &childelem);
+ moddata.data = childelem;
+ moddata.ulen = moddata.size = _entryrdn_rdn_elem_size(childelem);
+ /* Delete it first */
+ rc = _entryrdn_del_data(cursor, key, &moddata);
+ if (rc) {
+ goto bail0;
+ }
+ /* Add it back */
+ rc = _entryrdn_put_data(cursor, &realkey, &moddata,
+ RDN_INDEX_CHILD);
+ if (curr_childnum + 1 == childnum) {
+ childnum *= 2;
+ childelems = (rdn_elem **)slapi_ch_realloc((char *)childelems,
+ sizeof(rdn_elem *) * childnum);
+ memset(childelems + curr_childnum, 0,
+ sizeof(rdn_elem *) * (childnum - curr_childnum));
+ }
+ childelems[curr_childnum++] = childelem;
+ /* We don't access the address with this variable any more */
+ childelem = NULL;
+ } while (NULL != dataret.data && NULL != ptr);
+retry_get1:
+ rc = cursor->c_get(cursor, key, &data, DB_NEXT_DUP|DB_MULTIPLE);
+ if (DB_LOCK_DEADLOCK == rc) {
+ /* try again */
+ goto retry_get1;
+ } else if (DB_NOTFOUND == rc) {
+ rc = 0;
+ break; /* done */
+ } else if (rc) {
+ _entryrdn_cursor_print_error("_entryrdn_insert_key",
+ key->data, data.size, data.ulen, rc);
+ goto bail0;
+ }
+ } while (0 == rc);
+
+ /*
+ * Fixing Children's parent link:
+ * key: P<childID>:<childRDN> --> P<childID>:<childRDN>
+ * data: 0 --> <realID>
+ */
+ for (cep = childelems; cep && *cep; cep++) {
+ rdn_elem *pelem = NULL;
+ slapi_ch_free_string(&keybuf);
+ /* E.g., P1:nsuniqueid=ffff.... */
+ keybuf = slapi_ch_smprintf("%c%u:%s", RDN_INDEX_PARENT,
+ id_stored_to_internal((*cep)->rdn_elem_id),
+ (*cep)->rdn_elem_nrdn_rdn);
+ key->data = keybuf;
+ key->size = key->ulen = strlen(keybuf) + 1;
+ key->flags = DB_DBT_USERMEM;
+
+ memset(&moddata, 0, sizeof(moddata));
+ moddata.flags = DB_DBT_MALLOC;
+
+ /* Position cursor at the matching key */
+retry_get2:
+ rc = cursor->c_get(cursor, key, &moddata, DB_SET);
+ if (rc) {
+ if (DB_LOCK_DEADLOCK == rc) {
+ /* try again */
+ goto retry_get2;
+ } else if (rc) {
+ _entryrdn_cursor_print_error("_entryrdn_insert_key",
+ key->data, data.size, data.ulen, rc);
+ goto bail0;
+ }
+ }
+ pelem = (rdn_elem *)moddata.data;
+ if (TMPID == id_stored_to_internal(pelem->rdn_elem_id)) {
+ /* the parent id is TMPID;
+ * replace it with the given id */
+ id_internal_to_stored(id, pelem->rdn_elem_id);
+ rc = cursor->c_put(cursor, key, &moddata, DB_CURRENT);
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Fixing the parent link "
+ "(%s) failed: %s (%d)\n", keybuf,
+ dblayer_strerror(rc), rc);
+ goto bail0;
+ }
+ }
+ slapi_ch_free((void **)&moddata.data);
+ } /* for (cep = childelems; cep && *cep; cep++) */
+bail0:
+ for (cep = childelems; cep && *cep; cep++) {
+ slapi_ch_free((void **)cep);
+ }
+ slapi_ch_free((void **)&childelems);
+bail:
+ slapi_ch_free_string(&keybuf);
+ slapi_ch_free_string(&realkeybuf);
+ return rc;
+}
+
+/*
* This function starts from the suffix following the child links to the bottom.
* If the target leaf node does not exist, the nodes (the child link of the
* parent node and the self link) are added.
@@ -1818,6 +2000,32 @@ _entryrdn_insert_key(backend *be,
adddata.flags = DB_DBT_USERMEM;
rc = _entryrdn_put_data(cursor, &key, &adddata, RDN_INDEX_SELF);
+ if (DB_KEYEXIST == rc) {
+ DBT existdata;
+ rdn_elem *existelem = NULL;
+ ID tmpid;
+ memset(&existdata, 0, sizeof(existdata));
+ existdata.flags = DB_DBT_MALLOC;
+ rc = cursor->c_get(cursor, &key, &existdata, DB_SET);
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Get existing suffix %s "
+ "failed: %s (%d)\n",
+ nrdn, dblayer_strerror(rc), rc);
+ goto bail;
+ }
+ existelem = (rdn_elem *)existdata.data;
+ tmpid = id_stored_to_internal(existelem->rdn_elem_id);
+ slapi_ch_free((void **)&existelem);
+ if (TMPID == tmpid) {
+ rc = _entryrdn_replace_suffix_id(cursor, &key, &adddata,
+ id, nrdn);
+ if (rc) {
+ goto bail;
+ }
+ } /* if (TMPID == tmpid) */
+ rc = 0;
+ } /* if (DB_KEYEXIST == rc) */
slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
"_entryrdn_insert_key: Suffix %s added: %d\n",
nrdn, rc);
@@ -1849,7 +2057,6 @@ _entryrdn_insert_key(backend *be,
goto bail;
}
- slapi_rdn_free(&tmpsrdn);
memset(&data, 0, sizeof(data));
data.ulen = data.size = len;
data.data = elem;
@@ -1858,11 +2065,52 @@ _entryrdn_insert_key(backend *be,
/* getting the suffix element */
rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, &elem);
if (rc) {
- slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
- "_entryrdn_insert_key: Suffix \"%s\" not found: "
- "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
- goto bail;
+ const char *myrdn = slapi_rdn_get_nrdn(srdn);
+ const char *ep = NULL;
+ int isexception = 0;
+ /* Check the RDN is in the exception list */
+ for (ep = *rdn_exceptions; ep && *ep; ep++) {
+ if (!strcmp(ep, myrdn)) {
+ isexception = 1;
+ }
+ }
+
+ if (isexception) {
+ /* adding suffix RDN to the self key */
+ DBT adddata;
+ /* suffix ID = 0: fake ID to be replaced with the real one when
+ * it's really added. */
+ ID suffixid = TMPID;
+ slapi_ch_free((void **)&elem);
+ elem = _entryrdn_new_rdn_elem(be, suffixid, tmpsrdn, &len);
+ if (NULL == elem) {
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Failed to generate an elem: "
+ "id: %d, rdn: %s\n",
+ suffixid, slapi_rdn_get_rdn(tmpsrdn));
+ goto bail;
+ }
+#ifdef LDAP_DEBUG_ENTRYRDN
+ _entryrdn_dump_rdn_elem(elem);
+#endif
+ memset(&adddata, 0, sizeof(adddata));
+ adddata.ulen = adddata.size = len;
+ adddata.data = (void *)elem;
+ adddata.flags = DB_DBT_USERMEM;
+
+ rc = _entryrdn_put_data(cursor, &key, &adddata, RDN_INDEX_SELF);
+ slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Suffix %s added: %d\n",
+ slapi_rdn_get_rdn(tmpsrdn), rc);
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Suffix \"%s\" not found: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ goto bail;
+ }
}
+ slapi_rdn_free(&tmpsrdn);
+
/* workid: ID of suffix */
workid = id_stored_to_internal(elem->rdn_elem_id);
parentelem = elem;
@@ -2185,7 +2433,7 @@ retry_get0:
rc = cursor->c_del(cursor, 0);
if (rc && DB_NOTFOUND != rc) {
slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
- "_entryrdn_del_data: Deleting %s failed; "
+ "_entryrdn_delete_key: Deleting %s failed; "
"%s(%d)\n", (char *)key.data,
dblayer_strerror(rc), rc);
goto bail;
@@ -2200,7 +2448,7 @@ retry_get0:
rc = cursor->c_del(cursor, 0);
if (rc && DB_NOTFOUND != rc) {
slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
- "_entryrdn_del_data: Deleting %s failed; "
+ "_entryrdn_delete_key: Deleting %s failed; "
"%s(%d)\n", (char *)key.data,
dblayer_strerror(rc), rc);
goto bail;
@@ -2216,7 +2464,7 @@ retry_get0:
rc = cursor->c_del(cursor, 0);
if (rc && DB_NOTFOUND != rc) {
slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
- "_entryrdn_del_data: Deleting %s failed; "
+ "_entryrdn_delete_key: Deleting %s failed; "
"%s(%d)\n", (char *)key.data,
dblayer_strerror(rc), rc);
goto bail;