hash.c revision 1.5 1 1.5 lukem /* $NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $ */
2 1.2 lukem
3 1.1 lukem /*
4 1.1 lukem * Copyright (c) 1995
5 1.1 lukem * Bill Paul <wpaul (at) ctr.columbia.edu>. All rights reserved.
6 1.1 lukem *
7 1.1 lukem * Redistribution and use in source and binary forms, with or without
8 1.1 lukem * modification, are permitted provided that the following conditions
9 1.1 lukem * are met:
10 1.1 lukem * 1. Redistributions of source code must retain the above copyright
11 1.1 lukem * notice, this list of conditions and the following disclaimer.
12 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 lukem * notice, this list of conditions and the following disclaimer in the
14 1.1 lukem * documentation and/or other materials provided with the distribution.
15 1.1 lukem * 3. All advertising materials mentioning features or use of this software
16 1.1 lukem * must display the following acknowledgement:
17 1.1 lukem * This product includes software developed by Bill Paul.
18 1.1 lukem * 4. Neither the name of the author nor the names of any co-contributors
19 1.1 lukem * may be used to endorse or promote products derived from this software
20 1.1 lukem * without specific prior written permission.
21 1.1 lukem *
22 1.1 lukem * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 1.1 lukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 lukem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 lukem * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
26 1.1 lukem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 lukem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 lukem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 lukem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 lukem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 lukem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 lukem * SUCH DAMAGE.
33 1.1 lukem *
34 1.1 lukem */
35 1.1 lukem
36 1.2 lukem #include <sys/cdefs.h>
37 1.2 lukem #ifndef lint
38 1.5 lukem __RCSID("$NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $");
39 1.2 lukem #endif
40 1.2 lukem
41 1.2 lukem #include <sys/types.h>
42 1.2 lukem
43 1.1 lukem #include <stdio.h>
44 1.1 lukem #include <stdlib.h>
45 1.1 lukem #include <string.h>
46 1.2 lukem
47 1.1 lukem #include "hash.h"
48 1.1 lukem
49 1.3 wiz u_int32_t hash(const void *, size_t);
50 1.3 wiz u_int32_t hashkey(const char *);
51 1.2 lukem
52 1.1 lukem
53 1.1 lukem /*
54 1.1 lukem * This hash function is stolen directly from the
55 1.1 lukem * Berkeley DB package. It already exists inside libc, but
56 1.1 lukem * it's declared static which prevents us from calling it
57 1.1 lukem * from here.
58 1.1 lukem */
59 1.2 lukem
60 1.1 lukem /*
61 1.1 lukem * OZ's original sdbm hash
62 1.1 lukem */
63 1.1 lukem u_int32_t
64 1.3 wiz hash(const void *keyarg, size_t len)
65 1.1 lukem {
66 1.2 lukem const u_char *key;
67 1.2 lukem size_t loop;
68 1.2 lukem u_int32_t h;
69 1.1 lukem
70 1.1 lukem #define HASHC h = *key++ + 65599 * h
71 1.1 lukem
72 1.1 lukem h = 0;
73 1.1 lukem key = keyarg;
74 1.1 lukem if (len > 0) {
75 1.1 lukem loop = (len + 8 - 1) >> 3;
76 1.1 lukem
77 1.1 lukem switch (len & (8 - 1)) {
78 1.1 lukem case 0:
79 1.1 lukem do {
80 1.1 lukem HASHC;
81 1.1 lukem /* FALLTHROUGH */
82 1.1 lukem case 7:
83 1.1 lukem HASHC;
84 1.1 lukem /* FALLTHROUGH */
85 1.1 lukem case 6:
86 1.1 lukem HASHC;
87 1.1 lukem /* FALLTHROUGH */
88 1.1 lukem case 5:
89 1.1 lukem HASHC;
90 1.1 lukem /* FALLTHROUGH */
91 1.1 lukem case 4:
92 1.1 lukem HASHC;
93 1.1 lukem /* FALLTHROUGH */
94 1.1 lukem case 3:
95 1.1 lukem HASHC;
96 1.1 lukem /* FALLTHROUGH */
97 1.1 lukem case 2:
98 1.1 lukem HASHC;
99 1.1 lukem /* FALLTHROUGH */
100 1.1 lukem case 1:
101 1.1 lukem HASHC;
102 1.1 lukem } while (--loop);
103 1.1 lukem }
104 1.1 lukem }
105 1.1 lukem return (h);
106 1.1 lukem }
107 1.1 lukem
108 1.1 lukem /*
109 1.1 lukem * Generate a hash value for a given key (character string).
110 1.1 lukem * We mask off all but the lower 8 bits since our table array
111 1.1 lukem * can only hold 256 elements.
112 1.1 lukem */
113 1.2 lukem u_int32_t
114 1.3 wiz hashkey(const char *key)
115 1.1 lukem {
116 1.1 lukem
117 1.1 lukem if (key == NULL)
118 1.1 lukem return (-1);
119 1.5 lukem return(hash((const void *)key, strlen(key)) & HASH_MASK);
120 1.1 lukem }
121 1.1 lukem
122 1.1 lukem /* Find an entry in the hash table (may be hanging off a linked list). */
123 1.2 lukem char *
124 1.3 wiz lookup(struct group_entry **table, const char *key)
125 1.1 lukem {
126 1.1 lukem struct group_entry *cur;
127 1.1 lukem
128 1.1 lukem cur = table[hashkey(key)];
129 1.1 lukem
130 1.1 lukem while (cur) {
131 1.1 lukem if (!strcmp(cur->key, key))
132 1.1 lukem return(cur->data);
133 1.1 lukem cur = cur->next;
134 1.1 lukem }
135 1.1 lukem
136 1.1 lukem return(NULL);
137 1.1 lukem }
138 1.1 lukem
139 1.1 lukem /*
140 1.1 lukem * Store an entry in the main netgroup hash table. Here's how this
141 1.1 lukem * works: the table can only be so big when we initialize it (TABLESIZE)
142 1.1 lukem * but the number of netgroups in the /etc/netgroup file could easily be
143 1.1 lukem * much larger than the table. Since our hash values are adjusted to
144 1.1 lukem * never be greater than TABLESIZE too, this means it won't be long before
145 1.1 lukem * we find ourselves with two keys that hash to the same value.
146 1.1 lukem *
147 1.1 lukem * One way to deal with this is to malloc(2) a second table and start
148 1.1 lukem * doing indirection, but this is a pain in the butt and it's not worth
149 1.1 lukem * going to all that trouble for a dinky little program like this. Instead,
150 1.1 lukem * we turn each table entry into a linked list and simply link keys
151 1.1 lukem * with the same hash value together at the same index location within
152 1.1 lukem * the table.
153 1.1 lukem *
154 1.1 lukem * That's a lot of comment for such a small piece of code, isn't it.
155 1.1 lukem */
156 1.2 lukem void
157 1.3 wiz store(struct group_entry *table[], const char *key, const char *data)
158 1.1 lukem {
159 1.1 lukem struct group_entry *new;
160 1.1 lukem u_int32_t i;
161 1.1 lukem
162 1.1 lukem i = hashkey(key);
163 1.1 lukem
164 1.1 lukem new = (struct group_entry *)malloc(sizeof(struct group_entry));
165 1.1 lukem new->key = strdup(key);
166 1.1 lukem new->data = strdup(data);
167 1.1 lukem new->next = table[i];
168 1.1 lukem table[i] = new;
169 1.1 lukem
170 1.1 lukem return;
171 1.1 lukem }
172 1.1 lukem
173 1.1 lukem /*
174 1.1 lukem * Store a group member entry and/or update its grouplist. This is
175 1.1 lukem * a bit more complicated than the previous function since we have to
176 1.1 lukem * maintain not only the hash table of group members, each group member
177 1.1 lukem * structure also has a linked list of groups hung off it. If handed
178 1.1 lukem * a member name that we haven't encountered before, we have to do
179 1.1 lukem * two things: add that member to the table (possibly hanging them
180 1.1 lukem * off the end of a linked list, as above), and add a group name to
181 1.1 lukem * the member's grouplist list. If we're handed a name that already has
182 1.1 lukem * an entry in the table, then we just have to do one thing, which is
183 1.1 lukem * to update its grouplist.
184 1.1 lukem */
185 1.2 lukem void
186 1.3 wiz mstore(struct member_entry *table[], const char *key, const char *data,
187 1.3 wiz const char *domain)
188 1.1 lukem {
189 1.1 lukem struct member_entry *cur, *new;
190 1.1 lukem struct grouplist *tmp,*p;
191 1.1 lukem u_int32_t i;
192 1.1 lukem
193 1.1 lukem i = hashkey(key);
194 1.1 lukem cur = table[i];
195 1.1 lukem
196 1.1 lukem tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
197 1.1 lukem tmp->groupname = strdup(data);
198 1.1 lukem tmp->next = NULL;
199 1.1 lukem
200 1.1 lukem /* Check if all we have to do is insert a new groupname. */
201 1.1 lukem while (cur) {
202 1.1 lukem if (!strcmp(cur->key, key) && !strcmp(cur->domain,domain)) {
203 1.1 lukem p = cur->groups;
204 1.1 lukem while(p) {
205 1.4 bouyer if (!strcmp(p->groupname,data)) {
206 1.4 bouyer /* group already there */
207 1.4 bouyer free(tmp);
208 1.1 lukem return;
209 1.4 bouyer }
210 1.1 lukem p = p->next;
211 1.1 lukem }
212 1.1 lukem tmp->next = cur->groups;
213 1.1 lukem cur->groups = tmp;
214 1.1 lukem return;
215 1.1 lukem }
216 1.1 lukem cur = cur->next;
217 1.1 lukem }
218 1.1 lukem
219 1.1 lukem /* Didn't find a match -- add the whole mess to the table. */
220 1.1 lukem new = (struct member_entry *)malloc(sizeof(struct member_entry));
221 1.1 lukem new->key = strdup(key);
222 1.1 lukem new->domain = strdup(domain);
223 1.1 lukem new->groups = tmp;
224 1.1 lukem new->next = table[i];
225 1.1 lukem table[i] = new;
226 1.1 lukem
227 1.1 lukem return;
228 1.1 lukem }
229