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