hash.c revision 1.2 1 1.2 lukem /* $NetBSD: hash.c,v 1.2 1997/10/06 06:54:11 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.2 lukem __RCSID("$NetBSD: hash.c,v 1.2 1997/10/06 06:54:11 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.2 lukem u_int32_t hash __P((const void *, size_t));
50 1.2 lukem u_int32_t hashkey __P((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.1 lukem hash(keyarg, len)
65 1.1 lukem const void *keyarg;
66 1.2 lukem size_t len;
67 1.1 lukem {
68 1.2 lukem const u_char *key;
69 1.2 lukem size_t loop;
70 1.2 lukem u_int32_t h;
71 1.1 lukem
72 1.1 lukem #define HASHC h = *key++ + 65599 * h
73 1.1 lukem
74 1.1 lukem h = 0;
75 1.1 lukem key = keyarg;
76 1.1 lukem if (len > 0) {
77 1.1 lukem loop = (len + 8 - 1) >> 3;
78 1.1 lukem
79 1.1 lukem switch (len & (8 - 1)) {
80 1.1 lukem case 0:
81 1.1 lukem do {
82 1.1 lukem HASHC;
83 1.1 lukem /* FALLTHROUGH */
84 1.1 lukem case 7:
85 1.1 lukem HASHC;
86 1.1 lukem /* FALLTHROUGH */
87 1.1 lukem case 6:
88 1.1 lukem HASHC;
89 1.1 lukem /* FALLTHROUGH */
90 1.1 lukem case 5:
91 1.1 lukem HASHC;
92 1.1 lukem /* FALLTHROUGH */
93 1.1 lukem case 4:
94 1.1 lukem HASHC;
95 1.1 lukem /* FALLTHROUGH */
96 1.1 lukem case 3:
97 1.1 lukem HASHC;
98 1.1 lukem /* FALLTHROUGH */
99 1.1 lukem case 2:
100 1.1 lukem HASHC;
101 1.1 lukem /* FALLTHROUGH */
102 1.1 lukem case 1:
103 1.1 lukem HASHC;
104 1.1 lukem } while (--loop);
105 1.1 lukem }
106 1.1 lukem }
107 1.1 lukem return (h);
108 1.1 lukem }
109 1.1 lukem
110 1.1 lukem /*
111 1.1 lukem * Generate a hash value for a given key (character string).
112 1.1 lukem * We mask off all but the lower 8 bits since our table array
113 1.1 lukem * can only hold 256 elements.
114 1.1 lukem */
115 1.2 lukem u_int32_t
116 1.2 lukem hashkey(key)
117 1.2 lukem const char *key;
118 1.1 lukem {
119 1.1 lukem
120 1.1 lukem if (key == NULL)
121 1.1 lukem return (-1);
122 1.1 lukem return(hash((void *)key, strlen(key)) & HASH_MASK);
123 1.1 lukem }
124 1.1 lukem
125 1.1 lukem /* Find an entry in the hash table (may be hanging off a linked list). */
126 1.2 lukem char *
127 1.2 lukem lookup(table, key)
128 1.1 lukem struct group_entry *table[];
129 1.2 lukem const char *key;
130 1.1 lukem {
131 1.1 lukem struct group_entry *cur;
132 1.1 lukem
133 1.1 lukem cur = table[hashkey(key)];
134 1.1 lukem
135 1.1 lukem while (cur) {
136 1.1 lukem if (!strcmp(cur->key, key))
137 1.1 lukem return(cur->data);
138 1.1 lukem cur = cur->next;
139 1.1 lukem }
140 1.1 lukem
141 1.1 lukem return(NULL);
142 1.1 lukem }
143 1.1 lukem
144 1.1 lukem /*
145 1.1 lukem * Store an entry in the main netgroup hash table. Here's how this
146 1.1 lukem * works: the table can only be so big when we initialize it (TABLESIZE)
147 1.1 lukem * but the number of netgroups in the /etc/netgroup file could easily be
148 1.1 lukem * much larger than the table. Since our hash values are adjusted to
149 1.1 lukem * never be greater than TABLESIZE too, this means it won't be long before
150 1.1 lukem * we find ourselves with two keys that hash to the same value.
151 1.1 lukem *
152 1.1 lukem * One way to deal with this is to malloc(2) a second table and start
153 1.1 lukem * doing indirection, but this is a pain in the butt and it's not worth
154 1.1 lukem * going to all that trouble for a dinky little program like this. Instead,
155 1.1 lukem * we turn each table entry into a linked list and simply link keys
156 1.1 lukem * with the same hash value together at the same index location within
157 1.1 lukem * the table.
158 1.1 lukem *
159 1.1 lukem * That's a lot of comment for such a small piece of code, isn't it.
160 1.1 lukem */
161 1.2 lukem void
162 1.2 lukem store(table, key, data)
163 1.1 lukem struct group_entry *table[];
164 1.2 lukem const char *key, *data;
165 1.1 lukem {
166 1.1 lukem struct group_entry *new;
167 1.1 lukem u_int32_t i;
168 1.1 lukem
169 1.1 lukem i = hashkey(key);
170 1.1 lukem
171 1.1 lukem new = (struct group_entry *)malloc(sizeof(struct group_entry));
172 1.1 lukem new->key = strdup(key);
173 1.1 lukem new->data = strdup(data);
174 1.1 lukem new->next = table[i];
175 1.1 lukem table[i] = new;
176 1.1 lukem
177 1.1 lukem return;
178 1.1 lukem }
179 1.1 lukem
180 1.1 lukem /*
181 1.1 lukem * Store a group member entry and/or update its grouplist. This is
182 1.1 lukem * a bit more complicated than the previous function since we have to
183 1.1 lukem * maintain not only the hash table of group members, each group member
184 1.1 lukem * structure also has a linked list of groups hung off it. If handed
185 1.1 lukem * a member name that we haven't encountered before, we have to do
186 1.1 lukem * two things: add that member to the table (possibly hanging them
187 1.1 lukem * off the end of a linked list, as above), and add a group name to
188 1.1 lukem * the member's grouplist list. If we're handed a name that already has
189 1.1 lukem * an entry in the table, then we just have to do one thing, which is
190 1.1 lukem * to update its grouplist.
191 1.1 lukem */
192 1.2 lukem void
193 1.2 lukem mstore(table, key, data, domain)
194 1.1 lukem struct member_entry *table[];
195 1.2 lukem const char *key, *data, *domain;
196 1.1 lukem {
197 1.1 lukem struct member_entry *cur, *new;
198 1.1 lukem struct grouplist *tmp,*p;
199 1.1 lukem u_int32_t i;
200 1.1 lukem
201 1.1 lukem i = hashkey(key);
202 1.1 lukem cur = table[i];
203 1.1 lukem
204 1.1 lukem tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
205 1.1 lukem tmp->groupname = strdup(data);
206 1.1 lukem tmp->next = NULL;
207 1.1 lukem
208 1.1 lukem /* Check if all we have to do is insert a new groupname. */
209 1.1 lukem while (cur) {
210 1.1 lukem if (!strcmp(cur->key, key) && !strcmp(cur->domain,domain)) {
211 1.1 lukem p = cur->groups;
212 1.1 lukem while(p) {
213 1.1 lukem if (!strcmp(p->groupname,data))
214 1.1 lukem return;
215 1.1 lukem p = p->next;
216 1.1 lukem }
217 1.1 lukem tmp->next = cur->groups;
218 1.1 lukem cur->groups = tmp;
219 1.1 lukem return;
220 1.1 lukem }
221 1.1 lukem cur = cur->next;
222 1.1 lukem }
223 1.1 lukem
224 1.1 lukem /* Didn't find a match -- add the whole mess to the table. */
225 1.1 lukem new = (struct member_entry *)malloc(sizeof(struct member_entry));
226 1.1 lukem new->key = strdup(key);
227 1.1 lukem new->domain = strdup(domain);
228 1.1 lukem new->groups = tmp;
229 1.1 lukem new->next = table[i];
230 1.1 lukem table[i] = new;
231 1.1 lukem
232 1.1 lukem return;
233 1.1 lukem }
234