16cd6a6acSopenharmony_ci 26cd6a6acSopenharmony_ci/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */ 36cd6a6acSopenharmony_ci 46cd6a6acSopenharmony_ci/* 56cd6a6acSopenharmony_ci * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com> 66cd6a6acSopenharmony_ci * 76cd6a6acSopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. 86cd6a6acSopenharmony_ci * 96cd6a6acSopenharmony_ci * This library is free software; you can redistribute it and/or 106cd6a6acSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 116cd6a6acSopenharmony_ci * License as published by the Free Software Foundation; either 126cd6a6acSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 136cd6a6acSopenharmony_ci * 146cd6a6acSopenharmony_ci * This library is distributed in the hope that it will be useful, 156cd6a6acSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 166cd6a6acSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 176cd6a6acSopenharmony_ci * Lesser General Public License for more details. 186cd6a6acSopenharmony_ci * 196cd6a6acSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 206cd6a6acSopenharmony_ci * License along with this library; if not, write to the Free Software 216cd6a6acSopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 226cd6a6acSopenharmony_ci */ 236cd6a6acSopenharmony_ci 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci/* FLASK */ 266cd6a6acSopenharmony_ci 276cd6a6acSopenharmony_ci/* 286cd6a6acSopenharmony_ci * Implementation of the hash table type. 296cd6a6acSopenharmony_ci */ 306cd6a6acSopenharmony_ci 316cd6a6acSopenharmony_ci#include <stdlib.h> 326cd6a6acSopenharmony_ci#include <string.h> 336cd6a6acSopenharmony_ci#include <sepol/policydb/hashtab.h> 346cd6a6acSopenharmony_ci 356cd6a6acSopenharmony_ci#include "private.h" 366cd6a6acSopenharmony_ci 376cd6a6acSopenharmony_cihashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, 386cd6a6acSopenharmony_ci const_hashtab_key_t key), 396cd6a6acSopenharmony_ci int (*keycmp) (hashtab_t h, 406cd6a6acSopenharmony_ci const_hashtab_key_t key1, 416cd6a6acSopenharmony_ci const_hashtab_key_t key2), 426cd6a6acSopenharmony_ci unsigned int size) 436cd6a6acSopenharmony_ci{ 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci hashtab_t p; 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci p = (hashtab_t) malloc(sizeof(hashtab_val_t)); 486cd6a6acSopenharmony_ci if (p == NULL) 496cd6a6acSopenharmony_ci return p; 506cd6a6acSopenharmony_ci 516cd6a6acSopenharmony_ci memset(p, 0, sizeof(hashtab_val_t)); 526cd6a6acSopenharmony_ci p->size = size; 536cd6a6acSopenharmony_ci p->nel = 0; 546cd6a6acSopenharmony_ci p->hash_value = hash_value; 556cd6a6acSopenharmony_ci p->keycmp = keycmp; 566cd6a6acSopenharmony_ci p->htable = (hashtab_ptr_t *) calloc(size, sizeof(hashtab_ptr_t)); 576cd6a6acSopenharmony_ci if (p->htable == NULL) { 586cd6a6acSopenharmony_ci free(p); 596cd6a6acSopenharmony_ci return NULL; 606cd6a6acSopenharmony_ci } 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_ci return p; 636cd6a6acSopenharmony_ci} 646cd6a6acSopenharmony_ci 656cd6a6acSopenharmony_cistatic void hashtab_check_resize(hashtab_t h) 666cd6a6acSopenharmony_ci{ 676cd6a6acSopenharmony_ci unsigned int hvalue, i, old_size, new_size = h->size; 686cd6a6acSopenharmony_ci hashtab_ptr_t *new_htable, *dst, cur, next; 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_ci while (new_size <= h->nel && new_size * 2 != 0) 716cd6a6acSopenharmony_ci new_size *= 2; 726cd6a6acSopenharmony_ci 736cd6a6acSopenharmony_ci if (h->size == new_size) 746cd6a6acSopenharmony_ci return; 756cd6a6acSopenharmony_ci 766cd6a6acSopenharmony_ci new_htable = calloc(new_size, sizeof(*new_htable)); 776cd6a6acSopenharmony_ci if (!new_htable) 786cd6a6acSopenharmony_ci return; 796cd6a6acSopenharmony_ci 806cd6a6acSopenharmony_ci old_size = h->size; 816cd6a6acSopenharmony_ci h->size = new_size; 826cd6a6acSopenharmony_ci 836cd6a6acSopenharmony_ci /* Move all elements to the new htable */ 846cd6a6acSopenharmony_ci for (i = 0; i < old_size; i++) { 856cd6a6acSopenharmony_ci cur = h->htable[i]; 866cd6a6acSopenharmony_ci while (cur != NULL) { 876cd6a6acSopenharmony_ci hvalue = h->hash_value(h, cur->key); 886cd6a6acSopenharmony_ci dst = &new_htable[hvalue]; 896cd6a6acSopenharmony_ci while (*dst && h->keycmp(h, cur->key, (*dst)->key) > 0) 906cd6a6acSopenharmony_ci dst = &(*dst)->next; 916cd6a6acSopenharmony_ci 926cd6a6acSopenharmony_ci next = cur->next; 936cd6a6acSopenharmony_ci 946cd6a6acSopenharmony_ci cur->next = *dst; 956cd6a6acSopenharmony_ci *dst = cur; 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_ci cur = next; 986cd6a6acSopenharmony_ci } 996cd6a6acSopenharmony_ci } 1006cd6a6acSopenharmony_ci free(h->htable); 1016cd6a6acSopenharmony_ci h->htable = new_htable; 1026cd6a6acSopenharmony_ci} 1036cd6a6acSopenharmony_ci 1046cd6a6acSopenharmony_ciint hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum) 1056cd6a6acSopenharmony_ci{ 1066cd6a6acSopenharmony_ci int hvalue; 1076cd6a6acSopenharmony_ci hashtab_ptr_t prev, cur, newnode; 1086cd6a6acSopenharmony_ci 1096cd6a6acSopenharmony_ci if (!h) 1106cd6a6acSopenharmony_ci return SEPOL_ENOMEM; 1116cd6a6acSopenharmony_ci 1126cd6a6acSopenharmony_ci hashtab_check_resize(h); 1136cd6a6acSopenharmony_ci 1146cd6a6acSopenharmony_ci hvalue = h->hash_value(h, key); 1156cd6a6acSopenharmony_ci prev = NULL; 1166cd6a6acSopenharmony_ci cur = h->htable[hvalue]; 1176cd6a6acSopenharmony_ci while (cur && h->keycmp(h, key, cur->key) > 0) { 1186cd6a6acSopenharmony_ci prev = cur; 1196cd6a6acSopenharmony_ci cur = cur->next; 1206cd6a6acSopenharmony_ci } 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci if (cur && (h->keycmp(h, key, cur->key) == 0)) 1236cd6a6acSopenharmony_ci return SEPOL_EEXIST; 1246cd6a6acSopenharmony_ci 1256cd6a6acSopenharmony_ci newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t)); 1266cd6a6acSopenharmony_ci if (newnode == NULL) 1276cd6a6acSopenharmony_ci return SEPOL_ENOMEM; 1286cd6a6acSopenharmony_ci memset(newnode, 0, sizeof(struct hashtab_node)); 1296cd6a6acSopenharmony_ci newnode->key = key; 1306cd6a6acSopenharmony_ci newnode->datum = datum; 1316cd6a6acSopenharmony_ci if (prev) { 1326cd6a6acSopenharmony_ci newnode->next = prev->next; 1336cd6a6acSopenharmony_ci prev->next = newnode; 1346cd6a6acSopenharmony_ci } else { 1356cd6a6acSopenharmony_ci newnode->next = h->htable[hvalue]; 1366cd6a6acSopenharmony_ci h->htable[hvalue] = newnode; 1376cd6a6acSopenharmony_ci } 1386cd6a6acSopenharmony_ci 1396cd6a6acSopenharmony_ci h->nel++; 1406cd6a6acSopenharmony_ci return SEPOL_OK; 1416cd6a6acSopenharmony_ci} 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ciint hashtab_remove(hashtab_t h, hashtab_key_t key, 1446cd6a6acSopenharmony_ci void (*destroy) (hashtab_key_t k, 1456cd6a6acSopenharmony_ci hashtab_datum_t d, void *args), void *args) 1466cd6a6acSopenharmony_ci{ 1476cd6a6acSopenharmony_ci int hvalue; 1486cd6a6acSopenharmony_ci hashtab_ptr_t cur, last; 1496cd6a6acSopenharmony_ci 1506cd6a6acSopenharmony_ci if (!h) 1516cd6a6acSopenharmony_ci return SEPOL_ENOENT; 1526cd6a6acSopenharmony_ci 1536cd6a6acSopenharmony_ci hvalue = h->hash_value(h, key); 1546cd6a6acSopenharmony_ci last = NULL; 1556cd6a6acSopenharmony_ci cur = h->htable[hvalue]; 1566cd6a6acSopenharmony_ci while (cur != NULL && h->keycmp(h, key, cur->key) > 0) { 1576cd6a6acSopenharmony_ci last = cur; 1586cd6a6acSopenharmony_ci cur = cur->next; 1596cd6a6acSopenharmony_ci } 1606cd6a6acSopenharmony_ci 1616cd6a6acSopenharmony_ci if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) 1626cd6a6acSopenharmony_ci return SEPOL_ENOENT; 1636cd6a6acSopenharmony_ci 1646cd6a6acSopenharmony_ci if (last == NULL) 1656cd6a6acSopenharmony_ci h->htable[hvalue] = cur->next; 1666cd6a6acSopenharmony_ci else 1676cd6a6acSopenharmony_ci last->next = cur->next; 1686cd6a6acSopenharmony_ci 1696cd6a6acSopenharmony_ci if (destroy) 1706cd6a6acSopenharmony_ci destroy(cur->key, cur->datum, args); 1716cd6a6acSopenharmony_ci free(cur); 1726cd6a6acSopenharmony_ci h->nel--; 1736cd6a6acSopenharmony_ci return SEPOL_OK; 1746cd6a6acSopenharmony_ci} 1756cd6a6acSopenharmony_ci 1766cd6a6acSopenharmony_cihashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key) 1776cd6a6acSopenharmony_ci{ 1786cd6a6acSopenharmony_ci 1796cd6a6acSopenharmony_ci int hvalue; 1806cd6a6acSopenharmony_ci hashtab_ptr_t cur; 1816cd6a6acSopenharmony_ci 1826cd6a6acSopenharmony_ci if (!h) 1836cd6a6acSopenharmony_ci return NULL; 1846cd6a6acSopenharmony_ci 1856cd6a6acSopenharmony_ci hvalue = h->hash_value(h, key); 1866cd6a6acSopenharmony_ci cur = h->htable[hvalue]; 1876cd6a6acSopenharmony_ci while (cur != NULL && h->keycmp(h, key, cur->key) > 0) 1886cd6a6acSopenharmony_ci cur = cur->next; 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ci if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) 1916cd6a6acSopenharmony_ci return NULL; 1926cd6a6acSopenharmony_ci 1936cd6a6acSopenharmony_ci return cur->datum; 1946cd6a6acSopenharmony_ci} 1956cd6a6acSopenharmony_ci 1966cd6a6acSopenharmony_civoid hashtab_destroy(hashtab_t h) 1976cd6a6acSopenharmony_ci{ 1986cd6a6acSopenharmony_ci unsigned int i; 1996cd6a6acSopenharmony_ci hashtab_ptr_t cur, temp; 2006cd6a6acSopenharmony_ci 2016cd6a6acSopenharmony_ci if (!h) 2026cd6a6acSopenharmony_ci return; 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci for (i = 0; i < h->size; i++) { 2056cd6a6acSopenharmony_ci cur = h->htable[i]; 2066cd6a6acSopenharmony_ci while (cur != NULL) { 2076cd6a6acSopenharmony_ci temp = cur; 2086cd6a6acSopenharmony_ci cur = cur->next; 2096cd6a6acSopenharmony_ci free(temp); 2106cd6a6acSopenharmony_ci } 2116cd6a6acSopenharmony_ci h->htable[i] = NULL; 2126cd6a6acSopenharmony_ci } 2136cd6a6acSopenharmony_ci 2146cd6a6acSopenharmony_ci free(h->htable); 2156cd6a6acSopenharmony_ci h->htable = NULL; 2166cd6a6acSopenharmony_ci 2176cd6a6acSopenharmony_ci free(h); 2186cd6a6acSopenharmony_ci} 2196cd6a6acSopenharmony_ci 2206cd6a6acSopenharmony_ciint hashtab_map(hashtab_t h, 2216cd6a6acSopenharmony_ci int (*apply) (hashtab_key_t k, 2226cd6a6acSopenharmony_ci hashtab_datum_t d, void *args), void *args) 2236cd6a6acSopenharmony_ci{ 2246cd6a6acSopenharmony_ci unsigned int i; 2256cd6a6acSopenharmony_ci hashtab_ptr_t cur; 2266cd6a6acSopenharmony_ci int ret; 2276cd6a6acSopenharmony_ci 2286cd6a6acSopenharmony_ci if (!h) 2296cd6a6acSopenharmony_ci return SEPOL_OK; 2306cd6a6acSopenharmony_ci 2316cd6a6acSopenharmony_ci for (i = 0; i < h->size; i++) { 2326cd6a6acSopenharmony_ci cur = h->htable[i]; 2336cd6a6acSopenharmony_ci while (cur != NULL) { 2346cd6a6acSopenharmony_ci ret = apply(cur->key, cur->datum, args); 2356cd6a6acSopenharmony_ci if (ret) 2366cd6a6acSopenharmony_ci return ret; 2376cd6a6acSopenharmony_ci cur = cur->next; 2386cd6a6acSopenharmony_ci } 2396cd6a6acSopenharmony_ci } 2406cd6a6acSopenharmony_ci return SEPOL_OK; 2416cd6a6acSopenharmony_ci} 2426cd6a6acSopenharmony_ci 2436cd6a6acSopenharmony_civoid hashtab_hash_eval(hashtab_t h, char *tag) 2446cd6a6acSopenharmony_ci{ 2456cd6a6acSopenharmony_ci unsigned int i; 2466cd6a6acSopenharmony_ci int chain_len, slots_used, max_chain_len; 2476cd6a6acSopenharmony_ci hashtab_ptr_t cur; 2486cd6a6acSopenharmony_ci 2496cd6a6acSopenharmony_ci slots_used = 0; 2506cd6a6acSopenharmony_ci max_chain_len = 0; 2516cd6a6acSopenharmony_ci for (i = 0; i < h->size; i++) { 2526cd6a6acSopenharmony_ci cur = h->htable[i]; 2536cd6a6acSopenharmony_ci if (cur) { 2546cd6a6acSopenharmony_ci slots_used++; 2556cd6a6acSopenharmony_ci chain_len = 0; 2566cd6a6acSopenharmony_ci while (cur) { 2576cd6a6acSopenharmony_ci chain_len++; 2586cd6a6acSopenharmony_ci cur = cur->next; 2596cd6a6acSopenharmony_ci } 2606cd6a6acSopenharmony_ci 2616cd6a6acSopenharmony_ci if (chain_len > max_chain_len) 2626cd6a6acSopenharmony_ci max_chain_len = chain_len; 2636cd6a6acSopenharmony_ci } 2646cd6a6acSopenharmony_ci } 2656cd6a6acSopenharmony_ci 2666cd6a6acSopenharmony_ci printf 2676cd6a6acSopenharmony_ci ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", 2686cd6a6acSopenharmony_ci tag, h->nel, slots_used, h->size, max_chain_len); 2696cd6a6acSopenharmony_ci} 270