xref: /aosp_15_r20/external/selinux/libselinux/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 /* FLASK */
5*2d543d20SAndroid Build Coastguard Worker 
6*2d543d20SAndroid Build Coastguard Worker /*
7*2d543d20SAndroid Build Coastguard Worker  * Implementation of the hash table type.
8*2d543d20SAndroid Build Coastguard Worker  */
9*2d543d20SAndroid Build Coastguard Worker 
10*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
11*2d543d20SAndroid Build Coastguard Worker #include <string.h>
12*2d543d20SAndroid Build Coastguard Worker #include "hashtab.h"
13*2d543d20SAndroid Build Coastguard Worker 
selinux_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)14*2d543d20SAndroid Build Coastguard Worker hashtab_t selinux_hashtab_create(unsigned int (*hash_value) (hashtab_t h,
15*2d543d20SAndroid Build Coastguard Worker 						     const_hashtab_key_t key),
16*2d543d20SAndroid Build Coastguard Worker 			 int (*keycmp) (hashtab_t h,
17*2d543d20SAndroid Build Coastguard Worker 					const_hashtab_key_t key1,
18*2d543d20SAndroid Build Coastguard Worker 					const_hashtab_key_t key2),
19*2d543d20SAndroid Build Coastguard Worker 			 unsigned int size)
20*2d543d20SAndroid Build Coastguard Worker {
21*2d543d20SAndroid Build Coastguard Worker 
22*2d543d20SAndroid Build Coastguard Worker 	hashtab_t p;
23*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
24*2d543d20SAndroid Build Coastguard Worker 
25*2d543d20SAndroid Build Coastguard Worker 	p = (hashtab_t) malloc(sizeof(hashtab_val_t));
26*2d543d20SAndroid Build Coastguard Worker 	if (p == NULL)
27*2d543d20SAndroid Build Coastguard Worker 		return p;
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker 	memset(p, 0, sizeof(hashtab_val_t));
30*2d543d20SAndroid Build Coastguard Worker 	p->size = size;
31*2d543d20SAndroid Build Coastguard Worker 	p->nel = 0;
32*2d543d20SAndroid Build Coastguard Worker 	p->hash_value = hash_value;
33*2d543d20SAndroid Build Coastguard Worker 	p->keycmp = keycmp;
34*2d543d20SAndroid Build Coastguard Worker 	p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
35*2d543d20SAndroid Build Coastguard Worker 	if (p->htable == NULL) {
36*2d543d20SAndroid Build Coastguard Worker 		free(p);
37*2d543d20SAndroid Build Coastguard Worker 		return NULL;
38*2d543d20SAndroid Build Coastguard Worker 	}
39*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < size; i++)
40*2d543d20SAndroid Build Coastguard Worker 		p->htable[i] = (hashtab_ptr_t) NULL;
41*2d543d20SAndroid Build Coastguard Worker 
42*2d543d20SAndroid Build Coastguard Worker 	return p;
43*2d543d20SAndroid Build Coastguard Worker }
44*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_insert(hashtab_t h,hashtab_key_t key,hashtab_datum_t datum)45*2d543d20SAndroid Build Coastguard Worker int selinux_hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
46*2d543d20SAndroid Build Coastguard Worker {
47*2d543d20SAndroid Build Coastguard Worker 	unsigned int hvalue;
48*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t prev, cur, newnode;
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker 	if (!h)
51*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_OVERFLOW;
52*2d543d20SAndroid Build Coastguard Worker 
53*2d543d20SAndroid Build Coastguard Worker 	hvalue = h->hash_value(h, key);
54*2d543d20SAndroid Build Coastguard Worker 	prev = NULL;
55*2d543d20SAndroid Build Coastguard Worker 	cur = h->htable[hvalue];
56*2d543d20SAndroid Build Coastguard Worker 	while (cur && h->keycmp(h, key, cur->key) > 0) {
57*2d543d20SAndroid Build Coastguard Worker 		prev = cur;
58*2d543d20SAndroid Build Coastguard Worker 		cur = cur->next;
59*2d543d20SAndroid Build Coastguard Worker 	}
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker 	if (cur && (h->keycmp(h, key, cur->key) == 0))
62*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_PRESENT;
63*2d543d20SAndroid Build Coastguard Worker 
64*2d543d20SAndroid Build Coastguard Worker 	newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
65*2d543d20SAndroid Build Coastguard Worker 	if (newnode == NULL)
66*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_OVERFLOW;
67*2d543d20SAndroid Build Coastguard Worker 	memset(newnode, 0, sizeof(struct hashtab_node));
68*2d543d20SAndroid Build Coastguard Worker 	newnode->key = key;
69*2d543d20SAndroid Build Coastguard Worker 	newnode->datum = datum;
70*2d543d20SAndroid Build Coastguard Worker 	if (prev) {
71*2d543d20SAndroid Build Coastguard Worker 		newnode->next = prev->next;
72*2d543d20SAndroid Build Coastguard Worker 		prev->next = newnode;
73*2d543d20SAndroid Build Coastguard Worker 	} else {
74*2d543d20SAndroid Build Coastguard Worker 		newnode->next = h->htable[hvalue];
75*2d543d20SAndroid Build Coastguard Worker 		h->htable[hvalue] = newnode;
76*2d543d20SAndroid Build Coastguard Worker 	}
77*2d543d20SAndroid Build Coastguard Worker 
78*2d543d20SAndroid Build Coastguard Worker 	h->nel++;
79*2d543d20SAndroid Build Coastguard Worker 	return HASHTAB_SUCCESS;
80*2d543d20SAndroid Build Coastguard Worker }
81*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_remove(hashtab_t h,hashtab_key_t key,void (* destroy)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)82*2d543d20SAndroid Build Coastguard Worker int selinux_hashtab_remove(hashtab_t h, hashtab_key_t key,
83*2d543d20SAndroid Build Coastguard Worker 		   void (*destroy) (hashtab_key_t k,
84*2d543d20SAndroid Build Coastguard Worker 				    hashtab_datum_t d, void *args), void *args)
85*2d543d20SAndroid Build Coastguard Worker {
86*2d543d20SAndroid Build Coastguard Worker 	unsigned int hvalue;
87*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur, last;
88*2d543d20SAndroid Build Coastguard Worker 
89*2d543d20SAndroid Build Coastguard Worker 	if (!h)
90*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_MISSING;
91*2d543d20SAndroid Build Coastguard Worker 
92*2d543d20SAndroid Build Coastguard Worker 	hvalue = h->hash_value(h, key);
93*2d543d20SAndroid Build Coastguard Worker 	last = NULL;
94*2d543d20SAndroid Build Coastguard Worker 	cur = h->htable[hvalue];
95*2d543d20SAndroid Build Coastguard Worker 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
96*2d543d20SAndroid Build Coastguard Worker 		last = cur;
97*2d543d20SAndroid Build Coastguard Worker 		cur = cur->next;
98*2d543d20SAndroid Build Coastguard Worker 	}
99*2d543d20SAndroid Build Coastguard Worker 
100*2d543d20SAndroid Build Coastguard Worker 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
101*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_MISSING;
102*2d543d20SAndroid Build Coastguard Worker 
103*2d543d20SAndroid Build Coastguard Worker 	if (last == NULL)
104*2d543d20SAndroid Build Coastguard Worker 		h->htable[hvalue] = cur->next;
105*2d543d20SAndroid Build Coastguard Worker 	else
106*2d543d20SAndroid Build Coastguard Worker 		last->next = cur->next;
107*2d543d20SAndroid Build Coastguard Worker 
108*2d543d20SAndroid Build Coastguard Worker 	if (destroy)
109*2d543d20SAndroid Build Coastguard Worker 		destroy(cur->key, cur->datum, args);
110*2d543d20SAndroid Build Coastguard Worker 	free(cur);
111*2d543d20SAndroid Build Coastguard Worker 	h->nel--;
112*2d543d20SAndroid Build Coastguard Worker 	return HASHTAB_SUCCESS;
113*2d543d20SAndroid Build Coastguard Worker }
114*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_search(hashtab_t h,const_hashtab_key_t key)115*2d543d20SAndroid Build Coastguard Worker hashtab_datum_t selinux_hashtab_search(hashtab_t h, const_hashtab_key_t key)
116*2d543d20SAndroid Build Coastguard Worker {
117*2d543d20SAndroid Build Coastguard Worker 
118*2d543d20SAndroid Build Coastguard Worker 	unsigned int hvalue;
119*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur;
120*2d543d20SAndroid Build Coastguard Worker 
121*2d543d20SAndroid Build Coastguard Worker 	if (!h)
122*2d543d20SAndroid Build Coastguard Worker 		return NULL;
123*2d543d20SAndroid Build Coastguard Worker 
124*2d543d20SAndroid Build Coastguard Worker 	hvalue = h->hash_value(h, key);
125*2d543d20SAndroid Build Coastguard Worker 	cur = h->htable[hvalue];
126*2d543d20SAndroid Build Coastguard Worker 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
127*2d543d20SAndroid Build Coastguard Worker 		cur = cur->next;
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
130*2d543d20SAndroid Build Coastguard Worker 		return NULL;
131*2d543d20SAndroid Build Coastguard Worker 
132*2d543d20SAndroid Build Coastguard Worker 	return cur->datum;
133*2d543d20SAndroid Build Coastguard Worker }
134*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_destroy(hashtab_t h)135*2d543d20SAndroid Build Coastguard Worker void selinux_hashtab_destroy(hashtab_t h)
136*2d543d20SAndroid Build Coastguard Worker {
137*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
138*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur, temp;
139*2d543d20SAndroid Build Coastguard Worker 
140*2d543d20SAndroid Build Coastguard Worker 	if (!h)
141*2d543d20SAndroid Build Coastguard Worker 		return;
142*2d543d20SAndroid Build Coastguard Worker 
143*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < h->size; i++) {
144*2d543d20SAndroid Build Coastguard Worker 		cur = h->htable[i];
145*2d543d20SAndroid Build Coastguard Worker 		while (cur != NULL) {
146*2d543d20SAndroid Build Coastguard Worker 			temp = cur;
147*2d543d20SAndroid Build Coastguard Worker 			cur = cur->next;
148*2d543d20SAndroid Build Coastguard Worker 			free(temp);
149*2d543d20SAndroid Build Coastguard Worker 		}
150*2d543d20SAndroid Build Coastguard Worker 		h->htable[i] = NULL;
151*2d543d20SAndroid Build Coastguard Worker 	}
152*2d543d20SAndroid Build Coastguard Worker 
153*2d543d20SAndroid Build Coastguard Worker 	free(h->htable);
154*2d543d20SAndroid Build Coastguard Worker 	h->htable = NULL;
155*2d543d20SAndroid Build Coastguard Worker 
156*2d543d20SAndroid Build Coastguard Worker 	free(h);
157*2d543d20SAndroid Build Coastguard Worker }
158*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_destroy_key(hashtab_t h,int (* destroy_key)(hashtab_key_t k))159*2d543d20SAndroid Build Coastguard Worker void selinux_hashtab_destroy_key(hashtab_t h,
160*2d543d20SAndroid Build Coastguard Worker 		int (*destroy_key) (hashtab_key_t k))
161*2d543d20SAndroid Build Coastguard Worker {
162*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
163*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur, temp;
164*2d543d20SAndroid Build Coastguard Worker 
165*2d543d20SAndroid Build Coastguard Worker 	if (!h)
166*2d543d20SAndroid Build Coastguard Worker 		return;
167*2d543d20SAndroid Build Coastguard Worker 
168*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < h->size; i++) {
169*2d543d20SAndroid Build Coastguard Worker 		cur = h->htable[i];
170*2d543d20SAndroid Build Coastguard Worker 		while (cur != NULL) {
171*2d543d20SAndroid Build Coastguard Worker 			temp = cur;
172*2d543d20SAndroid Build Coastguard Worker 			cur = cur->next;
173*2d543d20SAndroid Build Coastguard Worker 			destroy_key(temp->key);
174*2d543d20SAndroid Build Coastguard Worker 			free(temp);
175*2d543d20SAndroid Build Coastguard Worker 		}
176*2d543d20SAndroid Build Coastguard Worker 		h->htable[i] = NULL;
177*2d543d20SAndroid Build Coastguard Worker 	}
178*2d543d20SAndroid Build Coastguard Worker 
179*2d543d20SAndroid Build Coastguard Worker 	free(h->htable);
180*2d543d20SAndroid Build Coastguard Worker 	h->htable = NULL;
181*2d543d20SAndroid Build Coastguard Worker 
182*2d543d20SAndroid Build Coastguard Worker 	free(h);
183*2d543d20SAndroid Build Coastguard Worker }
184*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_map(hashtab_t h,int (* apply)(hashtab_key_t k,hashtab_datum_t d,void * args),void * args)185*2d543d20SAndroid Build Coastguard Worker int selinux_hashtab_map(hashtab_t h,
186*2d543d20SAndroid Build Coastguard Worker 		int (*apply) (hashtab_key_t k,
187*2d543d20SAndroid Build Coastguard Worker 			      hashtab_datum_t d, void *args), void *args)
188*2d543d20SAndroid Build Coastguard Worker {
189*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
190*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur;
191*2d543d20SAndroid Build Coastguard Worker 	int ret;
192*2d543d20SAndroid Build Coastguard Worker 
193*2d543d20SAndroid Build Coastguard Worker 	if (!h)
194*2d543d20SAndroid Build Coastguard Worker 		return HASHTAB_SUCCESS;
195*2d543d20SAndroid Build Coastguard Worker 
196*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < h->size; i++) {
197*2d543d20SAndroid Build Coastguard Worker 		cur = h->htable[i];
198*2d543d20SAndroid Build Coastguard Worker 		while (cur != NULL) {
199*2d543d20SAndroid Build Coastguard Worker 			ret = apply(cur->key, cur->datum, args);
200*2d543d20SAndroid Build Coastguard Worker 			if (ret)
201*2d543d20SAndroid Build Coastguard Worker 				return ret;
202*2d543d20SAndroid Build Coastguard Worker 			cur = cur->next;
203*2d543d20SAndroid Build Coastguard Worker 		}
204*2d543d20SAndroid Build Coastguard Worker 	}
205*2d543d20SAndroid Build Coastguard Worker 	return HASHTAB_SUCCESS;
206*2d543d20SAndroid Build Coastguard Worker }
207*2d543d20SAndroid Build Coastguard Worker 
selinux_hashtab_hash_eval(hashtab_t h,char * tag)208*2d543d20SAndroid Build Coastguard Worker void selinux_hashtab_hash_eval(hashtab_t h, char *tag)
209*2d543d20SAndroid Build Coastguard Worker {
210*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
211*2d543d20SAndroid Build Coastguard Worker 	int chain_len, slots_used, max_chain_len;
212*2d543d20SAndroid Build Coastguard Worker 	hashtab_ptr_t cur;
213*2d543d20SAndroid Build Coastguard Worker 
214*2d543d20SAndroid Build Coastguard Worker 	slots_used = 0;
215*2d543d20SAndroid Build Coastguard Worker 	max_chain_len = 0;
216*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < h->size; i++) {
217*2d543d20SAndroid Build Coastguard Worker 		cur = h->htable[i];
218*2d543d20SAndroid Build Coastguard Worker 		if (cur) {
219*2d543d20SAndroid Build Coastguard Worker 			slots_used++;
220*2d543d20SAndroid Build Coastguard Worker 			chain_len = 0;
221*2d543d20SAndroid Build Coastguard Worker 			while (cur) {
222*2d543d20SAndroid Build Coastguard Worker 				chain_len++;
223*2d543d20SAndroid Build Coastguard Worker 				cur = cur->next;
224*2d543d20SAndroid Build Coastguard Worker 			}
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker 			if (chain_len > max_chain_len)
227*2d543d20SAndroid Build Coastguard Worker 				max_chain_len = chain_len;
228*2d543d20SAndroid Build Coastguard Worker 		}
229*2d543d20SAndroid Build Coastguard Worker 	}
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 	printf
232*2d543d20SAndroid Build Coastguard Worker 	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
233*2d543d20SAndroid Build Coastguard Worker 	     tag, h->nel, slots_used, h->size, max_chain_len);
234*2d543d20SAndroid Build Coastguard Worker }
235