1
2 /* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
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_insert(hashtab_t h,hashtab_key_t key,hashtab_datum_t datum)66 int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
67 {
68 int hvalue;
69 hashtab_ptr_t prev, cur, newnode;
70
71 if (!h)
72 return SEPOL_ENOMEM;
73
74 hvalue = h->hash_value(h, key);
75 prev = NULL;
76 cur = h->htable[hvalue];
77 while (cur && h->keycmp(h, key, cur->key) > 0) {
78 prev = cur;
79 cur = cur->next;
80 }
81
82 if (cur && (h->keycmp(h, key, cur->key) == 0))
83 return SEPOL_EEXIST;
84
85 newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
86 if (newnode == NULL)
87 return SEPOL_ENOMEM;
88 memset(newnode, 0, sizeof(struct hashtab_node));
89 newnode->key = key;
90 newnode->datum = datum;
91 if (prev) {
92 newnode->next = prev->next;
93 prev->next = newnode;
94 } else {
95 newnode->next = h->htable[hvalue];
96 h->htable[hvalue] = newnode;
97 }
98
99 h->nel++;
100 return SEPOL_OK;
101 }
102
hashtab_remove(hashtab_t h,hashtab_key_t key,void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)103 int hashtab_remove(hashtab_t h, hashtab_key_t key,
104 void (*destroy) (hashtab_key_t k,
105 hashtab_datum_t d, void *args), void *args)
106 {
107 int hvalue;
108 hashtab_ptr_t cur, last;
109
110 if (!h)
111 return SEPOL_ENOENT;
112
113 hvalue = h->hash_value(h, key);
114 last = NULL;
115 cur = h->htable[hvalue];
116 while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
117 last = cur;
118 cur = cur->next;
119 }
120
121 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
122 return SEPOL_ENOENT;
123
124 if (last == NULL)
125 h->htable[hvalue] = cur->next;
126 else
127 last->next = cur->next;
128
129 if (destroy)
130 destroy(cur->key, cur->datum, args);
131 free(cur);
132 h->nel--;
133 return SEPOL_OK;
134 }
135
hashtab_replace(hashtab_t h,hashtab_key_t key,hashtab_datum_t datum,void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)136 int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum,
137 void (*destroy) (hashtab_key_t k,
138 hashtab_datum_t d, void *args), void *args)
139 {
140 int hvalue;
141 hashtab_ptr_t prev, cur, newnode;
142
143 if (!h)
144 return SEPOL_ENOMEM;
145
146 hvalue = h->hash_value(h, key);
147 prev = NULL;
148 cur = h->htable[hvalue];
149 while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
150 prev = cur;
151 cur = cur->next;
152 }
153
154 if (cur && (h->keycmp(h, key, cur->key) == 0)) {
155 if (destroy)
156 destroy(cur->key, cur->datum, args);
157 cur->key = key;
158 cur->datum = datum;
159 } else {
160 newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
161 if (newnode == NULL)
162 return SEPOL_ENOMEM;
163 memset(newnode, 0, sizeof(struct hashtab_node));
164 newnode->key = key;
165 newnode->datum = datum;
166 if (prev) {
167 newnode->next = prev->next;
168 prev->next = newnode;
169 } else {
170 newnode->next = h->htable[hvalue];
171 h->htable[hvalue] = newnode;
172 }
173 }
174
175 return SEPOL_OK;
176 }
177
hashtab_search(hashtab_t h,const hashtab_key_t key)178 hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key)
179 {
180
181 int hvalue;
182 hashtab_ptr_t cur;
183
184 if (!h)
185 return NULL;
186
187 hvalue = h->hash_value(h, key);
188 cur = h->htable[hvalue];
189 while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
190 cur = cur->next;
191
192 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
193 return NULL;
194
195 return cur->datum;
196 }
197
hashtab_destroy(hashtab_t h)198 void hashtab_destroy(hashtab_t h)
199 {
200 unsigned int i;
201 hashtab_ptr_t cur, temp;
202
203 if (!h)
204 return;
205
206 for (i = 0; i < h->size; i++) {
207 cur = h->htable[i];
208 while (cur != NULL) {
209 temp = cur;
210 cur = cur->next;
211 free(temp);
212 }
213 h->htable[i] = NULL;
214 }
215
216 free(h->htable);
217 h->htable = NULL;
218
219 free(h);
220 }
221
hashtab_map(hashtab_t h,int (* apply)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)222 int hashtab_map(hashtab_t h,
223 int (*apply) (hashtab_key_t k,
224 hashtab_datum_t d, void *args), void *args)
225 {
226 unsigned int i, ret;
227 hashtab_ptr_t cur;
228
229 if (!h)
230 return SEPOL_OK;
231
232 for (i = 0; i < h->size; i++) {
233 cur = h->htable[i];
234 while (cur != NULL) {
235 ret = apply(cur->key, cur->datum, args);
236 if (ret)
237 return ret;
238 cur = cur->next;
239 }
240 }
241 return SEPOL_OK;
242 }
243
hashtab_map_remove_on_error(hashtab_t h,int (* apply)(hashtab_key_t k,hashtab_datum_t d,void * args),void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)244 void hashtab_map_remove_on_error(hashtab_t h,
245 int (*apply) (hashtab_key_t k,
246 hashtab_datum_t d,
247 void *args),
248 void (*destroy) (hashtab_key_t k,
249 hashtab_datum_t d,
250 void *args), void *args)
251 {
252 unsigned int i;
253 int ret;
254 hashtab_ptr_t last, cur, temp;
255
256 if (!h)
257 return;
258
259 for (i = 0; i < h->size; i++) {
260 last = NULL;
261 cur = h->htable[i];
262 while (cur != NULL) {
263 ret = apply(cur->key, cur->datum, args);
264 if (ret) {
265 if (last) {
266 last->next = cur->next;
267 } else {
268 h->htable[i] = cur->next;
269 }
270
271 temp = cur;
272 cur = cur->next;
273 if (destroy)
274 destroy(temp->key, temp->datum, args);
275 free(temp);
276 h->nel--;
277 } else {
278 last = cur;
279 cur = cur->next;
280 }
281 }
282 }
283
284 return;
285 }
286
hashtab_hash_eval(hashtab_t h,char * tag)287 void hashtab_hash_eval(hashtab_t h, char *tag)
288 {
289 unsigned int i;
290 int chain_len, slots_used, max_chain_len;
291 hashtab_ptr_t cur;
292
293 slots_used = 0;
294 max_chain_len = 0;
295 for (i = 0; i < h->size; i++) {
296 cur = h->htable[i];
297 if (cur) {
298 slots_used++;
299 chain_len = 0;
300 while (cur) {
301 chain_len++;
302 cur = cur->next;
303 }
304
305 if (chain_len > max_chain_len)
306 max_chain_len = chain_len;
307 }
308 }
309
310 printf
311 ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
312 tag, h->nel, slots_used, h->size, max_chain_len);
313 }
314