Home | History | Annotate | Download | only in src
      1 /* Copyright (C) 2005 Red Hat, Inc. */
      2 
      3 /* Object: dbase_llist_t (Linked List)
      4  * Partially Implements: dbase_t (Database)
      5  */
      6 
      7 struct dbase_llist;
      8 typedef struct dbase_llist dbase_t;
      9 #define DBASE_DEFINED
     10 
     11 #include <stdlib.h>
     12 #include "debug.h"
     13 #include "handle.h"
     14 #include "database_llist.h"
     15 
     16 int dbase_llist_needs_resync(semanage_handle_t * handle, dbase_llist_t * dbase)
     17 {
     18 
     19 	int cache_serial;
     20 
     21 	if (dbase->cache_serial < 0)
     22 		return 1;
     23 
     24 	cache_serial = handle->funcs->get_serial(handle);
     25 	if (cache_serial < 0)
     26 		return 1;
     27 
     28 	if (cache_serial != dbase->cache_serial) {
     29 		dbase_llist_drop_cache(dbase);
     30 		dbase->cache_serial = -1;
     31 		return 1;
     32 	}
     33 	return 0;
     34 }
     35 
     36 /* Helper for adding records to the cache */
     37 int dbase_llist_cache_prepend(semanage_handle_t * handle,
     38 			      dbase_llist_t * dbase, const record_t * data)
     39 {
     40 
     41 	/* Initialize */
     42 	cache_entry_t *entry = (cache_entry_t *) malloc(sizeof(cache_entry_t));
     43 	if (entry == NULL)
     44 		goto omem;
     45 
     46 	if (dbase->rtable->clone(handle, data, &entry->data) < 0)
     47 		goto err;
     48 
     49 	entry->prev = NULL;
     50 	entry->next = dbase->cache;
     51 
     52 	/* Link */
     53 	if (dbase->cache != NULL)
     54 		dbase->cache->prev = entry;
     55 	if (dbase->cache_tail == NULL)
     56 		dbase->cache_tail = entry;
     57 	dbase->cache = entry;
     58 	dbase->cache_sz++;
     59 	return STATUS_SUCCESS;
     60 
     61       omem:
     62 	ERR(handle, "out of memory");
     63 
     64       err:
     65 	ERR(handle, "could not cache record");
     66 	free(entry);
     67 	return STATUS_ERR;
     68 }
     69 
     70 void dbase_llist_drop_cache(dbase_llist_t * dbase)
     71 {
     72 
     73 	if (dbase->cache_serial < 0)
     74 		return;
     75 
     76 	cache_entry_t *prev, *ptr = dbase->cache;
     77 	while (ptr != NULL) {
     78 		prev = ptr;
     79 		ptr = ptr->next;
     80 		dbase->rtable->free(prev->data);
     81 		free(prev);
     82 	}
     83 
     84 	dbase->cache_serial = -1;
     85 	dbase->modified = 0;
     86 }
     87 
     88 int dbase_llist_set_serial(semanage_handle_t * handle, dbase_llist_t * dbase)
     89 {
     90 
     91 	int cache_serial = handle->funcs->get_serial(handle);
     92 	if (cache_serial < 0) {
     93 		ERR(handle, "could not update cache serial");
     94 		return STATUS_ERR;
     95 	}
     96 
     97 	dbase->cache_serial = cache_serial;
     98 	return STATUS_SUCCESS;
     99 }
    100 
    101 /* Helper for finding records in the cache */
    102 static int dbase_llist_cache_locate(semanage_handle_t * handle,
    103 				    dbase_llist_t * dbase,
    104 				    const record_key_t * key,
    105 				    cache_entry_t ** entry)
    106 {
    107 
    108 	cache_entry_t *ptr;
    109 
    110 	/* Implemented in parent */
    111 	if (dbase->dtable->cache(handle, dbase) < 0)
    112 		goto err;
    113 
    114 	for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
    115 		if (!dbase->rtable->compare(ptr->data, key)) {
    116 			*entry = ptr;
    117 			return STATUS_SUCCESS;
    118 		}
    119 	}
    120 
    121 	return STATUS_NODATA;
    122 
    123       err:
    124 	ERR(handle, "could not complete cache lookup");
    125 	return STATUS_ERR;
    126 }
    127 
    128 int dbase_llist_exists(semanage_handle_t * handle,
    129 		       dbase_llist_t * dbase,
    130 		       const record_key_t * key, int *response)
    131 {
    132 
    133 	cache_entry_t *entry;
    134 	int status;
    135 
    136 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    137 	if (status < 0)
    138 		goto err;
    139 
    140 	*response = (status != STATUS_NODATA);
    141 	return STATUS_SUCCESS;
    142 
    143       err:
    144 	ERR(handle, "could not check if record exists");
    145 	return STATUS_ERR;
    146 }
    147 
    148 int dbase_llist_add(semanage_handle_t * handle,
    149 		    dbase_llist_t * dbase,
    150 		    const record_key_t * key __attribute__ ((unused)),
    151 			 const record_t * data)
    152 {
    153 
    154 	if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
    155 		goto err;
    156 
    157 	dbase->modified = 1;
    158 	return STATUS_SUCCESS;
    159 
    160       err:
    161 	ERR(handle, "could not add record to the database");
    162 	return STATUS_ERR;
    163 }
    164 
    165 int dbase_llist_set(semanage_handle_t * handle,
    166 		    dbase_llist_t * dbase,
    167 		    const record_key_t * key, const record_t * data)
    168 {
    169 
    170 	cache_entry_t *entry;
    171 	int status;
    172 
    173 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    174 	if (status < 0)
    175 		goto err;
    176 	if (status == STATUS_NODATA) {
    177 		ERR(handle, "record not found in the database");
    178 		goto err;
    179 	} else {
    180 		dbase->rtable->free(entry->data);
    181 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
    182 			goto err;
    183 	}
    184 
    185 	dbase->modified = 1;
    186 	return STATUS_SUCCESS;
    187 
    188       err:
    189 	ERR(handle, "could not set record value");
    190 	return STATUS_ERR;
    191 }
    192 
    193 int dbase_llist_modify(semanage_handle_t * handle,
    194 		       dbase_llist_t * dbase,
    195 		       const record_key_t * key, const record_t * data)
    196 {
    197 
    198 	cache_entry_t *entry;
    199 	int status;
    200 
    201 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    202 	if (status < 0)
    203 		goto err;
    204 	if (status == STATUS_NODATA) {
    205 		if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
    206 			goto err;
    207 	} else {
    208 		dbase->rtable->free(entry->data);
    209 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
    210 			goto err;
    211 	}
    212 
    213 	dbase->modified = 1;
    214 	return STATUS_SUCCESS;
    215 
    216       err:
    217 	ERR(handle, "could not modify record value");
    218 	return STATUS_ERR;
    219 }
    220 
    221 hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)),
    222 			     dbase_llist_t * dbase, unsigned int *response)
    223 {
    224 
    225 	*response = dbase->cache_sz;
    226 	return STATUS_SUCCESS;
    227 }
    228 
    229 int dbase_llist_query(semanage_handle_t * handle,
    230 		      dbase_llist_t * dbase,
    231 		      const record_key_t * key, record_t ** response)
    232 {
    233 
    234 	cache_entry_t *entry;
    235 	int status;
    236 
    237 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    238 	if (status < 0 || status == STATUS_NODATA)
    239 		goto err;
    240 
    241 	if (dbase->rtable->clone(handle, entry->data, response) < 0)
    242 		goto err;
    243 
    244 	return STATUS_SUCCESS;
    245 
    246       err:
    247 	ERR(handle, "could not query record value");
    248 	return STATUS_ERR;
    249 }
    250 
    251 int dbase_llist_iterate(semanage_handle_t * handle,
    252 			dbase_llist_t * dbase,
    253 			int (*fn) (const record_t * record,
    254 				   void *fn_arg), void *arg)
    255 {
    256 
    257 	int rc;
    258 	cache_entry_t *ptr;
    259 
    260 	for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
    261 
    262 		rc = fn(ptr->data, arg);
    263 		if (rc < 0)
    264 			goto err;
    265 
    266 		else if (rc > 1)
    267 			break;
    268 	}
    269 
    270 	return STATUS_SUCCESS;
    271 
    272       err:
    273 	ERR(handle, "could not iterate over records");
    274 	return STATUS_ERR;
    275 }
    276 
    277 int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)),
    278 		    dbase_llist_t * dbase, const record_key_t * key)
    279 {
    280 
    281 	cache_entry_t *ptr, *prev = NULL;
    282 
    283 	for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
    284 		if (!dbase->rtable->compare(ptr->data, key)) {
    285 			if (prev != NULL)
    286 				prev->next = ptr->next;
    287 			else
    288 				dbase->cache = ptr->next;
    289 
    290 			if (ptr->next != NULL)
    291 				ptr->next->prev = ptr->prev;
    292 			else
    293 				dbase->cache_tail = ptr->prev;
    294 
    295 			dbase->rtable->free(ptr->data);
    296 			dbase->cache_sz--;
    297 			free(ptr);
    298 			dbase->modified = 1;
    299 			return STATUS_SUCCESS;
    300 		} else
    301 			prev = ptr;
    302 	}
    303 
    304 	return STATUS_SUCCESS;
    305 }
    306 
    307 int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase)
    308 {
    309 
    310 	int old_serial = dbase->cache_serial;
    311 
    312 	if (dbase_llist_set_serial(handle, dbase) < 0) {
    313 		ERR(handle, "could not set serial of cleared dbase");
    314 		return STATUS_ERR;
    315 	}
    316 
    317 	if (old_serial >= 0) {
    318 		cache_entry_t *prev, *ptr = dbase->cache;
    319 		while (ptr != NULL) {
    320 			prev = ptr;
    321 			ptr = ptr->next;
    322 			dbase->rtable->free(prev->data);
    323 			free(prev);
    324 		}
    325 	}
    326 
    327 	dbase->cache = NULL;
    328 	dbase->cache_tail = NULL;
    329 	dbase->cache_sz = 0;
    330 	dbase->modified = 1;
    331 	return STATUS_SUCCESS;
    332 }
    333 
    334 int dbase_llist_list(semanage_handle_t * handle,
    335 		     dbase_llist_t * dbase,
    336 		     record_t *** records, unsigned int *count)
    337 {
    338 
    339 	cache_entry_t *ptr;
    340 	record_t **tmp_records = NULL;
    341 	unsigned int tmp_count;
    342 	int i = 0;
    343 
    344 	tmp_count = dbase->cache_sz;
    345 	if (tmp_count > 0) {
    346 		tmp_records = (record_t **)
    347 		    calloc(tmp_count, sizeof(record_t *));
    348 
    349 		if (tmp_records == NULL)
    350 			goto omem;
    351 
    352 		for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
    353 			if (dbase->rtable->clone(handle,
    354 						 ptr->data,
    355 						 &tmp_records[i]) < 0)
    356 				goto err;
    357 			i++;
    358 		}
    359 	}
    360 
    361 	*records = tmp_records;
    362 	*count = tmp_count;
    363 	return STATUS_SUCCESS;
    364 
    365       omem:
    366 	ERR(handle, "out of memory");
    367 
    368       err:
    369 	if (tmp_records) {
    370 		for (; i >= 0; i--)
    371 			dbase->rtable->free(tmp_records[i]);
    372 		free(tmp_records);
    373 	}
    374 	ERR(handle, "could not allocate record array");
    375 	return STATUS_ERR;
    376 }
    377