• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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