diff options
Diffstat (limited to 'support/junction/xml.c')
-rw-r--r-- | support/junction/xml.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/support/junction/xml.c b/support/junction/xml.c new file mode 100644 index 0000000..813110b --- /dev/null +++ b/support/junction/xml.c @@ -0,0 +1,401 @@ +/** + * @file support/junction/xml.c + * @brief Common utilities for managing junction XML + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "junction.h" +#include "junction-internal.h" +#include "xlog.h" + +/** + * Predicate: is element content empty? + * + * @param content element content to test + * @return true if content is empty + */ +_Bool +junction_xml_is_empty(const xmlChar *content) +{ + return content == NULL || *content == '\0'; +} + +/** + * Match an XML parse tree node by its name + * + * @param node pointer to a node in an XML parse tree + * @param name NUL-terminated C string containing name to match + * @return true if "node" is named "name" + */ +_Bool +junction_xml_match_node_name(xmlNodePtr node, const xmlChar *name) +{ + return (node->type == XML_ELEMENT_NODE) && + (xmlStrcmp(node->name, name) == 0); +} + +/** + * Find a first-level child of "parent" named "name" + * + * @param parent pointer to node whose children are to be searched + * @param name NUL-terminated C string containing name to match + * @return pointer to child of "parent" whose name is "name" + */ +xmlNodePtr +junction_xml_find_child_by_name(xmlNodePtr parent, const xmlChar *name) +{ + xmlNodePtr node; + + for (node = parent->children; node != NULL; node = node->next) + if (junction_xml_match_node_name(node, name)) + return node; + return NULL; +} + +/** + * Read attribute into a boolean + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an integer + * @return true if attribute "attrname" has a valid boolean value + */ +_Bool +junction_xml_get_bool_attribute(xmlNodePtr node, const xmlChar *attrname, + _Bool *value) +{ + xmlChar *prop; + _Bool retval; + + retval = false; + prop = xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + if (xmlStrcmp(prop, (const xmlChar *)"true") == 0) { + *value = true; + retval = true; + goto out; + } + + if (xmlStrcmp(prop, (const xmlChar *)"false") == 0) { + *value = false; + retval = true; + goto out; + } + +out: + xmlFree(prop); + return retval; +} + +/** + * Set attribute to a boolean + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value boolean value to set + */ +void +junction_xml_set_bool_attribute(xmlNodePtr node, const xmlChar *attrname, + _Bool value) +{ + xmlSetProp(node, attrname, (const xmlChar *)(value ? "true" : "false")); +} + +/** + * Read attribute into an uint8_t + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an uint8_t + * @return true if attribute "attrname" has a valid uint8_t value + */ +_Bool +junction_xml_get_u8_attribute(xmlNodePtr node, const xmlChar *attrname, + uint8_t *value) +{ + char *endptr; + _Bool retval; + char *prop; + long tmp; + + retval = false; + prop = (char *)xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + errno = 0; + tmp = strtol(prop, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > 255 || tmp < 0) + goto out; + + *value = (uint8_t)tmp; + retval = true; + +out: + xmlFree(prop); + return retval; +} + +/** + * Read attribute into an integer + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an integer + * @return true if attribute "attrname" has a valid integer value + */ +_Bool +junction_xml_get_int_attribute(xmlNodePtr node, const xmlChar *attrname, + int *value) +{ + char *endptr; + _Bool retval; + char *prop; + long tmp; + + retval = false; + prop = (char *)xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + errno = 0; + tmp = strtol(prop, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN) + goto out; + + *value = (int)tmp; + retval = true; + +out: + xmlFree(prop); + return retval; +} + +/** + * Set attribute to an integer + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value integer value to set + */ +void +junction_xml_set_int_attribute(xmlNodePtr node, const xmlChar *attrname, + int value) +{ + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", value); + xmlSetProp(node, attrname, (const xmlChar *)buf); +} + +/** + * Read node content into an integer + * + * @param node pointer to a node in an XML parse tree + * @param value OUT: node's content converted to an integer + * @return true if "node" has valid integer content + */ +_Bool +junction_xml_get_int_content(xmlNodePtr node, int *value) +{ + xmlChar *content; + char *endptr; + _Bool retval; + long tmp; + + retval = false; + content = xmlNodeGetContent(node); + if (content == NULL) + goto out; + + errno = 0; + tmp = strtol((const char *)content, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN) + goto out; + + *value = (int)tmp; + retval = true; + +out: + xmlFree(content); + return retval; +} + +/** + * Add a child node with integer content + * + * @param parent pointer to a node in an XML parse tree + * @param name NUL-terminated C string containing name of child to add + * @param value set node content to this value + * @return pointer to new child node + */ +xmlNodePtr +junction_xml_set_int_content(xmlNodePtr parent, const xmlChar *name, int value) +{ + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", value); + return xmlNewTextChild(parent, NULL, name, (const xmlChar *)buf); +} + +/** + * Parse XML document in a buffer into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param buf opaque byte array containing XML to parse + * @param len size of "buf" in bytes + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml_buf() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +junction_parse_xml_buf(const char *pathname, const char *name, + void *buf, size_t len, xmlDocPtr *doc) +{ + xmlDocPtr tmp; + + tmp = xmlParseMemory(buf, (int)len); + if (tmp == NULL) { + xlog(D_GENERAL, "Failed to parse XML in %s(%s)\n", + pathname, name); + return FEDFS_ERR_SVRFAULT; + } + + *doc = tmp; + return FEDFS_OK; +} + +/** + * Read an XML document from an extended attribute into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param fd an open file descriptor + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml_read() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +junction_parse_xml_read(const char *pathname, int fd, const char *name, + xmlDocPtr *doc) +{ + FedFsStatus retval; + void *buf = NULL; + size_t len; + + retval = junction_get_xattr(fd, pathname, name, &buf, &len); + if (retval != FEDFS_OK) + return retval; + + xlog(D_CALL, "%s: XML document contained in junction:\n%zu.%s", + __func__, len, (char *)buf); + + retval = junction_parse_xml_buf(pathname, name, buf, len, doc); + + free(buf); + return retval; +} + +/** + * Read an XML document from an extended attribute into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_xml_parse(const char *pathname, const char *name, xmlDocPtr *doc) +{ + FedFsStatus retval; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_parse_xml_read(pathname, fd, name, doc); + + (void)close(fd); + return retval; +} + +/** + * Write an XML document into an extended attribute + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_xml_write(const char *pathname, const char *name, xmlDocPtr doc) +{ + xmlChar *buf = NULL; + FedFsStatus retval; + int fd, len; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = FEDFS_ERR_SVRFAULT; + xmlIndentTreeOutput = 1; + xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "UTF-8", 1); + if (len < 0) + goto out; + + retval = junction_set_xattr(fd, pathname, name, buf, (size_t)len); + +out: + xmlFree(buf); + (void)close(fd); + return retval; +} |