1*d3d3aa62Slukem /* $NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $ */
27307c9a9Slukem
342f1aa04Slukem /*
442f1aa04Slukem * Copyright (c) 1995
542f1aa04Slukem * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
642f1aa04Slukem *
742f1aa04Slukem * Redistribution and use in source and binary forms, with or without
842f1aa04Slukem * modification, are permitted provided that the following conditions
942f1aa04Slukem * are met:
1042f1aa04Slukem * 1. Redistributions of source code must retain the above copyright
1142f1aa04Slukem * notice, this list of conditions and the following disclaimer.
1242f1aa04Slukem * 2. Redistributions in binary form must reproduce the above copyright
1342f1aa04Slukem * notice, this list of conditions and the following disclaimer in the
1442f1aa04Slukem * documentation and/or other materials provided with the distribution.
1542f1aa04Slukem * 3. All advertising materials mentioning features or use of this software
1642f1aa04Slukem * must display the following acknowledgement:
1742f1aa04Slukem * This product includes software developed by Bill Paul.
1842f1aa04Slukem * 4. Neither the name of the author nor the names of any co-contributors
1942f1aa04Slukem * may be used to endorse or promote products derived from this software
2042f1aa04Slukem * without specific prior written permission.
2142f1aa04Slukem *
2242f1aa04Slukem * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2342f1aa04Slukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2442f1aa04Slukem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2542f1aa04Slukem * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2642f1aa04Slukem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2742f1aa04Slukem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2842f1aa04Slukem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2942f1aa04Slukem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3042f1aa04Slukem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3142f1aa04Slukem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3242f1aa04Slukem * SUCH DAMAGE.
3342f1aa04Slukem *
3442f1aa04Slukem */
3542f1aa04Slukem
367307c9a9Slukem #include <sys/cdefs.h>
377307c9a9Slukem #ifndef lint
38*d3d3aa62Slukem __RCSID("$NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $");
397307c9a9Slukem #endif
407307c9a9Slukem
417307c9a9Slukem #include <sys/types.h>
427307c9a9Slukem
4342f1aa04Slukem #include <stdio.h>
4442f1aa04Slukem #include <stdlib.h>
4542f1aa04Slukem #include <string.h>
467307c9a9Slukem
4742f1aa04Slukem #include "hash.h"
4842f1aa04Slukem
493a0b8f6eSwiz u_int32_t hash(const void *, size_t);
503a0b8f6eSwiz u_int32_t hashkey(const char *);
517307c9a9Slukem
5242f1aa04Slukem
5342f1aa04Slukem /*
5442f1aa04Slukem * This hash function is stolen directly from the
5542f1aa04Slukem * Berkeley DB package. It already exists inside libc, but
5642f1aa04Slukem * it's declared static which prevents us from calling it
5742f1aa04Slukem * from here.
5842f1aa04Slukem */
597307c9a9Slukem
6042f1aa04Slukem /*
6142f1aa04Slukem * OZ's original sdbm hash
6242f1aa04Slukem */
6342f1aa04Slukem u_int32_t
hash(const void * keyarg,size_t len)643a0b8f6eSwiz hash(const void *keyarg, size_t len)
6542f1aa04Slukem {
667307c9a9Slukem const u_char *key;
677307c9a9Slukem size_t loop;
687307c9a9Slukem u_int32_t h;
6942f1aa04Slukem
7042f1aa04Slukem #define HASHC h = *key++ + 65599 * h
7142f1aa04Slukem
7242f1aa04Slukem h = 0;
7342f1aa04Slukem key = keyarg;
7442f1aa04Slukem if (len > 0) {
7542f1aa04Slukem loop = (len + 8 - 1) >> 3;
7642f1aa04Slukem
7742f1aa04Slukem switch (len & (8 - 1)) {
7842f1aa04Slukem case 0:
7942f1aa04Slukem do {
8042f1aa04Slukem HASHC;
8142f1aa04Slukem /* FALLTHROUGH */
8242f1aa04Slukem case 7:
8342f1aa04Slukem HASHC;
8442f1aa04Slukem /* FALLTHROUGH */
8542f1aa04Slukem case 6:
8642f1aa04Slukem HASHC;
8742f1aa04Slukem /* FALLTHROUGH */
8842f1aa04Slukem case 5:
8942f1aa04Slukem HASHC;
9042f1aa04Slukem /* FALLTHROUGH */
9142f1aa04Slukem case 4:
9242f1aa04Slukem HASHC;
9342f1aa04Slukem /* FALLTHROUGH */
9442f1aa04Slukem case 3:
9542f1aa04Slukem HASHC;
9642f1aa04Slukem /* FALLTHROUGH */
9742f1aa04Slukem case 2:
9842f1aa04Slukem HASHC;
9942f1aa04Slukem /* FALLTHROUGH */
10042f1aa04Slukem case 1:
10142f1aa04Slukem HASHC;
10242f1aa04Slukem } while (--loop);
10342f1aa04Slukem }
10442f1aa04Slukem }
10542f1aa04Slukem return (h);
10642f1aa04Slukem }
10742f1aa04Slukem
10842f1aa04Slukem /*
10942f1aa04Slukem * Generate a hash value for a given key (character string).
11042f1aa04Slukem * We mask off all but the lower 8 bits since our table array
11142f1aa04Slukem * can only hold 256 elements.
11242f1aa04Slukem */
1137307c9a9Slukem u_int32_t
hashkey(const char * key)1143a0b8f6eSwiz hashkey(const char *key)
11542f1aa04Slukem {
11642f1aa04Slukem
11742f1aa04Slukem if (key == NULL)
11842f1aa04Slukem return (-1);
119*d3d3aa62Slukem return(hash((const void *)key, strlen(key)) & HASH_MASK);
12042f1aa04Slukem }
12142f1aa04Slukem
12242f1aa04Slukem /* Find an entry in the hash table (may be hanging off a linked list). */
1237307c9a9Slukem char *
lookup(struct group_entry ** table,const char * key)1243a0b8f6eSwiz lookup(struct group_entry **table, const char *key)
12542f1aa04Slukem {
12642f1aa04Slukem struct group_entry *cur;
12742f1aa04Slukem
12842f1aa04Slukem cur = table[hashkey(key)];
12942f1aa04Slukem
13042f1aa04Slukem while (cur) {
13142f1aa04Slukem if (!strcmp(cur->key, key))
13242f1aa04Slukem return(cur->data);
13342f1aa04Slukem cur = cur->next;
13442f1aa04Slukem }
13542f1aa04Slukem
13642f1aa04Slukem return(NULL);
13742f1aa04Slukem }
13842f1aa04Slukem
13942f1aa04Slukem /*
14042f1aa04Slukem * Store an entry in the main netgroup hash table. Here's how this
14142f1aa04Slukem * works: the table can only be so big when we initialize it (TABLESIZE)
14242f1aa04Slukem * but the number of netgroups in the /etc/netgroup file could easily be
14342f1aa04Slukem * much larger than the table. Since our hash values are adjusted to
14442f1aa04Slukem * never be greater than TABLESIZE too, this means it won't be long before
14542f1aa04Slukem * we find ourselves with two keys that hash to the same value.
14642f1aa04Slukem *
14742f1aa04Slukem * One way to deal with this is to malloc(2) a second table and start
14842f1aa04Slukem * doing indirection, but this is a pain in the butt and it's not worth
14942f1aa04Slukem * going to all that trouble for a dinky little program like this. Instead,
15042f1aa04Slukem * we turn each table entry into a linked list and simply link keys
15142f1aa04Slukem * with the same hash value together at the same index location within
15242f1aa04Slukem * the table.
15342f1aa04Slukem *
15442f1aa04Slukem * That's a lot of comment for such a small piece of code, isn't it.
15542f1aa04Slukem */
1567307c9a9Slukem void
store(struct group_entry * table[],const char * key,const char * data)1573a0b8f6eSwiz store(struct group_entry *table[], const char *key, const char *data)
15842f1aa04Slukem {
15942f1aa04Slukem struct group_entry *new;
16042f1aa04Slukem u_int32_t i;
16142f1aa04Slukem
16242f1aa04Slukem i = hashkey(key);
16342f1aa04Slukem
16442f1aa04Slukem new = (struct group_entry *)malloc(sizeof(struct group_entry));
16542f1aa04Slukem new->key = strdup(key);
16642f1aa04Slukem new->data = strdup(data);
16742f1aa04Slukem new->next = table[i];
16842f1aa04Slukem table[i] = new;
16942f1aa04Slukem
17042f1aa04Slukem return;
17142f1aa04Slukem }
17242f1aa04Slukem
17342f1aa04Slukem /*
17442f1aa04Slukem * Store a group member entry and/or update its grouplist. This is
17542f1aa04Slukem * a bit more complicated than the previous function since we have to
17642f1aa04Slukem * maintain not only the hash table of group members, each group member
17742f1aa04Slukem * structure also has a linked list of groups hung off it. If handed
17842f1aa04Slukem * a member name that we haven't encountered before, we have to do
17942f1aa04Slukem * two things: add that member to the table (possibly hanging them
18042f1aa04Slukem * off the end of a linked list, as above), and add a group name to
18142f1aa04Slukem * the member's grouplist list. If we're handed a name that already has
18242f1aa04Slukem * an entry in the table, then we just have to do one thing, which is
18342f1aa04Slukem * to update its grouplist.
18442f1aa04Slukem */
1857307c9a9Slukem void
mstore(struct member_entry * table[],const char * key,const char * data,const char * domain)1863a0b8f6eSwiz mstore(struct member_entry *table[], const char *key, const char *data,
1873a0b8f6eSwiz const char *domain)
18842f1aa04Slukem {
18942f1aa04Slukem struct member_entry *cur, *new;
19042f1aa04Slukem struct grouplist *tmp,*p;
19142f1aa04Slukem u_int32_t i;
19242f1aa04Slukem
19342f1aa04Slukem i = hashkey(key);
19442f1aa04Slukem cur = table[i];
19542f1aa04Slukem
19642f1aa04Slukem tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
19742f1aa04Slukem tmp->groupname = strdup(data);
19842f1aa04Slukem tmp->next = NULL;
19942f1aa04Slukem
20042f1aa04Slukem /* Check if all we have to do is insert a new groupname. */
20142f1aa04Slukem while (cur) {
20242f1aa04Slukem if (!strcmp(cur->key, key) && !strcmp(cur->domain,domain)) {
20342f1aa04Slukem p = cur->groups;
20442f1aa04Slukem while(p) {
205d6638342Sbouyer if (!strcmp(p->groupname,data)) {
206d6638342Sbouyer /* group already there */
207d6638342Sbouyer free(tmp);
20842f1aa04Slukem return;
209d6638342Sbouyer }
21042f1aa04Slukem p = p->next;
21142f1aa04Slukem }
21242f1aa04Slukem tmp->next = cur->groups;
21342f1aa04Slukem cur->groups = tmp;
21442f1aa04Slukem return;
21542f1aa04Slukem }
21642f1aa04Slukem cur = cur->next;
21742f1aa04Slukem }
21842f1aa04Slukem
21942f1aa04Slukem /* Didn't find a match -- add the whole mess to the table. */
22042f1aa04Slukem new = (struct member_entry *)malloc(sizeof(struct member_entry));
22142f1aa04Slukem new->key = strdup(key);
22242f1aa04Slukem new->domain = strdup(domain);
22342f1aa04Slukem new->groups = tmp;
22442f1aa04Slukem new->next = table[i];
22542f1aa04Slukem table[i] = new;
22642f1aa04Slukem
22742f1aa04Slukem return;
22842f1aa04Slukem }
229