diff options
Diffstat (limited to 'src/map.c')
-rw-r--r-- | src/map.c | 100 |
1 files changed, 83 insertions, 17 deletions
@@ -19,6 +19,7 @@ #include "map.h" #include "portmap.h" +/* The singleton for the cache. */ struct { struct domain { char *name; @@ -27,7 +28,7 @@ struct { time_t last_changed; struct entry { struct entry *prev, *next; - char *id, **visited_ids; + char *id, **related_ids; char *key; unsigned int key_len; char *value; @@ -121,6 +122,8 @@ map_data_find_map_entry_id(struct plugin_state *state, return NULL; } +/* Handlers for the list of related IDs. On this side we actually store them + * as one contiguous chunk of memory. */ static PRBool map_id_in_id_list(const char *id, char **id_list) { @@ -133,39 +136,60 @@ map_id_in_id_list(const char *id, char **id_list) return FALSE; } +/* Duplicate a passed-in list of strings. The result is stored in one chunk of + * memory: pointers first, then the individual strings. */ static char ** map_id_dup_id_list(const char **in_id_list) { int i, l; char **ret, *s; + /* Handle the NULL case. */ + if (in_id_list == NULL) { + return NULL; + } + /* Count the amount of space needed for the strings. */ for (i = 0, l = 0; (in_id_list[i] != NULL); i++) { l += (strlen(in_id_list[i]) + 1); } + /* No strings = no list. */ if (i == 0) { return NULL; } + /* Allocate space for the array of pointers (with NULL terminator) and + * then the string data. */ ret = malloc((i + 1) * sizeof(char *) + l); if (ret != NULL) { + /* Figure out where the string data will start. */ s = (char *) &ret[i + 1]; for (i = 0; (in_id_list[i] != NULL); i++) { + /* Set the address of this string, copy the data + * around, and then prepare the address of the next + * string. */ ret[i] = s; strcpy(s, in_id_list[i]); s += (strlen(s) + 1); } + /* NULL-terminate the array. */ ret[i] = NULL; } return ret; } +/* Free the list -- since it's one chunk of memory, we shouldn't try anything + * complicated. */ static void map_id_free_id_list(char **id_list) { free(id_list); } +/* Iterate through every entry in every map, calling the callback if "all" is + * true, or if "id" is not NULL and matches the entry's ID, or if the + * "related_id" is not NULL and in the list of related IDs. If the callback + * returns FALSE, then we abort and return FALSE, otherwise we return TRUE. */ static PRBool map_data_foreach_entry(struct plugin_state *state, - PRBool all, const char *id, const char *visited_id, + PRBool all, const char *id, const char *related_id, PRBool (*fn)(const char *domain, const char *map, const char *key, unsigned int key_len, const char *value, unsigned int value_len, @@ -186,9 +210,9 @@ map_data_foreach_entry(struct plugin_state *state, if (all || ((id != NULL) && (strcmp(id, entry->id) == 0)) || - ((visited_id != NULL) && - (map_id_in_id_list(visited_id, - entry->visited_ids)))) { + ((related_id != NULL) && + (map_id_in_id_list(related_id, + entry->related_ids)))) { if (!(*fn)(domain->name, map->name, entry->key, entry->key_len, @@ -204,6 +228,7 @@ map_data_foreach_entry(struct plugin_state *state, return TRUE; } +/* Iterate over every entry which matches the corresponding ID. */ PRBool map_data_foreach_entry_id(struct plugin_state *state, const char *id, PRBool (*fn)(const char *domain, const char *map, @@ -217,9 +242,10 @@ map_data_foreach_entry_id(struct plugin_state *state, const char *id, return map_data_foreach_entry(state, FALSE, id, NULL, fn, cbdata); } +/* Iterate over every entry which lists the ID as a related ID. */ PRBool -map_data_foreach_entry_visited_id(struct plugin_state *state, - const char *visited_id, +map_data_foreach_entry_related_id(struct plugin_state *state, + const char *related_id, PRBool (*fn)(const char *domain, const char *map, const char *key, @@ -229,10 +255,42 @@ map_data_foreach_entry_visited_id(struct plugin_state *state, const char *id, void *cbdata), void *cbdata) { - return map_data_foreach_entry(state, FALSE, NULL, visited_id, + return map_data_foreach_entry(state, FALSE, NULL, related_id, fn, cbdata); } +/* Iterate over all maps, calling the callback with information about the map + * and whatever the caller originally told us to keep track of when the map was + * first set up. */ +PRBool +map_data_foreach_map(struct plugin_state *state, const char *domain_name, + PRBool (*fn)(const char *domain, + const char *map, + void *backend_data, + void *cbdata), + void *cbdata) +{ + int i, j; + struct domain *domain; + struct map *map; + struct entry *entry; + for (i = 0; i < map_data.n_domains; i++) { + domain = &map_data.domains[i]; + if ((domain_name != NULL) && + (strcmp(domain->name, domain_name) != 0)) { + continue; + } + for (j = 0; j < domain->n_maps; j++) { + map = &domain->maps[j]; + if (!(*fn)(domain->name, map->name, map->backend_data, + cbdata)) { + return FALSE; + } + } + } + return TRUE; +} + /* Query function: check if we have a record for the domain. Return that * information in "supported", and return TRUE unless we ran into internal * errors. */ @@ -504,6 +562,8 @@ map_data_set_map(struct plugin_state *state, } } } else { + /* There's already a map there, we just need to update the + * data we're keeping track of for the backend. */ if (map->free_backend_data != NULL) { map->free_backend_data(map->backend_data); } @@ -531,6 +591,7 @@ map_data_unset_map_entry(struct plugin_state *state, if (map->entries == entry) { map->entries = next; } + map_id_free_id_list(entry->related_ids); free(entry->id); free(entry->key); free(entry->value); @@ -538,6 +599,7 @@ map_data_unset_map_entry(struct plugin_state *state, } } +/* Remove the entry from the map which matches the passed-in key. */ void map_data_unset_entry_key(struct plugin_state *state, const char *domain_name, @@ -553,6 +615,7 @@ map_data_unset_entry_key(struct plugin_state *state, map->last_changed = time(NULL); } +/* Remove the entry from the map which matches the passed-in ID. */ void map_data_unset_entry_id(struct plugin_state *state, const char *domain_name, @@ -573,7 +636,7 @@ map_data_set_entry(struct plugin_state *state, const char *domain_name, const char *map_name, const char *id, - const char **visited_ids, + const char **related_ids, unsigned int key_len, char *key, unsigned int value_len, @@ -591,26 +654,29 @@ map_data_set_entry(struct plugin_state *state, if (map != NULL) { entry = map_data_find_map_entry_id(state, map, id); if (entry != NULL) { + /* There's already an entry with this ID, so let's + * replace its key and value. */ free(entry->key); - free(entry->value); - entry->key = key; + entry->key = xmemdup(key, key_len); entry->key_len = key_len; - entry->value = value; + free(entry->value); + entry->value = xmemdup(value, value_len); entry->value_len = value_len; free(entry->id); entry->id = strdup(id); - map_id_free_id_list(entry->visited_ids); - entry->visited_ids = map_id_dup_id_list(visited_ids); + map_id_free_id_list(entry->related_ids); + entry->related_ids = map_id_dup_id_list(related_ids); } else { + /* There's no entry with this ID, so create one. */ entry = malloc(sizeof(*entry)); if (entry != NULL) { memset(entry, 0, sizeof(*entry)); - entry->key = key; + entry->key = xmemdup(key, key_len); entry->key_len = key_len; - entry->value = value; + entry->value = xmemdup(value, value_len); entry->value_len = value_len; entry->id = strdup(id); - entry->visited_ids = map_id_dup_id_list(visited_ids); + entry->related_ids = map_id_dup_id_list(related_ids); entry->next = map->entries; if (map->entries != NULL) { map->entries->prev = entry; |