1
2 /* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
3
4 /*
5 * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com>
6 *
7 * Copyright (C) 2007 Red Hat, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24
25 /* FLASK */
26
27 /*
28 * Implementation of the hash table type.
29 */
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sepol/policydb/hashtab.h>
34
hashtab_create(unsigned int (* hash_value)(hashtab_t h,const_hashtab_key_t key),int (* keycmp)(hashtab_t h,const_hashtab_key_t key1,const_hashtab_key_t key2),unsigned int size)35 hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
36 const_hashtab_key_t key),
37 int (*keycmp) (hashtab_t h,
38 const_hashtab_key_t key1,
39 const_hashtab_key_t key2),
40 unsigned int size)
41 {
42
43 hashtab_t p;
44 unsigned int i;
45
46 p = (hashtab_t) malloc(sizeof(hashtab_val_t));
47 if (p == NULL)
48 return p;
49
50 memset(p, 0, sizeof(hashtab_val_t));
51 p->size = size;
52 p->nel = 0;
53 p->hash_value = hash_value;
54 p->keycmp = keycmp;
55 p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
56 if (p->htable == NULL) {
57 free(p);
58 return NULL;
59 }
60 for (i = 0; i < size; i++)
61 p->htable[i] = (hashtab_ptr_t) NULL;
62
63 return p;
64 }
65
hashtab_check_resize(hashtab_t h)66 static void hashtab_check_resize(hashtab_t h)
67 {
68 unsigned int hvalue, i, old_size, new_size = h->size;
69 hashtab_ptr_t *new_htable, *dst, cur, next;
70
71 while (new_size <= h->nel && new_size * 2 != 0)
72 new_size *= 2;
73
74 if (h->size == new_size)
75 return;
76
77 new_htable = calloc(new_size, sizeof(*new_htable));
78 if (!new_htable)
79 return;
80
81 old_size = h->size;
82 h->size = new_size;
83
84 /* Move all elements to the new htable */
85 for (i = 0; i < old_size; i++) {
86 cur = h->htable[i];
87 while (cur != NULL) {
88 hvalue = h->hash_value(h, cur->key);
89 dst = &new_htable[hvalue];
90 while (*dst && h->keycmp(h, cur->key, (*dst)->key) > 0)
91 dst = &(*dst)->next;
92
93 next = cur->next;
94
95 cur->next = *dst;
96 *dst = cur;
97
98 cur = next;
99 }
100 }
101 free(h->htable);
102 h->htable = new_htable;
103 }
104
hashtab_insert(hashtab_t h,hashtab_key_t key,hashtab_datum_t datum)105 int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
106 {
107 int hvalue;
108 hashtab_ptr_t prev, cur, newnode;
109
110 if (!h)
111 return SEPOL_ENOMEM;
112
113 hashtab_check_resize(h);
114
115 hvalue = h->hash_value(h, key);
116 prev = NULL;
117 cur = h->htable[hvalue];
118 while (cur && h->keycmp(h, key, cur->key) > 0) {
119 prev = cur;
120 cur = cur->next;
121 }
122
123 if (cur && (h->keycmp(h, key, cur->key) == 0))
124 return SEPOL_EEXIST;
125
126 newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
127 if (newnode == NULL)
128 return SEPOL_ENOMEM;
129 memset(newnode, 0, sizeof(struct hashtab_node));
130 newnode->key = key;
131 newnode->datum = datum;
132 if (prev) {
133 newnode->next = prev->next;
134 prev->next = newnode;
135 } else {
136 newnode->next = h->htable[hvalue];
137 h->htable[hvalue] = newnode;
138 }
139
140 h->nel++;
141 return SEPOL_OK;
142 }
143
hashtab_remove(hashtab_t h,hashtab_key_t key,void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)144 int hashtab_remove(hashtab_t h, hashtab_key_t key,
145 void (*destroy) (hashtab_key_t k,
146 hashtab_datum_t d, void *args), void *args)
147 {
148 int hvalue;
149 hashtab_ptr_t cur, last;
150
151 if (!h)
152 return SEPOL_ENOENT;
153
154 hvalue = h->hash_value(h, key);
155 last = NULL;
156 cur = h->htable[hvalue];
157 while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
158 last = cur;
159 cur = cur->next;
160 }
161
162 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
163 return SEPOL_ENOENT;
164
165 if (last == NULL)
166 h->htable[hvalue] = cur->next;
167 else
168 last->next = cur->next;
169
170 if (destroy)
171 destroy(cur->key, cur->datum, args);
172 free(cur);
173 h->nel--;
174 return SEPOL_OK;
175 }
176
hashtab_search(hashtab_t h,const_hashtab_key_t key)177 hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
178 {
179
180 int hvalue;
181 hashtab_ptr_t cur;
182
183 if (!h)
184 return NULL;
185
186 hvalue = h->hash_value(h, key);
187 cur = h->htable[hvalue];
188 while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
189 cur = cur->next;
190
191 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
192 return NULL;
193
194 return cur->datum;
195 }
196
hashtab_destroy(hashtab_t h)197 void hashtab_destroy(hashtab_t h)
198 {
199 unsigned int i;
200 hashtab_ptr_t cur, temp;
201
202 if (!h)
203 return;
204
205 for (i = 0; i < h->size; i++) {
206 cur = h->htable[i];
207 while (cur != NULL) {
208 temp = cur;
209 cur = cur->next;
210 free(temp);
211 }
212 h->htable[i] = NULL;
213 }
214
215 free(h->htable);
216 h->htable = NULL;
217
218 free(h);
219 }
220
hashtab_map(hashtab_t h,int (* apply)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)221 int hashtab_map(hashtab_t h,
222 int (*apply) (hashtab_key_t k,
223 hashtab_datum_t d, void *args), void *args)
224 {
225 unsigned int i, ret;
226 hashtab_ptr_t cur;
227
228 if (!h)
229 return SEPOL_OK;
230
231 for (i = 0; i < h->size; i++) {
232 cur = h->htable[i];
233 while (cur != NULL) {
234 ret = apply(cur->key, cur->datum, args);
235 if (ret)
236 return ret;
237 cur = cur->next;
238 }
239 }
240 return SEPOL_OK;
241 }
242
hashtab_hash_eval(hashtab_t h,char * tag)243 void hashtab_hash_eval(hashtab_t h, char *tag)
244 {
245 unsigned int i;
246 int chain_len, slots_used, max_chain_len;
247 hashtab_ptr_t cur;
248
249 slots_used = 0;
250 max_chain_len = 0;
251 for (i = 0; i < h->size; i++) {
252 cur = h->htable[i];
253 if (cur) {
254 slots_used++;
255 chain_len = 0;
256 while (cur) {
257 chain_len++;
258 cur = cur->next;
259 }
260
261 if (chain_len > max_chain_len)
262 max_chain_len = chain_len;
263 }
264 }
265
266 printf
267 ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
268 tag, h->nel, slots_used, h->size, max_chain_len);
269 }
270