File: xml_attr.c

package info (click to toggle)
pacemaker 3.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 68,576 kB
  • sloc: xml: 160,564; ansic: 143,744; python: 5,670; sh: 2,969; makefile: 2,426
file content (141 lines) | stat: -rw-r--r-- 4,014 bytes parent folder | download
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);
}