/[hydra]/hydra/src/hash.c
ViewVC logotype

Annotation of /hydra/src/hash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations)
Mon Oct 21 20:33:31 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_0_10, hydra_0_0_8, hydra_0_0_9, hydra_0_1_3, hydra_0_1_2, hydra_0_1_1, hydra_0_1_0, hydra_0_1_7, hydra_0_1_6, hydra_0_1_4, hydra_0_1_8, HEAD
Branch point for: hydra_0_1_0_patches
Changes since 1.3: +186 -146 lines
File MIME type: text/plain
Removed some optimizations from Boa, that made the code harder
to read. Added the hash.c from Boa.

1 nmav 1.1 /*
2 nmav 1.4 * Boa, an http server
3 nmav 1.1 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4     * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
5     * Some changes Copyright (C) 1997 Jon Nelson <jnelson@boa.org>
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 1, or (at your option)
10     * any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20     *
21     */
22    
23 nmav 1.4 /* $Id: hash.c,v 1.14.4.7 2002/09/23 03:44:08 jnelson Exp $*/
24 nmav 1.1
25     #include "boa.h"
26     #include "parse.h"
27    
28 nmav 1.4 #define DEBUG if
29     #define DEBUG_HASH 0
30    
31 nmav 1.1 /*
32     * There are two hash tables used, each with a key/value pair
33     * stored in a hash_struct. They are:
34     *
35     * mime_hashtable:
36     * key = file extension
37     * value = mime type
38     *
39     * passwd_hashtable:
40     * key = username
41     * value = home directory
42     *
43     */
44    
45     struct _hash_struct_ {
46     char *key;
47     char *value;
48     struct _hash_struct_ *next;
49     };
50    
51     typedef struct _hash_struct_ hash_struct;
52    
53     static hash_struct *mime_hashtable[MIME_HASHTABLE_SIZE];
54     static hash_struct *passwd_hashtable[PASSWD_HASHTABLE_SIZE];
55    
56     #ifdef WANT_ICKY_HASH
57 nmav 1.4 static unsigned four_char_hash(const char *buf);
58     #define boa_hash four_char_hash
59     #else
60     #ifdef WANT_SDBM_HASH
61     static unsigned sdbm_hash(const char *str);
62     #define boa_hash sdbm_hash
63     #else
64     #ifdef WANT_DJB2_HASH
65     static unsigned djb2_hash(const char *str);
66     #define boa_hash djb2_hash
67     #else
68     static unsigned fnv1a_hash(const char *str);
69     #define boa_hash fnv1a_hash
70     #endif
71     #endif
72 nmav 1.1 #endif
73    
74     #ifdef WANT_ICKY_HASH
75 nmav 1.4 static unsigned four_char_hash(const char *buf)
76 nmav 1.1 {
77     unsigned int hash = (buf[0] +
78 nmav 1.4 (buf[1] ? buf[1] : 241 +
79     (buf[2] ? buf[2] : 251 +
80     (buf[3] ? buf[3] : 257))));
81     DEBUG(DEBUG_HASH) {
82     log_error_time();
83     fprintf(stderr, "four_char_hash(%s) = %u\n", buf, hash);
84     }
85 nmav 1.1 return hash;
86     }
87    
88     /* The next two hashes taken from
89     * http://www.cs.yorku.ca/~oz/hash.html
90     *
91     * In my (admittedly) very brief testing, djb2_hash performed
92     * very slightly better than sdbm_hash.
93     */
94    
95     #else
96     #define MAX_HASH_LENGTH 4
97     #ifdef WANT_SDBM_HASH
98 nmav 1.4 static unsigned sdbm_hash(const char *str)
99 nmav 1.1 {
100     unsigned hash = 0;
101     int c;
102     short count = MAX_HASH_LENGTH;
103    
104 nmav 1.4 DEBUG(DEBUG_HASH) {
105     log_error_time();
106     fprintf(stderr, "sdbm_hash(%s) = ", str);
107     }
108 nmav 1.1
109     while ((c = *str++) && count--)
110     hash = c + (hash << 6) + (hash << 16) - hash;
111    
112 nmav 1.4 DEBUG(DEBUG_HASH) {
113     fprintf(stderr, "%u\n", hash);
114     }
115 nmav 1.1 return hash;
116     }
117     #else
118 nmav 1.4 #ifdef WANT_DJB2_HASH
119     static unsigned djb2_hash(const char *str)
120 nmav 1.1 {
121     unsigned hash = 5381;
122     int c;
123     short count = MAX_HASH_LENGTH;
124    
125 nmav 1.4 DEBUG(DEBUG_HASH) {
126     log_error_time();
127     fprintf(stderr, "djb2_hash(%s) = ", str);
128     }
129 nmav 1.1
130     while ((c = *(str++)) && count--)
131     hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
132    
133 nmav 1.4 DEBUG(DEBUG_HASH) {
134     fprintf(stderr, "%u\n", hash);
135     }
136 nmav 1.1 return hash;
137     }
138 nmav 1.4 #else
139     /*
140     * magic 32 bit FNV1a hash constants
141     *
142     * See: http://www.isthe.com/chongo/tech/comp/fnv/index.html
143     */
144     #define OFFSET_BASIS 2166136261U
145     #define FNV_PRIME 16777619U
146     static unsigned fnv1a_hash(const char *str)
147     {
148     unsigned int hash = OFFSET_BASIS;
149     short count = MAX_HASH_LENGTH;
150    
151     /*
152     * compute FNV1a hash of the first file component
153     */
154     do {
155     hash ^= *str++;
156     hash *= FNV_PRIME;
157     } while (*str != '\0' && count--);
158    
159     return hash;
160     }
161    
162     #endif
163 nmav 1.1 #endif
164     #endif
165    
166     /*
167 nmav 1.4 * Name: hash_insert
168     * Description: Adds a key/value pair to the provided hashtable
169 nmav 1.1 */
170    
171 nmav 1.4 static
172     hash_struct *hash_insert(hash_struct *table[], unsigned int hash, char *key, char *value)
173 nmav 1.1 {
174 nmav 1.4 hash_struct *current, *trailer;
175 nmav 1.1
176 nmav 1.4 if (!key) {
177     log_error_time();
178     fprintf(stderr, "Yipes! Null value sent as key to hash_insert!\n");
179     return NULL;
180     }
181 nmav 1.1
182 nmav 1.4 /* should we bother to check table, hash, and key for NULL/0 ? */
183 nmav 1.1
184 nmav 1.4 DEBUG(DEBUG_HASH)
185     fprintf(stderr,
186     "Adding key \"%s\" for value \"%s\" (hash=%d)\n",
187     key, value, hash);
188 nmav 1.1
189 nmav 1.4 current = table[hash];
190 nmav 1.1 while (current) {
191 nmav 1.4 if (!strcmp(current->key, key))
192     return current; /* don't add extension twice */
193 nmav 1.1 if (current->next)
194     current = current->next;
195     else
196     break;
197     }
198    
199 nmav 1.4 /* not found */
200     trailer = (hash_struct *) malloc(sizeof (hash_struct));
201     if (trailer == NULL) {
202     WARN("unable to allocate memory for hash_insert");
203     return NULL;
204     }
205    
206     trailer->key = strdup(key);
207     trailer->value = strdup(value);
208     trailer->next = NULL;
209    
210     if (trailer->key == NULL || trailer->value == NULL) {
211     free(trailer);
212     if (trailer->key)
213     free(trailer->key);
214     if (trailer->value)
215     free(trailer->value);
216     WARN("allocated key or value is NULL");
217     return NULL;
218     }
219 nmav 1.1
220 nmav 1.4 /* successfully allocated and built new hash structure */
221 nmav 1.1 if (!current) {
222 nmav 1.4 /* no entries for this hash value */
223     table[hash] = trailer;
224 nmav 1.1 } else {
225 nmav 1.4 current->next = trailer;
226 nmav 1.1 }
227 nmav 1.4
228     return trailer;
229     }
230    
231     static
232     hash_struct *find_in_hash(hash_struct *table[], char *key, unsigned int hash)
233     {
234     hash_struct *current;
235    
236     current = table[hash];
237    
238     while (current) {
239     if (!strcmp(current->key, key)) /* hit */
240     return current;
241     current = current->next;
242     }
243    
244     return NULL;
245     }
246    
247     /*
248     * Name: add_mime_type
249     * Description: Adds a key/value pair to the mime_hashtable
250     */
251    
252     void add_mime_type(char *extension, char *type)
253     {
254     unsigned int hash;
255    
256     if (!extension || extension[0] == '\0') {
257     log_error_time();
258     fprintf(stderr, "Yipes! Null value sent as key to add_mime_type!\n");
259     return;
260     }
261    
262     hash = get_mime_hash_value(extension);
263     hash_insert(mime_hashtable, hash, extension, type);
264 nmav 1.1 }
265    
266     /*
267     * Name: get_mime_hash_value
268     *
269     * Description: adds the ASCII values of the file extension letters
270     * and mods by the hashtable size to get the hash value
271     */
272    
273     unsigned get_mime_hash_value(char *extension)
274     {
275     if (extension == NULL || extension[0] == '\0') {
276     /* FIXME */
277     log_error_time();
278 nmav 1.4 fprintf(stderr, "Attempt to hash NULL or empty string! [get_mime_hash_value]!\n");
279 nmav 1.1 return 0;
280     }
281    
282 nmav 1.4 return boa_hash(extension) % MIME_HASHTABLE_SIZE;
283 nmav 1.1 }
284    
285     /*
286     * Name: get_mime_type
287     *
288     * Description: Returns the mime type for a supplied filename.
289     * Returns default type if not found.
290     */
291    
292 nmav 1.2 char *get_mime_type(const char *filename)
293 nmav 1.1 {
294     char *extension;
295     hash_struct *current;
296    
297     unsigned int hash;
298    
299     extension = strrchr(filename, '.');
300    
301 nmav 1.4 /* remember, extension points to the *last* '.' in the filename,
302     * which may be NULL or look like:
303     * foo.bar
304     * foo. (in which case extension[1] == '\0')
305     */
306     if (!extension || extension[1] == '\0')
307 nmav 1.1 return default_type;
308    
309 nmav 1.4 /* make sure we hash on the 'bar' not the '.bar' */
310     ++extension;
311    
312 nmav 1.1 hash = get_mime_hash_value(extension);
313 nmav 1.4 current = find_in_hash(mime_hashtable, extension, hash);
314     return (current ? current->value : default_type);
315 nmav 1.1 }
316    
317     /*
318     * Name: get_homedir_hash_value
319     *
320     * Description: adds the ASCII values of the username letters
321     * and mods by the hashtable size to get the hash value
322     */
323    
324     unsigned get_homedir_hash_value(char *name)
325     {
326     unsigned int hash = 0;
327    
328     if (name == NULL || name[0] == '\0') {
329     /* FIXME */
330     log_error_time();
331 nmav 1.4 fprintf(stderr, "Attempt to hash NULL or empty string! [get_homedir_hash_value]\n");
332 nmav 1.1 return 0;
333     }
334    
335 nmav 1.4 hash = boa_hash(name) % PASSWD_HASHTABLE_SIZE;
336 nmav 1.1
337     return hash;
338     }
339    
340    
341     /*
342     * Name: get_home_dir
343     *
344     * Description: Returns a point to the supplied user's home directory.
345     * Adds to the hashtable if it's not already present.
346     *
347     */
348    
349     char *get_home_dir(char *name)
350     {
351 nmav 1.4 hash_struct *current;
352 nmav 1.1
353     unsigned int hash;
354    
355     hash = get_homedir_hash_value(name);
356    
357 nmav 1.4 current = find_in_hash(passwd_hashtable, name, hash);
358 nmav 1.1
359 nmav 1.4 if (!current) {
360     /* not found */
361     struct passwd *passwdbuf;
362 nmav 1.1
363 nmav 1.4 passwdbuf = getpwnam(name);
364 nmav 1.1
365 nmav 1.4 if (!passwdbuf) /* does not exist */
366     return NULL;
367 nmav 1.1
368 nmav 1.4 current = hash_insert(passwd_hashtable, hash, name, passwdbuf->pw_dir);
369 nmav 1.1 }
370    
371 nmav 1.4 return (current ? current->value : NULL);
372 nmav 1.1 }
373    
374 nmav 1.4 static
375     void clear_hashtable(hash_struct *table[], int size)
376 nmav 1.1 {
377     int i;
378     hash_struct *temp;
379 nmav 1.4 for (i = 0; i < size; ++i) { /* these limits OK? */
380     temp = table[i];
381 nmav 1.1 while (temp) {
382     hash_struct *temp_next;
383    
384     temp_next = temp->next;
385     free(temp->key);
386     free(temp->value);
387     free(temp);
388    
389     temp = temp_next;
390     }
391 nmav 1.4 table[i] = NULL;
392 nmav 1.1 }
393     }
394    
395 nmav 1.4 void dump_mime(void)
396     {
397     clear_hashtable(mime_hashtable, MIME_HASHTABLE_SIZE);
398     }
399    
400 nmav 1.1 void dump_passwd(void)
401     {
402 nmav 1.4 clear_hashtable(passwd_hashtable, PASSWD_HASHTABLE_SIZE);
403 nmav 1.1 }
404    
405     void show_hash_stats(void)
406     {
407     int i;
408     hash_struct *temp;
409     int total = 0;
410     int count;
411    
412     log_error_time();
413     fprintf(stderr, "mmap_hashtable has %d entries\n", mmap_list_entries_used);
414    
415     for (i = 0; i < MIME_HASHTABLE_SIZE; ++i) { /* these limits OK? */
416     if (mime_hashtable[i]) {
417     count = 0;
418     temp = mime_hashtable[i];
419     while (temp) {
420     temp = temp->next;
421     ++count;
422     }
423     #ifdef NOISY_SIGALRM
424     log_error_time();
425     fprintf(stderr, "mime_hashtable[%d] has %d entries\n",
426     i, count);
427     #endif
428     total += count;
429     }
430     }
431     log_error_time();
432 nmav 1.4 fprintf(stderr, "mime_hashtable has %d total entries\n", total);
433 nmav 1.1
434     total = 0;
435     for (i = 0; i < PASSWD_HASHTABLE_SIZE; ++i) { /* these limits OK? */
436     if (passwd_hashtable[i]) {
437     temp = passwd_hashtable[i];
438     count = 0;
439     while (temp) {
440     temp = temp->next;
441     ++count;
442     }
443     #ifdef NOISY_SIGALRM
444     log_error_time();
445     fprintf(stderr, "passwd_hashtable[%d] has %d entries\n",
446     i, count);
447     #endif
448     total += count;
449     }
450     }
451    
452     log_error_time();
453     fprintf(stderr, "passwd_hashtable has %d total entries\n",
454     total);
455    
456     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26