summaryrefslogtreecommitdiff
path: root/src/lib-config/get.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-config/get.c')
-rw-r--r--src/lib-config/get.c62
1 files changed, 54 insertions, 8 deletions
diff --git a/src/lib-config/get.c b/src/lib-config/get.c
index 2f1e90e1..a83686fd 100644
--- a/src/lib-config/get.c
+++ b/src/lib-config/get.c
@@ -38,12 +38,12 @@ CONFIG_NODE *config_node_find(CONFIG_NODE *node, const char *key)
return NULL;
}
-CONFIG_NODE *config_node_section(CONFIG_NODE *parent, const char *key, int new_type)
+CONFIG_NODE *config_node_section(CONFIG_REC *rec, CONFIG_NODE *parent, const char *key, int new_type)
{
- return config_node_section_index(parent, key, -1, new_type);
+ return config_node_section_index(rec, parent, key, -1, new_type);
}
-CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
+CONFIG_NODE *config_node_section_index(CONFIG_REC *rec, CONFIG_NODE *parent, const char *key,
int index, int new_type)
{
CONFIG_NODE *node;
@@ -54,7 +54,6 @@ CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
node = key == NULL ? NULL : config_node_find(parent, key);
if (node != NULL) {
- g_return_val_if_fail(new_type == -1 || new_type == node->type, NULL);
nindex = g_slist_index(parent->value, node);
if (index >= 0 && nindex != index &&
nindex <= g_slist_length(parent->value)) {
@@ -62,7 +61,25 @@ CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
parent->value = g_slist_remove(parent->value, node);
parent->value = g_slist_insert(parent->value, node, index);
}
- return node;
+ if (!is_node_list(node)) {
+ int show_error = 0;
+
+ if (new_type != -1) {
+ config_node_remove(rec, parent, node);
+ node = NULL;
+ show_error = 1;
+ } else if (!g_hash_table_lookup_extended(rec->cache_nodes, node, NULL, NULL)) {
+ g_hash_table_insert(rec->cache_nodes, node, NULL);
+ show_error = 1;
+ }
+ if (show_error)
+ g_critical("Expected %s node at `..%s/%s' was of scalar type. Corrupt config?",
+ new_type == NODE_TYPE_LIST ? "list" : new_type == NODE_TYPE_BLOCK ? "block" : "section",
+ parent->key, key);
+ } else {
+ g_return_val_if_fail(new_type == -1 || new_type == node->type, NULL);
+ return node;
+ }
}
if (new_type == -1)
@@ -91,7 +108,21 @@ CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int crea
/* check if it already exists in cache */
node = g_hash_table_lookup(rec->cache, section);
- if (node != NULL) return node;
+ if (node != NULL) {
+ if (create) {
+ const char *path = strrchr(section, '/');
+ if (path == NULL) path = section;
+ else path++;
+ new_type = *path == '(' ? NODE_TYPE_LIST : NODE_TYPE_BLOCK;
+ if (node->type != new_type) {
+ g_critical("Expected %s node at `%s' was of %s type. Corrupt config?",
+ new_type == NODE_TYPE_LIST ? "list" : "block", section,
+ node->type == NODE_TYPE_LIST ? "list" : "block");
+ node->type = new_type;
+ }
+ }
+ return node;
+ }
new_type = -1;
@@ -99,9 +130,18 @@ CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int crea
list = g_strsplit(section, "/", -1);
for (tmp = list; *tmp != NULL; tmp++) {
is_list = **tmp == '(';
- if (create) new_type = is_list ? NODE_TYPE_LIST : NODE_TYPE_BLOCK;
+ if (create) {
+ CONFIG_NODE *tmpnode;
+
+ new_type = is_list ? NODE_TYPE_LIST : NODE_TYPE_BLOCK;
+ tmpnode = config_node_find(node, *tmp + is_list);
+ if (tmpnode != NULL && tmpnode->type != new_type) {
+ g_critical("Expected %s node at `%s' was of scalar type. Corrupt config?", is_list ? "list" : "block", section);
+ config_node_remove(rec, node, tmpnode);
+ }
+ }
- node = config_node_section(node, *tmp + is_list, new_type);
+ node = config_node_section(rec, node, *tmp + is_list, new_type);
if (node == NULL) {
g_strfreev(list);
return NULL;
@@ -109,6 +149,12 @@ CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int crea
}
g_strfreev(list);
+ if (!is_node_list(node)) {
+ /* Will die. Better to not corrupt the config further in this case. */
+ g_critical("Attempt to use non-list node `%s' as list. Corrupt config?", section);
+ return NULL;
+ }
+
/* save to cache */
str = g_strdup(section);
g_hash_table_insert(rec->cache, str, node);