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