| /* |
| * Copyright 2011 Tresys Technology, LLC. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS |
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * The views and conclusions contained in the software and documentation are those |
| * of the authors and should not be interpreted as representing official policies, |
| * either expressed or implied, of Tresys Technology, LLC. |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| |
| #include <sepol/errcodes.h> |
| #include <sepol/policydb/hashtab.h> |
| #include <sepol/policydb/symtab.h> |
| |
| #include "cil_internal.h" |
| #include "cil_tree.h" |
| #include "cil_symtab.h" |
| #include "cil_mem.h" |
| #include "cil_strpool.h" |
| #include "cil_log.h" |
| |
| __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) static void cil_symtab_error(const char* msg, ...) |
| { |
| va_list ap; |
| va_start(ap, msg); |
| cil_vlog(CIL_ERR, msg, ap); |
| va_end(ap); |
| exit(1); |
| } |
| |
| void cil_symtab_init(symtab_t *symtab, unsigned int size) |
| { |
| int rc = symtab_init(symtab, size); |
| if (rc != SEPOL_OK) { |
| cil_symtab_error("Failed to create symtab\n"); |
| } |
| } |
| |
| void cil_symtab_datum_init(struct cil_symtab_datum *datum) |
| { |
| datum->name = NULL; |
| datum->fqn = NULL; |
| datum->symtab = NULL; |
| cil_list_init(&datum->nodes, CIL_LIST_ITEM); |
| } |
| |
| void cil_symtab_datum_destroy(struct cil_symtab_datum *datum) |
| { |
| cil_list_destroy(&datum->nodes, 0); |
| cil_symtab_remove_datum(datum); |
| } |
| |
| void cil_symtab_datum_remove_node(struct cil_symtab_datum *datum, struct cil_tree_node *node) |
| { |
| if (datum && datum->nodes != NULL) { |
| cil_list_remove(datum->nodes, CIL_NODE, node, 0); |
| if (datum->nodes->head == NULL) { |
| cil_symtab_datum_destroy(datum); |
| } |
| } |
| } |
| |
| /* This both initializes the datum and inserts it into the symtab. |
| Note that cil_symtab_datum_destroy() is the analog to the initializer portion */ |
| int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node) |
| { |
| int rc = hashtab_insert(symtab->table, key, (hashtab_datum_t)datum); |
| if (rc == SEPOL_OK) { |
| datum->name = key; |
| datum->fqn = key; |
| datum->symtab = symtab; |
| symtab->nprim++; |
| if (node) { |
| cil_list_append(datum->nodes, CIL_NODE, node); |
| } |
| } else if (rc != SEPOL_EEXIST) { |
| cil_symtab_error("Failed to insert datum into hashtab\n"); |
| } |
| |
| return rc; |
| } |
| |
| void cil_symtab_remove_datum(struct cil_symtab_datum *datum) |
| { |
| symtab_t *symtab = datum->symtab; |
| |
| if (symtab == NULL) { |
| return; |
| } |
| |
| hashtab_remove(symtab->table, datum->name, NULL, NULL); |
| symtab->nprim--; |
| datum->symtab = NULL; |
| } |
| |
| int cil_symtab_get_datum(symtab_t *symtab, char *key, struct cil_symtab_datum **datum) |
| { |
| *datum = (struct cil_symtab_datum*)hashtab_search(symtab->table, (hashtab_key_t)key); |
| if (*datum == NULL) { |
| return SEPOL_ENOENT; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| int cil_symtab_map(symtab_t *symtab, |
| int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), |
| void *args) |
| { |
| return hashtab_map(symtab->table, apply, args); |
| } |
| |
| static int __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args) |
| { |
| struct cil_symtab_datum *datum = d; |
| datum->symtab = NULL; |
| return SEPOL_OK; |
| } |
| |
| void cil_symtab_destroy(symtab_t *symtab) |
| { |
| if (symtab->table != NULL){ |
| cil_symtab_map(symtab, __cil_symtab_destroy_helper, NULL); |
| hashtab_destroy(symtab->table); |
| symtab->table = NULL; |
| } |
| } |
| |
| static void cil_complex_symtab_hash(struct cil_complex_symtab_key *ckey, int mask, intptr_t *hash) |
| { |
| intptr_t sum = ckey->key1 + ckey->key2 + ckey->key3 + ckey->key4; |
| *hash = (intptr_t)((sum >> 2) & mask); |
| } |
| |
| void cil_complex_symtab_init(struct cil_complex_symtab *symtab, unsigned int size) |
| { |
| symtab->htable = cil_calloc(size, sizeof(struct cil_complex_symtab *)); |
| |
| symtab->nelems = 0; |
| symtab->nslots = size; |
| symtab->mask = size - 1; |
| } |
| |
| int cil_complex_symtab_insert(struct cil_complex_symtab *symtab, |
| struct cil_complex_symtab_key *ckey, |
| struct cil_complex_symtab_datum *datum) |
| { |
| intptr_t hash; |
| struct cil_complex_symtab_node *node = NULL; |
| struct cil_complex_symtab_node *prev = NULL; |
| struct cil_complex_symtab_node *curr = NULL; |
| |
| node = cil_malloc(sizeof(*node)); |
| memset(node, 0, sizeof(*node)); |
| |
| node->ckey = ckey; |
| node->datum = datum; |
| |
| cil_complex_symtab_hash(ckey, symtab->mask, &hash); |
| |
| for (prev = NULL, curr = symtab->htable[hash]; curr != NULL; |
| prev = curr, curr = curr->next) { |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 == curr->ckey->key3 && |
| ckey->key4 == curr->ckey->key4) { |
| free(node); |
| return SEPOL_EEXIST; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 < curr->ckey->key2) { |
| break; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 < curr->ckey->key3) { |
| break; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 == curr->ckey->key3 && |
| ckey->key4 < curr->ckey->key4) { |
| break; |
| } |
| } |
| |
| if (prev != NULL) { |
| node->next = prev->next; |
| prev->next = node; |
| } else { |
| node->next = symtab->htable[hash]; |
| symtab->htable[hash] = node; |
| } |
| |
| symtab->nelems++; |
| |
| return SEPOL_OK; |
| } |
| |
| void cil_complex_symtab_search(struct cil_complex_symtab *symtab, |
| struct cil_complex_symtab_key *ckey, |
| struct cil_complex_symtab_datum **out) |
| { |
| intptr_t hash; |
| struct cil_complex_symtab_node *curr = NULL; |
| |
| cil_complex_symtab_hash(ckey, symtab->mask, &hash); |
| for (curr = symtab->htable[hash]; curr != NULL; curr = curr->next) { |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 == curr->ckey->key3 && |
| ckey->key4 == curr->ckey->key4) { |
| *out = curr->datum; |
| return; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 < curr->ckey->key2) { |
| break; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 < curr->ckey->key3) { |
| break; |
| } |
| |
| if (ckey->key1 == curr->ckey->key1 && |
| ckey->key2 == curr->ckey->key2 && |
| ckey->key3 == curr->ckey->key3 && |
| ckey->key4 < curr->ckey->key4) { |
| break; |
| } |
| } |
| |
| *out = NULL; |
| } |
| |
| void cil_complex_symtab_destroy(struct cil_complex_symtab *symtab) |
| { |
| struct cil_complex_symtab_node *curr = NULL; |
| struct cil_complex_symtab_node *temp = NULL; |
| unsigned int i; |
| |
| if (symtab == NULL) { |
| return; |
| } |
| |
| for (i = 0; i < symtab->nslots; i++) { |
| curr = symtab->htable[i]; |
| while (curr != NULL) { |
| temp = curr; |
| curr = curr->next; |
| free(temp); |
| } |
| symtab->htable[i] = NULL; |
| } |
| free(symtab->htable); |
| symtab->htable = NULL; |
| symtab->nelems = 0; |
| symtab->nslots = 0; |
| symtab->mask = 0; |
| } |