Blame SOURCES/021-xml-comments.patch

60de42
From c509cd07008b1f9b3402eeb7d7f3f6d504aa4fdb Mon Sep 17 00:00:00 2001
60de42
From: "Gao,Yan" <ygao@suse.com>
60de42
Date: Fri, 10 Feb 2017 15:44:16 +0100
60de42
Subject: [PATCH 1/2] Fix: libcrmcommon: Correctly compare XML comments to
60de42
 prevent crmd from getting into infinite election loop
60de42
60de42
With b7fa323, crmd could still get into an infinite election loop when
60de42
there was more than one comment with the exactly same text at the same
60de42
level within a CIB XML element. For example:
60de42
60de42
'''
60de42
  
60de42
  
60de42
  
60de42
  
60de42
  
60de42
  
60de42
  
60de42
  
60de42
'''
60de42
60de42
Basically, it'd produce big messes if using the diff operation "move"
60de42
for XML comments in such a case.
60de42
60de42
With this commit, it strictly tries to match the XML comments at the
60de42
exactly same offsets when comparing v2 patchset, so that only the diff
60de42
operations "create" and "delete" will be used for XML comments.
60de42
---
60de42
 lib/common/xml.c | 46 ++++++++++++++++++++++++++++++++--------------
60de42
 1 file changed, 32 insertions(+), 14 deletions(-)
60de42
60de42
diff --git a/lib/common/xml.c b/lib/common/xml.c
60de42
index 65237c8..fd80fe1 100644
60de42
--- a/lib/common/xml.c
60de42
+++ b/lib/common/xml.c
60de42
@@ -98,7 +98,7 @@ static filter_t filter[] = {
60de42
 /* *INDENT-ON* */
60de42
 
60de42
 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
60de42
-static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment);
60de42
+static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
60de42
 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
60de42
 static bool __xml_acl_check(xmlNode *xml, const char *name, enum xml_private_flags mode);
60de42
 const char *__xml_acl_to_text(enum xml_private_flags flags);
60de42
@@ -1555,11 +1555,11 @@ xml_accept_changes(xmlNode * xml)
60de42
 }
60de42
 
60de42
 static xmlNode *
60de42
-find_element(xmlNode *haystack, xmlNode *needle)
60de42
+find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
60de42
 {
60de42
     CRM_CHECK(needle != NULL, return NULL);
60de42
     return (needle->type == XML_COMMENT_NODE)?
60de42
-           find_xml_comment(haystack, needle)
60de42
+           find_xml_comment(haystack, needle, exact)
60de42
            : find_entity(haystack, crm_element_name(needle), ID(needle));
60de42
 }
60de42
 
60de42
@@ -1615,7 +1615,7 @@ __subtract_xml_object(xmlNode * target, xmlNode * patch)
60de42
         xmlNode *target_child = cIter;
60de42
 
60de42
         cIter = __xml_next(cIter);
60de42
-        patch_child = find_element(patch, target_child);
60de42
+        patch_child = find_element(patch, target_child, FALSE);
60de42
         __subtract_xml_object(target_child, patch_child);
60de42
     }
60de42
     free(id);
60de42
@@ -1677,7 +1677,7 @@ __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
60de42
     for (patch_child = __xml_first_child(patch); patch_child != NULL;
60de42
          patch_child = __xml_next(patch_child)) {
60de42
 
60de42
-        target_child = find_element(target, patch_child);
60de42
+        target_child = find_element(target, patch_child, FALSE);
60de42
         __add_xml_object(target, target_child, patch_child);
60de42
     }
60de42
 }
60de42
@@ -4026,7 +4026,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
60de42
 
60de42
     for (cIter = __xml_first_child(old); cIter != NULL; ) {
60de42
         xmlNode *old_child = cIter;
60de42
-        xmlNode *new_child = find_element(new, cIter);
60de42
+        xmlNode *new_child = find_element(new, cIter, TRUE);
60de42
 
60de42
         cIter = __xml_next(cIter);
60de42
         if(new_child) {
60de42
@@ -4041,7 +4041,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
60de42
             __xml_acl_apply(top); /* Make sure any ACLs are applied to 'candidate' */
60de42
             free_xml(candidate);
60de42
 
60de42
-            if (find_element(new, old_child) == NULL) {
60de42
+            if (find_element(new, old_child, TRUE) == NULL) {
60de42
                 xml_private_t *p = old_child->_private;
60de42
 
60de42
                 p->flags |= xpf_skip;
60de42
@@ -4051,7 +4051,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
60de42
 
60de42
     for (cIter = __xml_first_child(new); cIter != NULL; ) {
60de42
         xmlNode *new_child = cIter;
60de42
-        xmlNode *old_child = find_element(old, cIter);
60de42
+        xmlNode *old_child = find_element(old, cIter, TRUE);
60de42
 
60de42
         cIter = __xml_next(cIter);
60de42
         if(old_child == NULL) {
60de42
@@ -4226,18 +4226,36 @@ in_upper_context(int depth, int context, xmlNode * xml_node)
60de42
 }
60de42
 
60de42
 static xmlNode *
60de42
-find_xml_comment(xmlNode * root, xmlNode * search_comment)
60de42
+find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
60de42
 {
60de42
     xmlNode *a_child = NULL;
60de42
+    int search_offset = __xml_offset(search_comment);
60de42
 
60de42
     CRM_CHECK(search_comment->type == XML_COMMENT_NODE, return NULL);
60de42
 
60de42
     for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
60de42
-        if (a_child->type != XML_COMMENT_NODE) {
60de42
-            continue;
60de42
+        if (exact) {
60de42
+            int offset = __xml_offset(a_child);
60de42
+            xml_private_t *p = a_child->_private;
60de42
+
60de42
+            if (offset < search_offset) {
60de42
+                continue;
60de42
+
60de42
+            } else if (offset > search_offset) {
60de42
+                return NULL;
60de42
+            }
60de42
+
60de42
+            if (is_set(p->flags, xpf_skip)) {
60de42
+                continue;
60de42
+            }
60de42
         }
60de42
-        if (safe_str_eq((const char *)a_child->content, (const char *)search_comment->content)) {
60de42
+
60de42
+        if (a_child->type == XML_COMMENT_NODE
60de42
+            && safe_str_eq((const char *)a_child->content, (const char *)search_comment->content)) {
60de42
             return a_child;
60de42
+
60de42
+        } else if (exact) {
60de42
+            return NULL;
60de42
         }
60de42
     }
60de42
 
60de42
@@ -4332,7 +4350,7 @@ subtract_xml_object(xmlNode * parent, xmlNode * left, xmlNode * right,
60de42
          left_child = __xml_next(left_child)) {
60de42
         gboolean child_changed = FALSE;
60de42
 
60de42
-        right_child = find_element(right, left_child);
60de42
+        right_child = find_element(right, left_child, FALSE);
60de42
         subtract_xml_object(diff, left_child, right_child, full, &child_changed, marker);
60de42
         if (child_changed) {
60de42
             *changed = TRUE;
60de42
@@ -4458,7 +4476,7 @@ add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
60de42
     CRM_CHECK(update->type == XML_COMMENT_NODE, return 0);
60de42
 
60de42
     if (target == NULL) {
60de42
-        target = find_xml_comment(parent, update);
60de42
+        target = find_xml_comment(parent, update, FALSE);
60de42
     }
60de42
 
60de42
     if (target == NULL) {
60de42
-- 
60de42
1.8.3.1
60de42
60de42
60de42
From 362f02874b6be46bf2648fb45ebc6bc636d48965 Mon Sep 17 00:00:00 2001
60de42
From: "Gao,Yan" <ygao@suse.com>
60de42
Date: Mon, 13 Feb 2017 17:47:23 +0100
60de42
Subject: [PATCH 2/2] Fix: libcrmcommon: Correctly delete XML comments
60de42
 according to their positions
60de42
60de42
Previously, v2 patchset was not able to define which exact XML comments were
60de42
expected to be deleted in a CIB XML element. It was a problem if there
60de42
was more than one comment at the same level within a CIB XML element.
60de42
60de42
This commit resolves it by adding and handling a "position" field in the
60de42
diff operation "delete" for XML comments.
60de42
---
60de42
 lib/common/xml.c | 121 +++++++++++++++++++++++++++++++++++++++++++++----------
60de42
 1 file changed, 100 insertions(+), 21 deletions(-)
60de42
60de42
diff --git a/lib/common/xml.c b/lib/common/xml.c
60de42
index fd80fe1..6dce4cb 100644
60de42
--- a/lib/common/xml.c
60de42
+++ b/lib/common/xml.c
60de42
@@ -78,7 +78,7 @@ typedef struct xml_private_s
60de42
         uint32_t flags;
60de42
         char *user;
60de42
         GListPtr acls;
60de42
-        GListPtr deleted_paths;
60de42
+        GListPtr deleted_objs;
60de42
 } xml_private_t;
60de42
 
60de42
 typedef struct xml_acl_s {
60de42
@@ -86,6 +86,11 @@ typedef struct xml_acl_s {
60de42
         char *xpath;
60de42
 } xml_acl_t;
60de42
 
60de42
+typedef struct xml_deleted_obj_s {
60de42
+        char *path;
60de42
+        int position;
60de42
+} xml_deleted_obj_t;
60de42
+
60de42
 /* *INDENT-OFF* */
60de42
 
60de42
 static filter_t filter[] = {
60de42
@@ -275,6 +280,17 @@ __xml_acl_free(void *data)
60de42
 }
60de42
 
60de42
 static void
60de42
+__xml_deleted_obj_free(void *data)
60de42
+{
60de42
+    if(data) {
60de42
+        xml_deleted_obj_t *deleted_obj = data;
60de42
+
60de42
+        free(deleted_obj->path);
60de42
+        free(deleted_obj);
60de42
+    }
60de42
+}
60de42
+
60de42
+static void
60de42
 __xml_private_clean(xml_private_t *p)
60de42
 {
60de42
     if(p) {
60de42
@@ -288,9 +304,9 @@ __xml_private_clean(xml_private_t *p)
60de42
             p->acls = NULL;
60de42
         }
60de42
 
60de42
-        if(p->deleted_paths) {
60de42
-            g_list_free_full(p->deleted_paths, free);
60de42
-            p->deleted_paths = NULL;
60de42
+        if(p->deleted_objs) {
60de42
+            g_list_free_full(p->deleted_objs, __xml_deleted_obj_free);
60de42
+            p->deleted_objs = NULL;
60de42
         }
60de42
     }
60de42
 }
60de42
@@ -1094,10 +1110,10 @@ is_config_change(xmlNode *xml)
60de42
 
60de42
     if(xml->doc && xml->doc->_private) {
60de42
         p = xml->doc->_private;
60de42
-        for(gIter = p->deleted_paths; gIter; gIter = gIter->next) {
60de42
-            char *path = gIter->data;
60de42
+        for(gIter = p->deleted_objs; gIter; gIter = gIter->next) {
60de42
+            xml_deleted_obj_t *deleted_obj = gIter->data;
60de42
 
60de42
-            if(strstr(path, "/"XML_TAG_CIB"/"XML_CIB_TAG_CONFIGURATION) != NULL) {
60de42
+            if(strstr(deleted_obj->path, "/"XML_TAG_CIB"/"XML_CIB_TAG_CONFIGURATION) != NULL) {
60de42
                 return TRUE;
60de42
             }
60de42
         }
60de42
@@ -1241,11 +1257,15 @@ xml_create_patchset_v2(xmlNode *source, xmlNode *target)
60de42
         crm_xml_add(v, vfields[lpc], value);
60de42
     }
60de42
 
60de42
-    for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
60de42
+    for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
60de42
+        xml_deleted_obj_t *deleted_obj = gIter->data;
60de42
         xmlNode *change = create_xml_node(patchset, XML_DIFF_CHANGE);
60de42
 
60de42
         crm_xml_add(change, XML_DIFF_OP, "delete");
60de42
-        crm_xml_add(change, XML_DIFF_PATH, gIter->data);
60de42
+        crm_xml_add(change, XML_DIFF_PATH, deleted_obj->path);
60de42
+        if (deleted_obj->position >= 0) {
60de42
+            crm_xml_add_int(change, XML_DIFF_POSITION, deleted_obj->position);
60de42
+        }
60de42
     }
60de42
 
60de42
     __xml_build_changes(target, patchset);
60de42
@@ -1473,7 +1493,15 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset)
60de42
                 }
60de42
 
60de42
             } else if(strcmp(op, "delete") == 0) {
60de42
-                do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", xpath);
60de42
+                int position = -1;
60de42
+
60de42
+                crm_element_value_int(change, XML_DIFF_POSITION, &position);
60de42
+                if (position >= 0) {
60de42
+                    do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)", xpath, position);
60de42
+
60de42
+                } else {
60de42
+                    do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", xpath);
60de42
+                }
60de42
             }
60de42
         }
60de42
         return;
60de42
@@ -1521,8 +1549,17 @@ xml_log_changes(uint8_t log_level, const char *function, xmlNode * xml)
60de42
         return;
60de42
     }
60de42
 
60de42
-    for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
60de42
-        do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", (char*)gIter->data);
60de42
+    for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
60de42
+        xml_deleted_obj_t *deleted_obj = gIter->data;
60de42
+
60de42
+        if (deleted_obj->position >= 0) {
60de42
+            do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)",
60de42
+                             deleted_obj->path, deleted_obj->position);
60de42
+
60de42
+        } else {
60de42
+            do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s",
60de42
+                             deleted_obj->path);
60de42
+        }
60de42
     }
60de42
 
60de42
     log_data_element(log_level, __FILE__, function, __LINE__, "+ ", xml, 0,
60de42
@@ -1881,7 +1918,7 @@ xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset, bool check_version)
60de42
 }
60de42
 
60de42
 static xmlNode *
60de42
-__first_xml_child_match(xmlNode *parent, const char *name, const char *id)
60de42
+__first_xml_child_match(xmlNode *parent, const char *name, const char *id, int position)
60de42
 {
60de42
     xmlNode *cIter = NULL;
60de42
 
60de42
@@ -1894,13 +1931,21 @@ __first_xml_child_match(xmlNode *parent, const char *name, const char *id)
60de42
                 continue;
60de42
             }
60de42
         }
60de42
+
60de42
+        /* The "position" makes sense only for XML comments for now */
60de42
+        if (cIter->type == XML_COMMENT_NODE
60de42
+            && position >= 0
60de42
+            && __xml_offset(cIter) != position) {
60de42
+            continue;
60de42
+        }
60de42
+
60de42
         return cIter;
60de42
     }
60de42
     return NULL;
60de42
 }
60de42
 
60de42
 static xmlNode *
60de42
-__xml_find_path(xmlNode *top, const char *key)
60de42
+__xml_find_path(xmlNode *top, const char *key, int target_position)
60de42
 {
60de42
     xmlNode *target = (xmlNode*)top->doc;
60de42
     char *id = malloc(XML_BUFFER_SIZE);
60de42
@@ -1923,13 +1968,19 @@ __xml_find_path(xmlNode *top, const char *key)
60de42
 
60de42
         } else if(tag && section) {
60de42
             int f = sscanf (section, "%[^[][@id='%[^']", tag, id);
60de42
+            int current_position = -1;
60de42
+
60de42
+            /* The "target_position" is for the target tag */
60de42
+            if (rc == 1 && target_position >= 0) {
60de42
+                current_position = target_position;
60de42
+            }
60de42
 
60de42
             switch(f) {
60de42
                 case 1:
60de42
-                    target = __first_xml_child_match(target, tag, NULL);
60de42
+                    target = __first_xml_child_match(target, tag, NULL, current_position);
60de42
                     break;
60de42
                 case 2:
60de42
-                    target = __first_xml_child_match(target, tag, id);
60de42
+                    target = __first_xml_child_match(target, tag, id, current_position);
60de42
                     break;
60de42
                 default:
60de42
                     crm_trace("Aborting on %s", section);
60de42
@@ -1975,16 +2026,20 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset, bool check_version)
60de42
         xmlNode *match = NULL;
60de42
         const char *op = crm_element_value(change, XML_DIFF_OP);
60de42
         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
60de42
+        int position = -1;
60de42
 
60de42
         crm_trace("Processing %s %s", change->name, op);
60de42
         if(op == NULL) {
60de42
             continue;
60de42
         }
60de42
 
60de42
+        if(strcmp(op, "delete") == 0) {
60de42
+            crm_element_value_int(change, XML_DIFF_POSITION, &position);
60de42
+        }
60de42
 #if 0
60de42
         match = get_xpath_object(xpath, xml, LOG_TRACE);
60de42
 #else
60de42
-        match = __xml_find_path(xml, xpath);
60de42
+        match = __xml_find_path(xml, xpath, position);
60de42
 #endif
60de42
         crm_trace("Performing %s on %s with %p", op, xpath, match);
60de42
 
60de42
@@ -2583,8 +2638,8 @@ xml_get_path(xmlNode *xml)
60de42
     return NULL;
60de42
 }
60de42
 
60de42
-void
60de42
-free_xml(xmlNode * child)
60de42
+static void
60de42
+free_xml_with_position(xmlNode * child, int position)
60de42
 {
60de42
     if (child != NULL) {
60de42
         xmlNode *top = NULL;
60de42
@@ -2613,9 +2668,25 @@ free_xml(xmlNode * child)
60de42
                 char buffer[XML_BUFFER_SIZE];
60de42
 
60de42
                 if(__get_prefix(NULL, child, buffer, offset) > 0) {
60de42
+                    xml_deleted_obj_t *deleted_obj = calloc(1, sizeof(xml_deleted_obj_t));
60de42
+
60de42
                     crm_trace("Deleting %s %p from %p", buffer, child, doc);
60de42
+
60de42
+                    deleted_obj->path = strdup(buffer);
60de42
+
60de42
+                    deleted_obj->position = -1;
60de42
+                    /* Record the "position" only for XML comments for now */
60de42
+                    if (child->type == XML_COMMENT_NODE) {
60de42
+                        if (position >= 0) {
60de42
+                            deleted_obj->position = position;
60de42
+
60de42
+                        } else {
60de42
+                            deleted_obj->position = __xml_offset(child);
60de42
+                        }
60de42
+                    }
60de42
+
60de42
                     p = doc->_private;
60de42
-                    p->deleted_paths = g_list_append(p->deleted_paths, strdup(buffer));
60de42
+                    p->deleted_objs = g_list_append(p->deleted_objs, deleted_obj);
60de42
                     set_doc_flag(child, xpf_dirty);
60de42
                 }
60de42
             }
60de42
@@ -2629,6 +2700,13 @@ free_xml(xmlNode * child)
60de42
     }
60de42
 }
60de42
 
60de42
+
60de42
+void
60de42
+free_xml(xmlNode * child)
60de42
+{
60de42
+    free_xml_with_position(child, -1);
60de42
+}
60de42
+
60de42
 xmlNode *
60de42
 copy_xml(xmlNode * src)
60de42
 {
60de42
@@ -4039,7 +4117,8 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
60de42
 
60de42
             __xml_node_clean(candidate);
60de42
             __xml_acl_apply(top); /* Make sure any ACLs are applied to 'candidate' */
60de42
-            free_xml(candidate);
60de42
+            /* Record the old position */
60de42
+            free_xml_with_position(candidate, __xml_offset(old_child));
60de42
 
60de42
             if (find_element(new, old_child, TRUE) == NULL) {
60de42
                 xml_private_t *p = old_child->_private;
60de42
-- 
60de42
1.8.3.1
60de42