From 09c1b9cbe5175636bcf4b606edfd0022bd9cfd6b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 31 Dec 2004 03:51:42 +0000 Subject: r4427: - added ldb_msg_*() functions for sorting, comparing and copying messages - added a ldb_msg_canonicalize() function that fixes a record to not have any duplicate elements - changed ldbedit to use ldb_msg_canonicalize(). This fixes a bug when you rename multiple elements in a record in one edit (This used to be commit f006e724400843419c8b6155cbeae1876983855e) --- source4/lib/ldb/common/ldb_msg.c | 134 +++++++++++++++++++++++++++++++++++++++ source4/lib/ldb/include/ldb.h | 12 ++++ source4/lib/ldb/tools/ldbedit.c | 7 ++ 3 files changed, 153 insertions(+) (limited to 'source4/lib') diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index 18859c86dd..3865e7afa9 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -227,6 +227,16 @@ int ldb_msg_element_compare(struct ldb_message_element *el1, return 0; } +/* + compare two ldb_message_element structures + comparing by element name +*/ +int ldb_msg_element_compare_name(struct ldb_message_element *el1, + struct ldb_message_element *el2) +{ + return ldb_attr_cmp(el1->name, el2->name); +} + /* convenience functions to return common types from a message these return the first value if the attribute is multi-valued @@ -305,3 +315,127 @@ const char *ldb_msg_find_string(const struct ldb_message *msg, } return v->data; } + + +/* + sort the elements of a message by name +*/ +void ldb_msg_sort_elements(struct ldb_message *msg) +{ + qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), + (comparison_fn_t)ldb_msg_element_compare_name); +} + + +/* + free a message created using ldb_msg_copy +*/ +void ldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg) +{ + int i, j; + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + for (j=0;jnum_values;j++) { + ldb_free(ldb, el->values[j].data); + } + if (el->values) ldb_free(ldb, el->values); + ldb_free(ldb, el->name); + } + if (msg->elements) ldb_free(ldb, msg->elements); + ldb_free(ldb, msg->dn); + ldb_free(ldb, msg); +} + +/* + copy a message, allocating new memory for all parts +*/ +struct ldb_message *ldb_msg_copy(struct ldb_context *ldb, + const struct ldb_message *msg) +{ + struct ldb_message *msg2; + int i, j; + + msg2 = ldb_malloc_p(ldb, struct ldb_message); + if (msg2 == NULL) return NULL; + + msg2->elements = NULL; + msg2->num_elements = 0; + msg2->private_data = NULL; + + msg2->dn = ldb_strdup(ldb, msg->dn); + if (msg2->dn == NULL) goto failed; + + msg2->elements = ldb_malloc_array_p(ldb, struct ldb_message_element, msg->num_elements); + if (msg2->elements == NULL) goto failed; + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el1 = &msg->elements[i]; + struct ldb_message_element *el2 = &msg2->elements[i]; + + el2->flags = el1->flags; + el2->num_values = 0; + el2->values = NULL; + el2->name = ldb_strdup(ldb, el1->name); + if (el2->name == NULL) goto failed; + el2->values = ldb_malloc_array_p(ldb, struct ldb_val, el1->num_values); + for (j=0;jnum_values;j++) { + el2->values[j] = ldb_val_dup(ldb, &el1->values[j]); + if (el2->values[j].data == NULL && + el1->values[j].length != 0) { + goto failed; + } + el2->num_values++; + } + + msg2->num_elements++; + } + + return msg2; + +failed: + ldb_msg_free(ldb, msg2); + return NULL; +} + + +/* + canonicalise a message, merging elements of the same name +*/ +struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, + const struct ldb_message *msg) +{ + int i; + struct ldb_message *msg2; + + msg2 = ldb_msg_copy(ldb, msg); + if (msg2 == NULL) return NULL; + + ldb_msg_sort_elements(msg2); + + for (i=1;inum_elements;i++) { + struct ldb_message_element *el1 = &msg2->elements[i-1]; + struct ldb_message_element *el2 = &msg2->elements[i]; + if (ldb_msg_element_compare_name(el1, el2) == 0) { + el1->values = ldb_realloc_p(ldb, el1->values, struct ldb_val, + el1->num_values + el2->num_values); + if (el1->values == NULL) { + return NULL; + } + memcpy(el1->values + el1->num_values, + el2->values, + sizeof(struct ldb_val) * el2->num_values); + el1->num_values += el2->num_values; + ldb_free(ldb, el2->name); + ldb_free(ldb, el2->values); + if (i+1num_elements) { + memmove(el2, el2+1, sizeof(struct ldb_message_element) * + (msg2->num_elements - (i+1))); + } + msg2->num_elements--; + i--; + } + } + + return msg2; +} diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 03d0cc7a3b..9dff510417 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -293,6 +293,18 @@ double ldb_msg_find_double(const struct ldb_message *msg, const char *ldb_msg_find_string(const struct ldb_message *msg, const char *attr_name, const char *default_value); + +void ldb_msg_sort_elements(struct ldb_message *msg); + +void ldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg); + +struct ldb_message *ldb_msg_copy(struct ldb_context *ldb, + const struct ldb_message *msg); + +struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, + const struct ldb_message *msg); + + struct ldb_val ldb_val_dup(struct ldb_context *ldb, const struct ldb_val *v); diff --git a/source4/lib/ldb/tools/ldbedit.c b/source4/lib/ldb/tools/ldbedit.c index f84d05440f..6cd6ef041b 100644 --- a/source4/lib/ldb/tools/ldbedit.c +++ b/source4/lib/ldb/tools/ldbedit.c @@ -69,6 +69,12 @@ static int modify_record(struct ldb_context *ldb, mod.num_elements = 0; mod.elements = NULL; + msg2 = ldb_msg_canonicalize(ldb, msg2); + if (msg2 == NULL) { + fprintf(stderr, "Failed to canonicalise msg2\n"); + return -1; + } + /* look in msg2 to find elements that need to be added or modified */ for (i=0;inum_elements;i++) { @@ -295,6 +301,7 @@ static void usage(void) printf(" -b basedn choose baseDN\n"); printf(" -a edit all records (expression 'objectclass=*')\n"); printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n"); + printf(" -v verbose mode)\n"); exit(1); } -- cgit