1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
* Copyright 2004-2025 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <bzlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlIO.h> /* xmlAllocOutputBuffer */
#include <crm/crm.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h> // PCMK__XML_LOG_BASE, etc.
#include "crmcommon_private.h"
/*!
* \internal
* \brief Remove an XML attribute from its parent and free it
*
* \param[in,out] attr XML attribute to remove
* \param[in] force If \c true, remove the attribute immediately, ignoring
* ACLs and change tracking
*
* \return Standard Pacemaker return code (\c EPERM if ACLs prevent removal, or
* or \c pcmk_rc_ok otherwise)
*
* \note If the attribute has no parent element, this function does not free it.
* This mimics \c xmlRemoveProp().
*/
int
pcmk__xa_remove(xmlAttr *attr, bool force)
{
xmlNode *element = NULL;
if ((attr == NULL) || (attr->parent == NULL)) {
return pcmk_rc_ok;
}
element = attr->parent;
if (!force && !pcmk__check_acl(element, NULL, pcmk__xf_acl_write)) {
// ACLs apply to element, not to particular attributes
crm_trace("ACLs prevent removal of attributes from %s element",
(const char *) element->name);
return EPERM;
}
if (!force && (element != NULL)
&& pcmk__xml_doc_all_flags_set(element->doc, pcmk__xf_tracking)) {
// Leave in place (marked for removal) until after diff is calculated
pcmk__xml_set_parent_flags(element, pcmk__xf_dirty);
pcmk__set_xml_flags((xml_node_private_t *) attr->_private,
pcmk__xf_deleted);
} else {
pcmk__xml_free_private_data((xmlNode *) attr);
xmlRemoveProp(attr);
}
return pcmk_rc_ok;
}
void
pcmk__mark_xml_attr_dirty(xmlAttr *a)
{
xmlNode *parent = a->parent;
xml_node_private_t *nodepriv = a->_private;
pcmk__set_xml_flags(nodepriv, pcmk__xf_dirty|pcmk__xf_modified);
pcmk__clear_xml_flags(nodepriv, pcmk__xf_deleted);
pcmk__mark_xml_node_dirty(parent);
}
// This also clears attribute's flags if not marked as deleted
bool
pcmk__marked_as_deleted(xmlAttrPtr a, void *user_data)
{
xml_node_private_t *nodepriv = a->_private;
if (pcmk_is_set(nodepriv->flags, pcmk__xf_deleted)) {
return true;
}
nodepriv->flags = pcmk__xf_none;
return false;
}
/*!
* \internal
* \brief Append an XML attribute to a buffer
*
* \param[in] attr Attribute to append
* \param[in,out] buffer Where to append the content (must not be \p NULL)
*/
void
pcmk__dump_xml_attr(const xmlAttr *attr, GString *buffer)
{
const char *name = NULL;
const char *value = NULL;
gchar *value_esc = NULL;
xml_node_private_t *nodepriv = NULL;
if (attr == NULL || attr->children == NULL) {
return;
}
nodepriv = attr->_private;
if (nodepriv && pcmk_is_set(nodepriv->flags, pcmk__xf_deleted)) {
return;
}
name = (const char *) attr->name;
value = (const char *) attr->children->content;
if (value == NULL) {
/* Don't print anything for unset attribute. Any null-indicator value,
* including the empty string, could also be a real value that needs to
* be treated differently from "unset".
*/
return;
}
if (pcmk__xml_needs_escape(value, pcmk__xml_escape_attr)) {
value_esc = pcmk__xml_escape(value, pcmk__xml_escape_attr);
value = value_esc;
}
pcmk__g_strcat(buffer, " ", name, "=\"", value, "\"", NULL);
g_free(value_esc);
}
|