]> git.ipfire.org Git - pakfire.git/commitdiff
parser: Fix appending to variables with inheritance
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 30 Nov 2022 15:25:17 +0000 (15:25 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 30 Nov 2022 15:25:17 +0000 (15:25 +0000)
Fixes: #12997
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/parser.c

index d88f0a339c1d505a001fdbc6748146a4688308e8..7a8da8d5abb2de22c64baa1301290d94fe6bbea7 100644 (file)
@@ -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,