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