@@ -78,14 +78,19 @@ typedef struct xml_private_s
78
78
uint32_t flags ;
79
79
char * user ;
80
80
GListPtr acls ;
81
- GListPtr deleted_paths ;
81
+ GListPtr deleted_objs ;
82
82
} xml_private_t ;
83
83
84
84
typedef struct xml_acl_s {
85
85
enum xml_private_flags mode ;
86
86
char * xpath ;
87
87
} xml_acl_t ;
88
88
89
+ typedef struct xml_deleted_obj_s {
90
+ char * path ;
91
+ int position ;
92
+ } xml_deleted_obj_t ;
93
+
89
94
/* *INDENT-OFF* */
90
95
91
96
static filter_t filter [] = {
@@ -98,7 +103,7 @@ static filter_t filter[] = {
98
103
/* *INDENT-ON* */
99
104
100
105
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 );
102
107
static int add_xml_comment (xmlNode * parent , xmlNode * target , xmlNode * update );
103
108
static bool __xml_acl_check (xmlNode * xml , const char * name , enum xml_private_flags mode );
104
109
const char * __xml_acl_to_text (enum xml_private_flags flags );
@@ -274,6 +279,17 @@ __xml_acl_free(void *data)
274
279
}
275
280
}
276
281
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
+
277
293
static void
278
294
__xml_private_clean (xml_private_t * p )
279
295
{
@@ -288,9 +304,9 @@ __xml_private_clean(xml_private_t *p)
288
304
p -> acls = NULL ;
289
305
}
290
306
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 ;
294
310
}
295
311
}
296
312
}
@@ -1094,10 +1110,10 @@ is_config_change(xmlNode *xml)
1094
1110
1095
1111
if (xml -> doc && xml -> doc -> _private ) {
1096
1112
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 ;
1099
1115
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 ) {
1101
1117
return TRUE;
1102
1118
}
1103
1119
}
@@ -1241,11 +1257,15 @@ xml_create_patchset_v2(xmlNode *source, xmlNode *target)
1241
1257
crm_xml_add (v , vfields [lpc ], value );
1242
1258
}
1243
1259
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 ;
1245
1262
xmlNode * change = create_xml_node (patchset , XML_DIFF_CHANGE );
1246
1263
1247
1264
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
+ }
1249
1269
}
1250
1270
1251
1271
__xml_build_changes (target , patchset );
@@ -1473,7 +1493,15 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset)
1473
1493
}
1474
1494
1475
1495
} 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
+ }
1477
1505
}
1478
1506
}
1479
1507
return ;
@@ -1521,8 +1549,17 @@ xml_log_changes(uint8_t log_level, const char *function, xmlNode * xml)
1521
1549
return ;
1522
1550
}
1523
1551
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
+ }
1526
1563
}
1527
1564
1528
1565
log_data_element (log_level , __FILE__ , function , __LINE__ , "+ " , xml , 0 ,
@@ -1555,11 +1592,11 @@ xml_accept_changes(xmlNode * xml)
1555
1592
}
1556
1593
1557
1594
static xmlNode *
1558
- find_element (xmlNode * haystack , xmlNode * needle )
1595
+ find_element (xmlNode * haystack , xmlNode * needle , gboolean exact )
1559
1596
{
1560
1597
CRM_CHECK (needle != NULL , return NULL );
1561
1598
return (needle -> type == XML_COMMENT_NODE )?
1562
- find_xml_comment (haystack , needle )
1599
+ find_xml_comment (haystack , needle , exact )
1563
1600
: find_entity (haystack , crm_element_name (needle ), ID (needle ));
1564
1601
}
1565
1602
@@ -1615,7 +1652,7 @@ __subtract_xml_object(xmlNode * target, xmlNode * patch)
1615
1652
xmlNode * target_child = cIter ;
1616
1653
1617
1654
cIter = __xml_next (cIter );
1618
- patch_child = find_element (patch , target_child );
1655
+ patch_child = find_element (patch , target_child , FALSE );
1619
1656
__subtract_xml_object (target_child , patch_child );
1620
1657
}
1621
1658
free (id );
@@ -1677,7 +1714,7 @@ __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
1677
1714
for (patch_child = __xml_first_child (patch ); patch_child != NULL ;
1678
1715
patch_child = __xml_next (patch_child )) {
1679
1716
1680
- target_child = find_element (target , patch_child );
1717
+ target_child = find_element (target , patch_child , FALSE );
1681
1718
__add_xml_object (target , target_child , patch_child );
1682
1719
}
1683
1720
}
@@ -1881,7 +1918,7 @@ xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset, bool check_version)
1881
1918
}
1882
1919
1883
1920
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 )
1885
1922
{
1886
1923
xmlNode * cIter = NULL ;
1887
1924
@@ -1894,13 +1931,21 @@ __first_xml_child_match(xmlNode *parent, const char *name, const char *id)
1894
1931
continue ;
1895
1932
}
1896
1933
}
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
+
1897
1942
return cIter ;
1898
1943
}
1899
1944
return NULL ;
1900
1945
}
1901
1946
1902
1947
static xmlNode *
1903
- __xml_find_path (xmlNode * top , const char * key )
1948
+ __xml_find_path (xmlNode * top , const char * key , int target_position )
1904
1949
{
1905
1950
xmlNode * target = (xmlNode * )top -> doc ;
1906
1951
char * id = malloc (XML_BUFFER_SIZE );
@@ -1923,13 +1968,19 @@ __xml_find_path(xmlNode *top, const char *key)
1923
1968
1924
1969
} else if (tag && section ) {
1925
1970
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
+ }
1926
1977
1927
1978
switch (f ) {
1928
1979
case 1 :
1929
- target = __first_xml_child_match (target , tag , NULL );
1980
+ target = __first_xml_child_match (target , tag , NULL , current_position );
1930
1981
break ;
1931
1982
case 2 :
1932
- target = __first_xml_child_match (target , tag , id );
1983
+ target = __first_xml_child_match (target , tag , id , current_position );
1933
1984
break ;
1934
1985
default :
1935
1986
crm_trace ("Aborting on %s" , section );
@@ -1975,16 +2026,20 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset, bool check_version)
1975
2026
xmlNode * match = NULL ;
1976
2027
const char * op = crm_element_value (change , XML_DIFF_OP );
1977
2028
const char * xpath = crm_element_value (change , XML_DIFF_PATH );
2029
+ int position = -1 ;
1978
2030
1979
2031
crm_trace ("Processing %s %s" , change -> name , op );
1980
2032
if (op == NULL ) {
1981
2033
continue ;
1982
2034
}
1983
2035
2036
+ if (strcmp (op , "delete" ) == 0 ) {
2037
+ crm_element_value_int (change , XML_DIFF_POSITION , & position );
2038
+ }
1984
2039
#if 0
1985
2040
match = get_xpath_object (xpath , xml , LOG_TRACE );
1986
2041
#else
1987
- match = __xml_find_path (xml , xpath );
2042
+ match = __xml_find_path (xml , xpath , position );
1988
2043
#endif
1989
2044
crm_trace ("Performing %s on %s with %p" , op , xpath , match );
1990
2045
@@ -2583,8 +2638,8 @@ xml_get_path(xmlNode *xml)
2583
2638
return NULL ;
2584
2639
}
2585
2640
2586
- void
2587
- free_xml (xmlNode * child )
2641
+ static void
2642
+ free_xml_with_position (xmlNode * child , int position )
2588
2643
{
2589
2644
if (child != NULL ) {
2590
2645
xmlNode * top = NULL ;
@@ -2613,9 +2668,25 @@ free_xml(xmlNode * child)
2613
2668
char buffer [XML_BUFFER_SIZE ];
2614
2669
2615
2670
if (__get_prefix (NULL , child , buffer , offset ) > 0 ) {
2671
+ xml_deleted_obj_t * deleted_obj = calloc (1 , sizeof (xml_deleted_obj_t ));
2672
+
2616
2673
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
+
2617
2688
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 );
2619
2690
set_doc_flag (child , xpf_dirty );
2620
2691
}
2621
2692
}
@@ -2629,6 +2700,13 @@ free_xml(xmlNode * child)
2629
2700
}
2630
2701
}
2631
2702
2703
+
2704
+ void
2705
+ free_xml (xmlNode * child )
2706
+ {
2707
+ free_xml_with_position (child , -1 );
2708
+ }
2709
+
2632
2710
xmlNode *
2633
2711
copy_xml (xmlNode * src )
2634
2712
{
@@ -4026,7 +4104,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
4026
4104
4027
4105
for (cIter = __xml_first_child (old ); cIter != NULL ; ) {
4028
4106
xmlNode * old_child = cIter ;
4029
- xmlNode * new_child = find_element (new , cIter );
4107
+ xmlNode * new_child = find_element (new , cIter , TRUE );
4030
4108
4031
4109
cIter = __xml_next (cIter );
4032
4110
if (new_child ) {
@@ -4039,9 +4117,10 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
4039
4117
4040
4118
__xml_node_clean (candidate );
4041
4119
__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 ));
4043
4122
4044
- if (find_element (new , old_child ) == NULL ) {
4123
+ if (find_element (new , old_child , TRUE ) == NULL ) {
4045
4124
xml_private_t * p = old_child -> _private ;
4046
4125
4047
4126
p -> flags |= xpf_skip ;
@@ -4051,7 +4130,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
4051
4130
4052
4131
for (cIter = __xml_first_child (new ); cIter != NULL ; ) {
4053
4132
xmlNode * new_child = cIter ;
4054
- xmlNode * old_child = find_element (old , cIter );
4133
+ xmlNode * old_child = find_element (old , cIter , TRUE );
4055
4134
4056
4135
cIter = __xml_next (cIter );
4057
4136
if (old_child == NULL ) {
@@ -4226,18 +4305,36 @@ in_upper_context(int depth, int context, xmlNode * xml_node)
4226
4305
}
4227
4306
4228
4307
static xmlNode *
4229
- find_xml_comment (xmlNode * root , xmlNode * search_comment )
4308
+ find_xml_comment (xmlNode * root , xmlNode * search_comment , gboolean exact )
4230
4309
{
4231
4310
xmlNode * a_child = NULL ;
4311
+ int search_offset = __xml_offset (search_comment );
4232
4312
4233
4313
CRM_CHECK (search_comment -> type == XML_COMMENT_NODE , return NULL );
4234
4314
4235
4315
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
+ }
4238
4330
}
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 )) {
4240
4334
return a_child ;
4335
+
4336
+ } else if (exact ) {
4337
+ return NULL ;
4241
4338
}
4242
4339
}
4243
4340
@@ -4332,7 +4429,7 @@ subtract_xml_object(xmlNode * parent, xmlNode * left, xmlNode * right,
4332
4429
left_child = __xml_next (left_child )) {
4333
4430
gboolean child_changed = FALSE;
4334
4431
4335
- right_child = find_element (right , left_child );
4432
+ right_child = find_element (right , left_child , FALSE );
4336
4433
subtract_xml_object (diff , left_child , right_child , full , & child_changed , marker );
4337
4434
if (child_changed ) {
4338
4435
* changed = TRUE;
@@ -4458,7 +4555,7 @@ add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
4458
4555
CRM_CHECK (update -> type == XML_COMMENT_NODE , return 0 );
4459
4556
4460
4557
if (target == NULL ) {
4461
- target = find_xml_comment (parent , update );
4558
+ target = find_xml_comment (parent , update , FALSE );
4462
4559
}
4463
4560
4464
4561
if (target == NULL ) {
0 commit comments