diff options
author | Aleš Matěj <amatej@redhat.com> | 2021-11-10 15:07:39 +0300 |
---|---|---|
committer | Neal Gompa (ニール・ゴンパ) <ngompa13@gmail.com> | 2022-03-29 07:53:40 +0300 |
commit | 0b2f0180bf777aea2255eaa2af27d4e82055ec33 (patch) | |
tree | 6c1c25dd9b9d08dada7095c487ba6c0f02ea97d7 | |
parent | 869b789f0f4eedfab561f7d397a578cbc5966ed9 (diff) |
Fix '&' encoding in attributes when parsing repodata
When loading repodata libxml2 replaces all '&' with "&"
This can lead to problems, if an rpm contains '&' in a dependency and we
run createrepo_c on it it gets stored as "&" if we later run
createrepo_c with --update its loaded and encoded as "&" which get
stored in the xml as "&#38;"
To circumvent this change all "&" back to '&' when parsing.
-rw-r--r-- | src/xml_parser.c | 44 | ||||
-rw-r--r-- | src/xml_parser_filelists.c | 7 | ||||
-rw-r--r-- | src/xml_parser_internal.h | 9 | ||||
-rw-r--r-- | src/xml_parser_other.c | 7 | ||||
-rw-r--r-- | src/xml_parser_primary.c | 7 | ||||
-rw-r--r-- | src/xml_parser_repomd.c | 7 | ||||
-rw-r--r-- | src/xml_parser_updateinfo.c | 7 |
7 files changed, 88 insertions, 0 deletions
diff --git a/src/xml_parser.c b/src/xml_parser.c index 05bcde7..37203ef 100644 --- a/src/xml_parser.c +++ b/src/xml_parser.c @@ -292,3 +292,47 @@ cr_xml_parser_generic_from_string(xmlParserCtxtPtr parser, return ret; } + +const xmlChar ** +unescape_ampersand_from_values(const xmlChar **attr, gboolean *allocation_needed) { + *allocation_needed = FALSE; + + if (!attr) { + return attr; + } + + // In the vast majority of cases there is no '&' in the + // data so check if there is any first and if not return + // quickly. + // + // attr consists of key1, value1, key2, value2 pairs, + // we know which keys we want (they don't contain &) so + // we don't have to check those. + size_t nattr; + for (nattr = 1; attr[nattr]; nattr+=2) { + if (strchr((char *)attr[nattr], '&')) { + *allocation_needed = TRUE; + } + } + + if (!*allocation_needed) { + return attr; + } + + char **attr_copy = g_malloc0(sizeof(char *) * (nattr - 1)); + if (attr_copy) { + for (nattr = 0; attr[nattr]; nattr++) { + if (strchr((char *)attr[nattr], '&')) { + char **cut_out_amp = g_strsplit((char *)attr[nattr], "#38;", -1); + attr_copy[nattr] = g_strjoinv(NULL, cut_out_amp); + g_strfreev(cut_out_amp); + } else { + attr_copy[nattr] = g_strdup((char *)attr[nattr]); + } + } + + attr_copy[nattr] = 0; + } + + return (const xmlChar **)attr_copy; +} diff --git a/src/xml_parser_filelists.c b/src/xml_parser_filelists.c index 33a2058..1885850 100644 --- a/src/xml_parser_filelists.c +++ b/src/xml_parser_filelists.c @@ -90,6 +90,9 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) return; } + gboolean free_attr = FALSE; + attr = unescape_ampersand_from_values(attr, &free_attr); + // Update parser data pd->state = sw->to; pd->docontent = sw->docontent; @@ -197,6 +200,10 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) default: break; } + + if (free_attr) { + g_strfreev((char **)attr); + } } static void XMLCALL diff --git a/src/xml_parser_internal.h b/src/xml_parser_internal.h index f81566b..0a33578 100644 --- a/src/xml_parser_internal.h +++ b/src/xml_parser_internal.h @@ -249,6 +249,15 @@ other_parser_data_new(cr_XmlParserNewPkgCb newpkgcb, cr_XmlParserWarningCb warningcb, void *warningcb_data); +/** Replace & by real ampersand char from values in attr. + * @param attr List of attributes + * @param allocation_needed Output bool whether returned attr has to be freed. + * @return attr with regular '&' instead of "&"; + */ +const xmlChar **unescape_ampersand_from_values(const xmlChar **attr, + gboolean *allocation_needed); + + #ifdef __cplusplus } #endif diff --git a/src/xml_parser_other.c b/src/xml_parser_other.c index a57382a..a5d8afa 100644 --- a/src/xml_parser_other.c +++ b/src/xml_parser_other.c @@ -90,6 +90,9 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) return; } + gboolean free_attr = FALSE; + attr = unescape_ampersand_from_values(attr, &free_attr); + // Update parser data pd->state = sw->to; pd->docontent = sw->docontent; @@ -206,6 +209,10 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) default: break; } + + if (free_attr) { + g_strfreev((char **)attr); + } } static void XMLCALL diff --git a/src/xml_parser_primary.c b/src/xml_parser_primary.c index d3d3f5d..a98ecf9 100644 --- a/src/xml_parser_primary.c +++ b/src/xml_parser_primary.c @@ -156,6 +156,9 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) return; } + gboolean free_attr = FALSE; + attr = unescape_ampersand_from_values(attr, &free_attr); + // Update parser data pd->state = sw->to; pd->docontent = sw->docontent; @@ -444,6 +447,10 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) default: break; } + + if (free_attr) { + g_strfreev((char **)attr); + } } static void XMLCALL diff --git a/src/xml_parser_repomd.c b/src/xml_parser_repomd.c index 2e31817..f0b06a5 100644 --- a/src/xml_parser_repomd.c +++ b/src/xml_parser_repomd.c @@ -114,6 +114,9 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) return; } + gboolean free_attr = FALSE; + attr = unescape_ampersand_from_values(attr, &free_attr); + // Update parser data pd->state = sw->to; pd->docontent = sw->docontent; @@ -258,6 +261,10 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) default: break; } + + if (free_attr) { + g_strfreev((char **)attr); + } } static void diff --git a/src/xml_parser_updateinfo.c b/src/xml_parser_updateinfo.c index e51929b..6635930 100644 --- a/src/xml_parser_updateinfo.c +++ b/src/xml_parser_updateinfo.c @@ -132,6 +132,9 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) return; } + gboolean free_attr = FALSE; + attr = unescape_ampersand_from_values(attr, &free_attr); + // Update parser data pd->state = sw->to; pd->docontent = sw->docontent; @@ -394,6 +397,10 @@ cr_start_handler(void *pdata, const xmlChar *element, const xmlChar **attr) package->relogin_suggested = TRUE; break; } + + if (free_attr) { + g_strfreev((char **)attr); + } } static void |