From ff65d01333ef9e0c9dd53144186381b6b44c64af Mon Sep 17 00:00:00 2001 From: Robin Hack Date: Mon, 23 Mar 2015 14:10:18 +0100 Subject: [PATCH] nwrap: Add nwrap vector memory management functions Nwrap vectors are just more inteligent arrays. They can look like very simple version of vectors from C++. TESTS: Add nwrap_vector tests. Signed-off-by: Robin Hack Reviewed-by: Andreas Schneider Reviewed-by: Michael Adam --- lib/nss_wrapper/nss_wrapper.c | 137 ++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/lib/nss_wrapper/nss_wrapper.c b/lib/nss_wrapper/nss_wrapper.c index e985bb3f4cb..69949aaf458 100644 --- a/lib/nss_wrapper/nss_wrapper.c +++ b/lib/nss_wrapper/nss_wrapper.c @@ -50,6 +50,8 @@ #include #include +#include + /* * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h gives us * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on @@ -477,6 +479,141 @@ struct nwrap_main { struct nwrap_main *nwrap_main_global; struct nwrap_main __nwrap_main_global; +/* + * VECTORS + */ + +#define DEFAULT_VECTOR_CAPACITY 16 + +struct nwrap_vector { + void **items; + size_t count; + size_t capacity; +}; + +/* Macro returns pointer to first element of vector->items array. + * + * nwrap_vector is used as a memory backend which take care of + * memory allocations and other stuff like memory growing. + * nwrap_vectors should not be considered as some abstract structures. + * On this level, vectors are more handy than direct realloc/malloc + * calls. + * + * nwrap_vector->items is array inside nwrap_vector which can be + * directly pointed by libc structure assembled by cwrap itself. + * + * EXAMPLE: + * + * 1) struct hostent contains char **h_addr_list element. + * 2) nwrap_vector holds array of pointers to addresses. + * It's easier to use vector to store results of + * file parsing etc. + * + * Now, pretend that cwrap assembled struct hostent and + * we need to set h_addr_list to point to nwrap_vector. + * Idea behind is to shield users from internal nwrap_vector + * implementation. + * (Yes, not fully - array terminated by NULL is needed because + * it's result expected by libc function caller.) + * + * + * CODE EXAMPLE: + * + * struct hostent he; + * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector)); + * ... don't care about failed allocation now ... + * + * ... fill nwrap vector ... + * + * struct hostent he; + * he.h_addr_list = nwrap_vector_head(vector); + * + */ +#define nwrap_vector_head(vect) ((void *)((vect)->items)) + +#define nwrap_vector_foreach(item, vect, iter) \ + for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \ + item != NULL; \ + (item) = (vect).items[++iter]) + +static inline bool nwrap_vector_init(struct nwrap_vector *const vector) +{ + if (vector == NULL) { + return false; + } + + /* count is initialized by ZERO_STRUCTP */ + ZERO_STRUCTP(vector); + vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1)); + if (vector->items == NULL) { + return false; + } + vector->capacity = DEFAULT_VECTOR_CAPACITY; + memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1)); + + return true; +} + +static bool nwrap_vector_add_item(struct nwrap_vector *cont, void *const item) +{ + assert (cont != NULL); + + if (cont->items == NULL) { + nwrap_vector_init(cont); + } + + if (cont->count == cont->capacity) { + /* Items array _MUST_ be NULL terminated because it's passed + * as result to caller which expect NULL terminated array from libc. + */ + void **items = realloc(cont->items, sizeof(void *) * ((cont->capacity * 2) + 1)); + if (items == NULL) { + return false; + } + cont->items = items; + + /* Don't count ending NULL to capacity */ + cont->capacity *= 2; + } + + cont->items[cont->count] = item; + + cont->count += 1; + cont->items[cont->count] = NULL; + + return true; +} + +static bool nwrap_vector_merge(struct nwrap_vector *dst, + struct nwrap_vector *src) +{ + void **dst_items = NULL; + size_t count; + + if (src->count == 0) { + return true; + } + + count = dst->count + src->count; + + /* We don't need reallocation if we have enough capacity. */ + if (src->count > (dst->capacity - dst->count)) { + dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *)); + if (dst_items == NULL) { + return false; + } + dst->items = dst_items; + dst->capacity = count; + } + + memcpy((void *)(((long *)dst->items) + dst->count), + src->items, + src->count * sizeof(void *)); + dst->count = count; + + return true; +} + struct nwrap_cache { const char *path; int fd;