diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index b2ff529..1e80bc6 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -136,6 +136,10 @@ const char *pcmk__xe_add_last_written(xmlNode *xe); xmlNode *pcmk__xe_match(xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v); +void pcmk__xe_remove_matching_attrs(xmlNode *element, + bool (*match)(xmlAttrPtr, void *), + void *user_data); + /*! * \internal * \brief Get the root directory to scan XML artefacts of given kind for diff --git a/lib/common/xml.c b/lib/common/xml.c index f2f48e9..39c5e53 100644 --- a/lib/common/xml.c +++ b/lib/common/xml.c @@ -618,6 +618,40 @@ expand_plus_plus(xmlNode * target, const char *name, const char *value) return; } +/*! + * \internal + * \brief Remove an XML element's attributes that match some criteria + * + * \param[in,out] element XML element to modify + * \param[in] match If not NULL, only remove attributes for which + * this function returns true + * \param[in] user_data Data to pass to \p match + */ +void +pcmk__xe_remove_matching_attrs(xmlNode *element, + bool (*match)(xmlAttrPtr, void *), + void *user_data) +{ + xmlAttrPtr next = NULL; + + for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) { + next = a->next; // Grab now because attribute might get removed + if ((match == NULL) || match(a, user_data)) { + if (!pcmk__check_acl(element, NULL, xpf_acl_write)) { + crm_trace("ACLs prevent removal of %s attribute from %s element", + (const char *) a->name, (const char *) element->name); + + } else if (pcmk__tracking_xml_changes(element, false)) { + // Leave (marked for removal) until after diff is calculated + set_parent_flag(element, xpf_dirty); + pcmk__set_xml_flags((xml_private_t *) a->_private, xpf_deleted); + } else { + xmlRemoveProp(a); + } + } + } +} + xmlDoc * getDocPtr(xmlNode * node) {