diff --git a/imap/http_dav.c b/imap/http_dav.c index 91bbc28b6b..a6fa5c8345 100644 --- a/imap/http_dav.c +++ b/imap/http_dav.c @@ -5494,7 +5494,7 @@ EXPORTED int meth_propfind(struct transaction_t *txn, void *params) xmlDocPtr indoc = NULL, outdoc = NULL; xmlNodePtr root, cur = NULL, props = NULL; xmlNsPtr ns[NUM_NAMESPACE]; - struct hash_table ns_table = { 0, NULL, NULL }; + struct hash_table ns_table = HASH_TABLE_INITIALIZER; struct propfind_ctx fctx; struct propfind_entry_list *elist = NULL; @@ -7900,7 +7900,7 @@ int meth_report(struct transaction_t *txn, void *params) xmlNodePtr inroot = NULL, outroot = NULL, cur, prop = NULL, props = NULL; const struct report_type_t *report = NULL; xmlNsPtr ns[NUM_NAMESPACE]; - struct hash_table ns_table = { 0, NULL, NULL }; + struct hash_table ns_table = HASH_TABLE_INITIALIZER; struct propfind_ctx fctx; struct propfind_entry_list *elist = NULL; diff --git a/lib/hash.c b/lib/hash.c index 9703142c3b..84f2e80d28 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -43,10 +43,11 @@ EXPORTED hash_table *construct_hash_table(hash_table *table, size_t size, int us assert(table); assert(size); - table->size = size; + table->size = size; + table->seed = rand(); /* might be zero, that's okay */ /* Allocate the table -- different for using memory pools and not */ - if(use_mpool) { + if (use_mpool) { /* Allocate an initial memory pool for 32 byte keys + the hash table * + the buckets themselves */ table->pool = @@ -72,7 +73,7 @@ EXPORTED hash_table *construct_hash_table(hash_table *table, size_t size, int us EXPORTED void *hash_insert(const char *key, void *data, hash_table *table) { - unsigned val = strhash(key) % table->size; + unsigned val = strhash_seeded(table->seed, key) % table->size; bucket *ptr, *newptr; bucket **prev; @@ -153,9 +154,14 @@ EXPORTED void *hash_insert(const char *key, void *data, hash_table *table) EXPORTED void *hash_lookup(const char *key, hash_table *table) { - unsigned val = strhash(key) % table->size; + unsigned val; bucket *ptr; + if (!table->size) + return NULL; + + val = strhash_seeded(table->seed, key) % table->size; + if (!(table->table)[val]) return NULL; @@ -178,8 +184,7 @@ EXPORTED void *hash_lookup(const char *key, hash_table *table) * since it will leak memory until you get rid of the entire hash table */ EXPORTED void *hash_del(const char *key, hash_table *table) { - unsigned val = strhash(key) % table->size; - void *data; + unsigned val = strhash_seeded(table->seed, key) % table->size; bucket *ptr, *last = NULL; if (!(table->table)[val]) @@ -200,15 +205,10 @@ EXPORTED void *hash_del(const char *key, hash_table *table) int cmpresult = strcmp(key, ptr->key); if (!cmpresult) { + void *data = ptr->data; if (last != NULL ) { - data = ptr -> data; last -> next = ptr -> next; - if(!table->pool) { - free(ptr->key); - free(ptr); - } - return data; } /* @@ -221,15 +221,15 @@ EXPORTED void *hash_del(const char *key, hash_table *table) else { - data = ptr->data; (table->table)[val] = ptr->next; - if(!table->pool) { - free(ptr->key); - free(ptr); - } - return data; } - } else if (cmpresult < 0) { + if(!table->pool) { + free(ptr->key); + free(ptr); + } + return data; + } + if (cmpresult < 0) { /* its not here! */ return NULL; } diff --git a/lib/hash.h b/lib/hash.h index 8051ac1760..cfa7da1ffa 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -3,10 +3,11 @@ #define HASH__H #include /* For size_t */ +#include #include "mpool.h" #include "strarray.h" -#define HASH_TABLE_INITIALIZER {0, NULL, NULL} +#define HASH_TABLE_INITIALIZER {0, 0, NULL, NULL} /* ** A hash table consists of an array of these buckets. Each bucket @@ -32,6 +33,7 @@ typedef struct bucket { typedef struct hash_table { size_t size; + uint32_t seed; bucket **table; struct mpool *pool; } hash_table; diff --git a/lib/strhash.c b/lib/strhash.c index d7c1741d2a..1b3251db73 100644 --- a/lib/strhash.c +++ b/lib/strhash.c @@ -42,17 +42,32 @@ #include "config.h" -EXPORTED unsigned strhash(const char *string) +#include "lib/strhash.h" + +/* The well-known djb2 algorithm (e.g. http://www.cse.yorku.ca/~oz/hash.html), + * with the addition of an optional seed to limit predictability. + * + * XXX return type 'unsigned' for back-compat to previous version, but + * XXX ought to be 'uint32_t' + */ +EXPORTED unsigned strhash_seeded_djb2(uint32_t seed, const char *string) { - unsigned ret_val = 0; - int i; + const unsigned char *ustr = (const unsigned char *) string; + unsigned hash = 5381; + int c; - while (*string) - { - i = (int) *string; - ret_val ^= i; - ret_val <<= 1; - string ++; - } - return ret_val; + if (seed) { + /* treat the bytes of the seed as a prefix to the string */ + unsigned i; + for (i = 0; i < sizeof seed; i++) { + c = seed & 0xff; + hash = ((hash << 5) + hash) ^ c; + seed >>= 8; + } + } + + while ((c = *ustr++)) + hash = ((hash << 5) + hash) ^ c; + + return hash; } diff --git a/lib/strhash.h b/lib/strhash.h index 34533fdffa..27339bb288 100644 --- a/lib/strhash.h +++ b/lib/strhash.h @@ -41,7 +41,11 @@ */ #ifndef _STRHASH_H_ +#include -unsigned strhash(const char *string); +unsigned strhash_seeded_djb2(uint32_t seed, const char *string); + +#define strhash(in) strhash_seeded_djb2((0), (in)) +#define strhash_seeded(sd, in) strhash_seeded_djb2((sd), (in)) #endif /* _STRHASH_H_ */