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
35 #include "private.h"
36
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)37 hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
38 const_hashtab_key_t key),
39 int (*keycmp) (hashtab_t h,
40 const_hashtab_key_t key1,
41 const_hashtab_key_t key2),
42 unsigned int size)
43 {
44
45 hashtab_t p;
46 unsigned int i;
47
48 p = (hashtab_t) malloc(sizeof(hashtab_val_t));
49 if (p == NULL)
50 return p;
51
52 memset(p, 0, sizeof(hashtab_val_t));
53 p->size = size;
54 p->nel = 0;
55 p->hash_value = hash_value;
56 p->keycmp = keycmp;
57 p->htable = (hashtab_ptr_t *) mallocarray(size, sizeof(hashtab_ptr_t));
58 if (p->htable == NULL) {
59 free(p);
60 return NULL;
61 }
62 for (i = 0; i < size; i++)
63 p->htable[i] = (hashtab_ptr_t) NULL;
64
65 return p;
66 }
67
hashtab_check_resize(hashtab_t h)68 static void hashtab_check_resize(hashtab_t h)
69 {
70 unsigned int hvalue, i, old_size, new_size = h->size;
71 hashtab_ptr_t *new_htable, *dst, cur, next;
72
73 while (new_size <= h->nel && new_size * 2 != 0)
74 new_size *= 2;
75
76 if (h->size == new_size)
77 return;
78
79 new_htable = calloc(new_size, sizeof(*new_htable));
80 if (!new_htable)
81 return;
82
83 old_size = h->size;
84 h->size = new_size;
85
86 /* Move all elements to the new htable */
87 for (i = 0; i < old_size; i++) {
88 cur = h->htable[i];
89 while (cur != NULL) {
90 hvalue = h->hash_value(h, cur->key);
91 dst = &new_htable[hvalue];
92 while (*dst && h->keycmp(h, cur->key, (*dst)->key) > 0)
93 dst = &(*dst)->next;
94
95 next = cur->next;
96
97 cur->next = *dst;
98 *dst = cur;
99
100 cur = next;
101 }
102 }
103 free(h->htable);
104 h->htable = new_htable;
105 }
106
hashtab_insert(hashtab_t h,hashtab_key_t key,hashtab_datum_t datum)107 int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
108 {
109 int hvalue;
110 hashtab_ptr_t prev, cur, newnode;
111
112 if (!h)
113 return SEPOL_ENOMEM;
114
115 hashtab_check_resize(h);
116
117 hvalue = h->hash_value(h, key);
118 prev = NULL;
119 cur = h->htable[hvalue];
120 while (cur && h->keycmp(h, key, cur->key) > 0) {
121 prev = cur;
122 cur = cur->next;
123 }
124
125 if (cur && (h->keycmp(h, key, cur->key) == 0))
126 return SEPOL_EEXIST;
127
128 newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
129 if (newnode == NULL)
130 return SEPOL_ENOMEM;
131 memset(newnode, 0, sizeof(struct hashtab_node));
132 newnode->key = key;
133 newnode->datum = datum;
134 if (prev) {
135 newnode->next = prev->next;
136 prev->next = newnode;
137 } else {
138 newnode->next = h->htable[hvalue];
139 h->htable[hvalue] = newnode;
140 }
141
142 h->nel++;
143 return SEPOL_OK;
144 }
145
hashtab_remove(hashtab_t h,hashtab_key_t key,void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)146 int hashtab_remove(hashtab_t h, hashtab_key_t key,
147 void (*destroy) (hashtab_key_t k,
148 hashtab_datum_t d, void *args), void *args)
149 {
150 int hvalue;
151 hashtab_ptr_t cur, last;
152
153 if (!h)
154 return SEPOL_ENOENT;
155
156 hvalue = h->hash_value(h, key);
157 last = NULL;
158 cur = h->htable[hvalue];
159 while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
160 last = cur;
161 cur = cur->next;
162 }
163
164 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
165 return SEPOL_ENOENT;
166
167 if (last == NULL)
168 h->htable[hvalue] = cur->next;
169 else
170 last->next = cur->next;
171
172 if (destroy)
173 destroy(cur->key, cur->datum, args);
174 free(cur);
175 h->nel--;
176 return SEPOL_OK;
177 }
178
hashtab_search(hashtab_t h,const_hashtab_key_t key)179 hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
180 {
181
182 int hvalue;
183 hashtab_ptr_t cur;
184
185 if (!h)
186 return NULL;
187
188 hvalue = h->hash_value(h, key);
189 cur = h->htable[hvalue];
190 while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
191 cur = cur->next;
192
193 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
194 return NULL;
195
196 return cur->datum;
197 }
198
hashtab_destroy(hashtab_t h)199 void hashtab_destroy(hashtab_t h)
200 {
201 unsigned int i;
202 hashtab_ptr_t cur, temp;
203
204 if (!h)
205 return;
206
207 for (i = 0; i < h->size; i++) {
208 cur = h->htable[i];
209 while (cur != NULL) {
210 temp = cur;
211 cur = cur->next;
212 free(temp);
213 }
214 h->htable[i] = NULL;
215 }
216
217 free(h->htable);
218 h->htable = NULL;
219
220 free(h);
221 }
222
hashtab_map(hashtab_t h,int (* apply)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)223 int hashtab_map(hashtab_t h,
224 int (*apply) (hashtab_key_t k,
225 hashtab_datum_t d, void *args), void *args)
226 {
227 unsigned int i;
228 hashtab_ptr_t cur;
229 int ret;
230
231 if (!h)
232 return SEPOL_OK;
233
234 for (i = 0; i < h->size; i++) {
235 cur = h->htable[i];
236 while (cur != NULL) {
237 ret = apply(cur->key, cur->datum, args);
238 if (ret)
239 return ret;
240 cur = cur->next;
241 }
242 }
243 return SEPOL_OK;
244 }
245
hashtab_hash_eval(hashtab_t h,char * tag)246 void hashtab_hash_eval(hashtab_t h, char *tag)
247 {
248 unsigned int i;
249 int chain_len, slots_used, max_chain_len;
250 hashtab_ptr_t cur;
251
252 slots_used = 0;
253 max_chain_len = 0;
254 for (i = 0; i < h->size; i++) {
255 cur = h->htable[i];
256 if (cur) {
257 slots_used++;
258 chain_len = 0;
259 while (cur) {
260 chain_len++;
261 cur = cur->next;
262 }
263
264 if (chain_len > max_chain_len)
265 max_chain_len = chain_len;
266 }
267 }
268
269 printf
270 ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
271 tag, h->nel, slots_used, h->size, max_chain_len);
272 }
273