From 02ac7cbd48be21d70b9b05ca006661ca01563463 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 30 Nov 2022 15:25:17 +0000 Subject: [PATCH] parser: Fix appending to variables with inheritance Fixes: #12997 Signed-off-by: Michael Tremer --- src/libpakfire/parser.c | 111 ++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/src/libpakfire/parser.c b/src/libpakfire/parser.c index d88f0a339..7a8da8d5a 100644 --- a/src/libpakfire/parser.c +++ b/src/libpakfire/parser.c @@ -245,6 +245,29 @@ static void pakfire_parser_strip_namespace(char** s) { (*s)[0] = '\0'; } +static char* pakfire_parser_join(const char* fmt, const char* val1, const char* val2) { + char* result = NULL; + int r; + + // Merge both values if both are set + if (val1 && *val1 && val2 && *val2) { + r = asprintf(&result, fmt, val1, val2); + if (r < 0) + return NULL; + + return result; + } + + // If only one value is set, return that one + if (val1 && *val1) + return strdup(val1); + else if (val2 && *val2) + return strdup(val2); + + // Return an empty string if no value is set + return strdup(""); +} + static struct pakfire_parser_declaration* pakfire_parser_find_declaration( struct pakfire_parser* parser, const char* namespace, const char* name) { struct pakfire_parser_declaration* d; @@ -273,6 +296,8 @@ static struct pakfire_parser_declaration* pakfire_parser_find_declaration( int pakfire_parser_set(struct pakfire_parser* parser, const char* namespace, const char* name, const char* value, int flags) { + char* buffer = NULL; + if (!name) return -EINVAL; @@ -282,14 +307,22 @@ int pakfire_parser_set(struct pakfire_parser* parser, // Handle when name already exists struct pakfire_parser_declaration* d = pakfire_parser_get_declaration(parser, namespace, name); if (d) { + if (flags & PAKFIRE_PARSER_DECLARATION_APPEND) { + buffer = pakfire_parser_join("%s %s", d->value, value); + if (!buffer) + return 1; + + // Reset the append flag + flags &= ~PAKFIRE_PARSER_DECLARATION_APPEND; + } else { + buffer = strdup(value); + } + // Replace value if (d->value) free(d->value); - if (value) - d->value = strdup(value); - else - d->value = NULL; + d->value = buffer; // Update flags if (flags) @@ -318,8 +351,13 @@ int pakfire_parser_set(struct pakfire_parser* parser, // Import flags d->flags = flags; - DEBUG(parser->pakfire, "%p: New declaration: %s.%s = %s\n", - parser, d->namespace, d->name, d->value); + DEBUG(parser->pakfire, "%p: New declaration (%d): %s.%s %s= %s\n", + parser, + d->flags, + d->namespace, + d->name, + (d->flags & PAKFIRE_PARSER_DECLARATION_APPEND) ? "+" : "", + d->value); // Assign new declaration to array parser->declarations = reallocarray(parser->declarations, @@ -331,8 +369,7 @@ int pakfire_parser_set(struct pakfire_parser* parser, int pakfire_parser_apply_declaration(struct pakfire_parser* parser, struct pakfire_parser_declaration* declaration) { - if (declaration->flags & PAKFIRE_PARSER_DECLARATION_APPEND) - return pakfire_parser_append(parser, declaration->namespace, declaration->name, declaration->value); + DEBUG(parser->pakfire, "GOT HERE %d\n", declaration->flags); return pakfire_parser_set(parser, declaration->namespace, declaration->name, declaration->value, declaration->flags); @@ -723,8 +760,12 @@ char** pakfire_parser_list_namespaces(struct pakfire_parser* parser, } int pakfire_parser_merge(struct pakfire_parser* parser1, struct pakfire_parser* parser2) { + struct pakfire_parser_declaration* d = NULL; + char* namespace = NULL; + char* value = NULL; + int r; + DEBUG(parser1->pakfire, "Merging parsers %p and %p\n", parser1, parser2); - char namespace[NAME_MAX*2+1]; if (!parser2) { errno = EINVAL; @@ -736,25 +777,53 @@ int pakfire_parser_merge(struct pakfire_parser* parser1, struct pakfire_parser* return EINVAL; for (unsigned int i = 0; i < parser2->num_declarations; i++) { - struct pakfire_parser_declaration* d = parser2->declarations[i]; + d = parser2->declarations[i]; if (!d) break; - if (parser2->namespace && *d->namespace) - pakfire_string_format(namespace, "%s.%s", parser2->namespace, d->namespace); - else if (parser2->namespace) - pakfire_string_set(namespace, parser2->namespace); - else if (*d->namespace) - pakfire_string_set(namespace, d->namespace); - else - pakfire_string_set(namespace, ""); + // Make the new namespace + namespace = pakfire_parser_join("%s.%s", parser2->namespace, d->namespace); + if (!namespace) { + r = 1; + goto OUT; + } + + const char* old_value = NULL; - int r = pakfire_parser_set(parser1, namespace, d->name, d->value, d->flags); + // Fetch the old value if we are supposed to be appending + if (d->flags & PAKFIRE_PARSER_DECLARATION_APPEND) { + old_value = pakfire_parser_get_raw(parser1, namespace, d->name); + + // XXX This is not ideal, to only reset once we have found an old + // value because we might carry this over too far. + // However, this is the only way to fix #12997 + if (old_value) + d->flags &= ~PAKFIRE_PARSER_DECLARATION_APPEND; + } + + // Make the new value + value = pakfire_parser_join("%s %s", old_value, d->value); + if (!value) { + r = 1; + goto OUT; + } + + // Set everything in parser 1 + r = pakfire_parser_set(parser1, namespace, d->name, value, d->flags); if (r) - return r; + goto OUT; + +OUT: + if (namespace) + free(namespace); + if (value) + free(value); + + if (r) + break; } - return 0; + return r; } int pakfire_parser_read(struct pakfire_parser* parser, FILE* f, -- 2.39.5