>From 96bf2632392d9656152b75123fa708681ecbc986 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sat, 26 Jan 2013 23:42:10 -0800 Subject: [PATCH 2/4] dsdb-schema: make deduplication of class and schema possible When a class or an attribute is replicated it might already exists in the existing schema, so while replicating the new version of this object we want to get rid of the old version of the object is the current validating schema so that we don't end up having duplicates. Signed-off-by: Matthieu Patou --- source4/dsdb/schema/schema.h | 5 ++++ source4/dsdb/schema/schema_init.c | 60 +++++++++++++++++++++++++++++++++---- source4/dsdb/schema/schema_set.c | 53 ++++++++++++++++++++++++++++---- 3 files changed, 108 insertions(+), 10 deletions(-) diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index 66df1c5..538b858 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -221,6 +221,11 @@ struct dsdb_schema { struct dsdb_attribute *attributes; struct dsdb_class *classes; + struct dsdb_attribute **attributes_to_remove; + uint32_t attributes_to_remove_size; + struct dsdb_class **classes_to_remove; + uint32_t classes_to_remove_size; + /* lists of classes sorted by various attributes, for faster access */ uint32_t num_classes; diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 752d4f5..47c180b 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -699,9 +699,10 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema, return WERR_OK; } -WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb, - struct dsdb_schema *schema, - struct ldb_message *msg) +WERROR dsdb_set_attribute_from_ldb_dups(struct ldb_context *ldb, + struct dsdb_schema *schema, + struct ldb_message *msg, + bool checkdups) { WERROR status; struct dsdb_attribute *attr = talloc_zero(schema, struct dsdb_attribute); @@ -729,12 +730,39 @@ WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb, return WERR_DS_ATT_SCHEMA_REQ_SYNTAX; } + if (checkdups) { + const struct dsdb_attribute* att2 = dsdb_attribute_by_attributeID_id(schema, + attr->attributeID_id); + + if (att2) { + struct dsdb_attributes** a; + uint32_t v = ++(schema->attributes_to_remove_size); + a = talloc_realloc(schema, schema->attributes_to_remove, + struct dsdb_attributes*, + schema->attributes_to_remove_size); + if (!a) { + return WERR_NOMEM; + } + /* Mark the old attribute as to be removed */ + a[v - 1] = (struct dsdb_attribute*) discard_const(att2); + schema->attributes_to_remove = a; + } + } + DLIST_ADD(schema->attributes, attr); return WERR_OK; } -WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema, - struct ldb_message *msg) +WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb, + struct dsdb_schema *schema, + struct ldb_message *msg) +{ + return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, false); +} + +WERROR dsdb_set_class_from_ldb_dups(struct dsdb_schema *schema, + struct ldb_message *msg, + bool checkdups) { WERROR status; struct dsdb_class *obj = talloc_zero(schema, struct dsdb_class); @@ -792,10 +820,32 @@ WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema, GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false); GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false); + if (checkdups) { + const struct dsdb_class* c = dsdb_class_by_governsID_id(schema, obj->governsID_id); + if (c) { + struct dsdb_class** nc; + uint32_t v = ++(schema->classes_to_remove_size); + nc = talloc_realloc(schema, schema->classes_to_remove, + struct dsdb_classes*, + schema->classes_to_remove_size); + if (!nc) { + return WERR_NOMEM; + } + /* Mark the old class to be removed */ + nc[v - 1] = (struct dsdb_class*) discard_const(c); + schema->classes_to_remove = nc; + } + } DLIST_ADD(schema->classes, obj); return WERR_OK; } +WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema, + struct ldb_message *msg) +{ + return dsdb_set_class_from_ldb_dups(schema, msg, false); +} + #define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__) /* diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index 31862a4..05711b3 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -329,6 +329,26 @@ int dsdb_setup_sorted_accessors(struct ldb_context *ldb, unsigned int num_int_id; int ret; + for (i=0; i < schema->classes_to_remove_size; i++) { + DLIST_REMOVE(schema->classes, schema->classes_to_remove[i]); + talloc_free(schema->classes_to_remove[i]); + } + for (i=0; i < schema->attributes_to_remove_size; i++) { + DLIST_REMOVE(schema->attributes, schema->attributes_to_remove[i]); + talloc_free(schema->attributes_to_remove[i]); + } + } + + if (schema->attributes_to_remove) { + talloc_free(schema->attributes_to_remove); + schema->attributes_to_remove = NULL; + } + + if (schema->classes_to_remove) { + talloc_free(schema->classes_to_remove); + schema->classes_to_remove = NULL; + } + /* free all caches */ dsdb_sorted_accessors_free(schema); @@ -669,10 +689,26 @@ int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *sc } /** - * Add an element to the schema (attribute or class) from an LDB message + * @brief Add a new element to the schema and checks if it's a duplicate + * + * This function will add a new element to the schema and checks for existing + * duplicates. + * + * @param[in] ldb A pointer to an LDB context + * + * @param[in] schema A pointer to the dsdb_schema where the element + * will be added. + * + * @param[in] msg The ldb_message object representing the element + * to add. + * + * @param[in] checkdups A boolean to indicate if checks for duplicates + * should be done. + * + * @return A WERROR code */ -WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema, - struct ldb_message *msg) +WERROR dsdb_schema_set_el_from_ldb_msg_dups(struct ldb_context *ldb, struct dsdb_schema *schema, + struct ldb_message *msg, bool checkdups) { const char* tstring; time_t ts; @@ -686,15 +722,22 @@ WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_sche } if (samdb_find_attribute(ldb, msg, "objectclass", "attributeSchema") != NULL) { - return dsdb_set_attribute_from_ldb(ldb, schema, msg); + + return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, checkdups); } else if (samdb_find_attribute(ldb, msg, "objectclass", "classSchema") != NULL) { - return dsdb_set_class_from_ldb(schema, msg); + return dsdb_set_class_from_ldb_dups(schema, msg, checkdups); } /* Don't fail on things not classes or attributes */ return WERR_OK; } +WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema, + struct ldb_message *msg) +{ + return dsdb_schema_set_el_from_ldb_msg_dups(ldb, schema, msg, false); +} + /** * Rather than read a schema from the LDB itself, read it from an ldif * file. This allows schema to be loaded and used while adding the -- 1.7.9.5