Skip to content

Commit ea6fb27

Browse files
authored
Merge pull request #1225 from gao-yan/handle-xml-comment
Correctly handle xml comments
2 parents 2b821c5 + 362f028 commit ea6fb27

File tree

1 file changed

+132
-35
lines changed

1 file changed

+132
-35
lines changed

lib/common/xml.c

Lines changed: 132 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,19 @@ typedef struct xml_private_s
7878
uint32_t flags;
7979
char *user;
8080
GListPtr acls;
81-
GListPtr deleted_paths;
81+
GListPtr deleted_objs;
8282
} xml_private_t;
8383

8484
typedef struct xml_acl_s {
8585
enum xml_private_flags mode;
8686
char *xpath;
8787
} xml_acl_t;
8888

89+
typedef struct xml_deleted_obj_s {
90+
char *path;
91+
int position;
92+
} xml_deleted_obj_t;
93+
8994
/* *INDENT-OFF* */
9095

9196
static filter_t filter[] = {
@@ -98,7 +103,7 @@ static filter_t filter[] = {
98103
/* *INDENT-ON* */
99104

100105
static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
101-
static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment);
106+
static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
102107
static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
103108
static bool __xml_acl_check(xmlNode *xml, const char *name, enum xml_private_flags mode);
104109
const char *__xml_acl_to_text(enum xml_private_flags flags);
@@ -274,6 +279,17 @@ __xml_acl_free(void *data)
274279
}
275280
}
276281

282+
static void
283+
__xml_deleted_obj_free(void *data)
284+
{
285+
if(data) {
286+
xml_deleted_obj_t *deleted_obj = data;
287+
288+
free(deleted_obj->path);
289+
free(deleted_obj);
290+
}
291+
}
292+
277293
static void
278294
__xml_private_clean(xml_private_t *p)
279295
{
@@ -288,9 +304,9 @@ __xml_private_clean(xml_private_t *p)
288304
p->acls = NULL;
289305
}
290306

291-
if(p->deleted_paths) {
292-
g_list_free_full(p->deleted_paths, free);
293-
p->deleted_paths = NULL;
307+
if(p->deleted_objs) {
308+
g_list_free_full(p->deleted_objs, __xml_deleted_obj_free);
309+
p->deleted_objs = NULL;
294310
}
295311
}
296312
}
@@ -1094,10 +1110,10 @@ is_config_change(xmlNode *xml)
10941110

10951111
if(xml->doc && xml->doc->_private) {
10961112
p = xml->doc->_private;
1097-
for(gIter = p->deleted_paths; gIter; gIter = gIter->next) {
1098-
char *path = gIter->data;
1113+
for(gIter = p->deleted_objs; gIter; gIter = gIter->next) {
1114+
xml_deleted_obj_t *deleted_obj = gIter->data;
10991115

1100-
if(strstr(path, "/"XML_TAG_CIB"/"XML_CIB_TAG_CONFIGURATION) != NULL) {
1116+
if(strstr(deleted_obj->path, "/"XML_TAG_CIB"/"XML_CIB_TAG_CONFIGURATION) != NULL) {
11011117
return TRUE;
11021118
}
11031119
}
@@ -1241,11 +1257,15 @@ xml_create_patchset_v2(xmlNode *source, xmlNode *target)
12411257
crm_xml_add(v, vfields[lpc], value);
12421258
}
12431259

1244-
for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
1260+
for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
1261+
xml_deleted_obj_t *deleted_obj = gIter->data;
12451262
xmlNode *change = create_xml_node(patchset, XML_DIFF_CHANGE);
12461263

12471264
crm_xml_add(change, XML_DIFF_OP, "delete");
1248-
crm_xml_add(change, XML_DIFF_PATH, gIter->data);
1265+
crm_xml_add(change, XML_DIFF_PATH, deleted_obj->path);
1266+
if (deleted_obj->position >= 0) {
1267+
crm_xml_add_int(change, XML_DIFF_POSITION, deleted_obj->position);
1268+
}
12491269
}
12501270

12511271
__xml_build_changes(target, patchset);
@@ -1473,7 +1493,15 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset)
14731493
}
14741494

14751495
} else if(strcmp(op, "delete") == 0) {
1476-
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", xpath);
1496+
int position = -1;
1497+
1498+
crm_element_value_int(change, XML_DIFF_POSITION, &position);
1499+
if (position >= 0) {
1500+
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)", xpath, position);
1501+
1502+
} else {
1503+
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", xpath);
1504+
}
14771505
}
14781506
}
14791507
return;
@@ -1521,8 +1549,17 @@ xml_log_changes(uint8_t log_level, const char *function, xmlNode * xml)
15211549
return;
15221550
}
15231551

1524-
for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
1525-
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", (char*)gIter->data);
1552+
for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
1553+
xml_deleted_obj_t *deleted_obj = gIter->data;
1554+
1555+
if (deleted_obj->position >= 0) {
1556+
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)",
1557+
deleted_obj->path, deleted_obj->position);
1558+
1559+
} else {
1560+
do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s",
1561+
deleted_obj->path);
1562+
}
15261563
}
15271564

15281565
log_data_element(log_level, __FILE__, function, __LINE__, "+ ", xml, 0,
@@ -1555,11 +1592,11 @@ xml_accept_changes(xmlNode * xml)
15551592
}
15561593

15571594
static xmlNode *
1558-
find_element(xmlNode *haystack, xmlNode *needle)
1595+
find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
15591596
{
15601597
CRM_CHECK(needle != NULL, return NULL);
15611598
return (needle->type == XML_COMMENT_NODE)?
1562-
find_xml_comment(haystack, needle)
1599+
find_xml_comment(haystack, needle, exact)
15631600
: find_entity(haystack, crm_element_name(needle), ID(needle));
15641601
}
15651602

@@ -1615,7 +1652,7 @@ __subtract_xml_object(xmlNode * target, xmlNode * patch)
16151652
xmlNode *target_child = cIter;
16161653

16171654
cIter = __xml_next(cIter);
1618-
patch_child = find_element(patch, target_child);
1655+
patch_child = find_element(patch, target_child, FALSE);
16191656
__subtract_xml_object(target_child, patch_child);
16201657
}
16211658
free(id);
@@ -1677,7 +1714,7 @@ __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
16771714
for (patch_child = __xml_first_child(patch); patch_child != NULL;
16781715
patch_child = __xml_next(patch_child)) {
16791716

1680-
target_child = find_element(target, patch_child);
1717+
target_child = find_element(target, patch_child, FALSE);
16811718
__add_xml_object(target, target_child, patch_child);
16821719
}
16831720
}
@@ -1881,7 +1918,7 @@ xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset, bool check_version)
18811918
}
18821919

18831920
static xmlNode *
1884-
__first_xml_child_match(xmlNode *parent, const char *name, const char *id)
1921+
__first_xml_child_match(xmlNode *parent, const char *name, const char *id, int position)
18851922
{
18861923
xmlNode *cIter = NULL;
18871924

@@ -1894,13 +1931,21 @@ __first_xml_child_match(xmlNode *parent, const char *name, const char *id)
18941931
continue;
18951932
}
18961933
}
1934+
1935+
/* The "position" makes sense only for XML comments for now */
1936+
if (cIter->type == XML_COMMENT_NODE
1937+
&& position >= 0
1938+
&& __xml_offset(cIter) != position) {
1939+
continue;
1940+
}
1941+
18971942
return cIter;
18981943
}
18991944
return NULL;
19001945
}
19011946

19021947
static xmlNode *
1903-
__xml_find_path(xmlNode *top, const char *key)
1948+
__xml_find_path(xmlNode *top, const char *key, int target_position)
19041949
{
19051950
xmlNode *target = (xmlNode*)top->doc;
19061951
char *id = malloc(XML_BUFFER_SIZE);
@@ -1923,13 +1968,19 @@ __xml_find_path(xmlNode *top, const char *key)
19231968

19241969
} else if(tag && section) {
19251970
int f = sscanf (section, "%[^[][@id='%[^']", tag, id);
1971+
int current_position = -1;
1972+
1973+
/* The "target_position" is for the target tag */
1974+
if (rc == 1 && target_position >= 0) {
1975+
current_position = target_position;
1976+
}
19261977

19271978
switch(f) {
19281979
case 1:
1929-
target = __first_xml_child_match(target, tag, NULL);
1980+
target = __first_xml_child_match(target, tag, NULL, current_position);
19301981
break;
19311982
case 2:
1932-
target = __first_xml_child_match(target, tag, id);
1983+
target = __first_xml_child_match(target, tag, id, current_position);
19331984
break;
19341985
default:
19351986
crm_trace("Aborting on %s", section);
@@ -1975,16 +2026,20 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset, bool check_version)
19752026
xmlNode *match = NULL;
19762027
const char *op = crm_element_value(change, XML_DIFF_OP);
19772028
const char *xpath = crm_element_value(change, XML_DIFF_PATH);
2029+
int position = -1;
19782030

19792031
crm_trace("Processing %s %s", change->name, op);
19802032
if(op == NULL) {
19812033
continue;
19822034
}
19832035

2036+
if(strcmp(op, "delete") == 0) {
2037+
crm_element_value_int(change, XML_DIFF_POSITION, &position);
2038+
}
19842039
#if 0
19852040
match = get_xpath_object(xpath, xml, LOG_TRACE);
19862041
#else
1987-
match = __xml_find_path(xml, xpath);
2042+
match = __xml_find_path(xml, xpath, position);
19882043
#endif
19892044
crm_trace("Performing %s on %s with %p", op, xpath, match);
19902045

@@ -2583,8 +2638,8 @@ xml_get_path(xmlNode *xml)
25832638
return NULL;
25842639
}
25852640

2586-
void
2587-
free_xml(xmlNode * child)
2641+
static void
2642+
free_xml_with_position(xmlNode * child, int position)
25882643
{
25892644
if (child != NULL) {
25902645
xmlNode *top = NULL;
@@ -2613,9 +2668,25 @@ free_xml(xmlNode * child)
26132668
char buffer[XML_BUFFER_SIZE];
26142669

26152670
if(__get_prefix(NULL, child, buffer, offset) > 0) {
2671+
xml_deleted_obj_t *deleted_obj = calloc(1, sizeof(xml_deleted_obj_t));
2672+
26162673
crm_trace("Deleting %s %p from %p", buffer, child, doc);
2674+
2675+
deleted_obj->path = strdup(buffer);
2676+
2677+
deleted_obj->position = -1;
2678+
/* Record the "position" only for XML comments for now */
2679+
if (child->type == XML_COMMENT_NODE) {
2680+
if (position >= 0) {
2681+
deleted_obj->position = position;
2682+
2683+
} else {
2684+
deleted_obj->position = __xml_offset(child);
2685+
}
2686+
}
2687+
26172688
p = doc->_private;
2618-
p->deleted_paths = g_list_append(p->deleted_paths, strdup(buffer));
2689+
p->deleted_objs = g_list_append(p->deleted_objs, deleted_obj);
26192690
set_doc_flag(child, xpf_dirty);
26202691
}
26212692
}
@@ -2629,6 +2700,13 @@ free_xml(xmlNode * child)
26292700
}
26302701
}
26312702

2703+
2704+
void
2705+
free_xml(xmlNode * child)
2706+
{
2707+
free_xml_with_position(child, -1);
2708+
}
2709+
26322710
xmlNode *
26332711
copy_xml(xmlNode * src)
26342712
{
@@ -4026,7 +4104,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
40264104

40274105
for (cIter = __xml_first_child(old); cIter != NULL; ) {
40284106
xmlNode *old_child = cIter;
4029-
xmlNode *new_child = find_element(new, cIter);
4107+
xmlNode *new_child = find_element(new, cIter, TRUE);
40304108

40314109
cIter = __xml_next(cIter);
40324110
if(new_child) {
@@ -4039,9 +4117,10 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
40394117

40404118
__xml_node_clean(candidate);
40414119
__xml_acl_apply(top); /* Make sure any ACLs are applied to 'candidate' */
4042-
free_xml(candidate);
4120+
/* Record the old position */
4121+
free_xml_with_position(candidate, __xml_offset(old_child));
40434122

4044-
if (find_element(new, old_child) == NULL) {
4123+
if (find_element(new, old_child, TRUE) == NULL) {
40454124
xml_private_t *p = old_child->_private;
40464125

40474126
p->flags |= xpf_skip;
@@ -4051,7 +4130,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
40514130

40524131
for (cIter = __xml_first_child(new); cIter != NULL; ) {
40534132
xmlNode *new_child = cIter;
4054-
xmlNode *old_child = find_element(old, cIter);
4133+
xmlNode *old_child = find_element(old, cIter, TRUE);
40554134

40564135
cIter = __xml_next(cIter);
40574136
if(old_child == NULL) {
@@ -4226,18 +4305,36 @@ in_upper_context(int depth, int context, xmlNode * xml_node)
42264305
}
42274306

42284307
static xmlNode *
4229-
find_xml_comment(xmlNode * root, xmlNode * search_comment)
4308+
find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
42304309
{
42314310
xmlNode *a_child = NULL;
4311+
int search_offset = __xml_offset(search_comment);
42324312

42334313
CRM_CHECK(search_comment->type == XML_COMMENT_NODE, return NULL);
42344314

42354315
for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
4236-
if (a_child->type != XML_COMMENT_NODE) {
4237-
continue;
4316+
if (exact) {
4317+
int offset = __xml_offset(a_child);
4318+
xml_private_t *p = a_child->_private;
4319+
4320+
if (offset < search_offset) {
4321+
continue;
4322+
4323+
} else if (offset > search_offset) {
4324+
return NULL;
4325+
}
4326+
4327+
if (is_set(p->flags, xpf_skip)) {
4328+
continue;
4329+
}
42384330
}
4239-
if (safe_str_eq((const char *)a_child->content, (const char *)search_comment->content)) {
4331+
4332+
if (a_child->type == XML_COMMENT_NODE
4333+
&& safe_str_eq((const char *)a_child->content, (const char *)search_comment->content)) {
42404334
return a_child;
4335+
4336+
} else if (exact) {
4337+
return NULL;
42414338
}
42424339
}
42434340

@@ -4332,7 +4429,7 @@ subtract_xml_object(xmlNode * parent, xmlNode * left, xmlNode * right,
43324429
left_child = __xml_next(left_child)) {
43334430
gboolean child_changed = FALSE;
43344431

4335-
right_child = find_element(right, left_child);
4432+
right_child = find_element(right, left_child, FALSE);
43364433
subtract_xml_object(diff, left_child, right_child, full, &child_changed, marker);
43374434
if (child_changed) {
43384435
*changed = TRUE;
@@ -4458,7 +4555,7 @@ add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
44584555
CRM_CHECK(update->type == XML_COMMENT_NODE, return 0);
44594556

44604557
if (target == NULL) {
4461-
target = find_xml_comment(parent, update);
4558+
target = find_xml_comment(parent, update, FALSE);
44624559
}
44634560

44644561
if (target == NULL) {

0 commit comments

Comments
 (0)