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 	key = NULL;
    158 	dbase->modified = 1;
    159 	return STATUS_SUCCESS;
    160 
    161       err:
    162 	ERR(handle, "could not add record to the database");
    163 	return STATUS_ERR;
    164 }
    165 
    166 int dbase_llist_set(semanage_handle_t * handle,
    167 		    dbase_llist_t * dbase,
    168 		    const record_key_t * key, const record_t * data)
    169 {
    170 
    171 	cache_entry_t *entry;
    172 	int status;
    173 
    174 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    175 	if (status < 0)
    176 		goto err;
    177 	if (status == STATUS_NODATA) {
    178 		ERR(handle, "record not found in the database");
    179 		goto err;
    180 	} else {
    181 		dbase->rtable->free(entry->data);
    182 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
    183 			goto err;
    184 	}
    185 
    186 	dbase->modified = 1;
    187 	return STATUS_SUCCESS;
    188 
    189       err:
    190 	ERR(handle, "could not set record value");
    191 	return STATUS_ERR;
    192 }
    193 
    194 int dbase_llist_modify(semanage_handle_t * handle,
    195 		       dbase_llist_t * dbase,
    196 		       const record_key_t * key, const record_t * data)
    197 {
    198 
    199 	cache_entry_t *entry;
    200 	int status;
    201 
    202 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    203 	if (status < 0)
    204 		goto err;
    205 	if (status == STATUS_NODATA) {
    206 		if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
    207 			goto err;
    208 	} else {
    209 		dbase->rtable->free(entry->data);
    210 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
    211 			goto err;
    212 	}
    213 
    214 	dbase->modified = 1;
    215 	return STATUS_SUCCESS;
    216 
    217       err:
    218 	ERR(handle, "could not modify record value");
    219 	return STATUS_ERR;
    220 }
    221 
    222 hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)),
    223 			     dbase_llist_t * dbase, unsigned int *response)
    224 {
    225 
    226 	*response = dbase->cache_sz;
    227 	handle = NULL;
    228 	return STATUS_SUCCESS;
    229 }
    230 
    231 int dbase_llist_query(semanage_handle_t * handle,
    232 		      dbase_llist_t * dbase,
    233 		      const record_key_t * key, record_t ** response)
    234 {
    235 
    236 	cache_entry_t *entry;
    237 	int status;
    238 
    239 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
    240 	if (status < 0 || status == STATUS_NODATA)
    241 		goto err;
    242 
    243 	if (dbase->rtable->clone(handle, entry->data, response) < 0)
    244 		goto err;
    245 
    246 	return STATUS_SUCCESS;
    247 
    248       err:
    249 	ERR(handle, "could not query record value");
    250 	return STATUS_ERR;
    251 }
    252 
    253 int dbase_llist_iterate(semanage_handle_t * handle,
    254 			dbase_llist_t * dbase,
    255 			int (*fn) (const record_t * record,
    256 				   void *fn_arg), void *arg)
    257 {
    258 
    259 	int rc;
    260 	cache_entry_t *ptr;
    261 
    262 	for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
    263 
    264 		rc = fn(ptr->data, arg);
    265 		if (rc < 0)
    266 			goto err;
    267 
    268 		else if (rc > 1)
    269 			break;
    270 	}
    271 
    272 	return STATUS_SUCCESS;
    273 
    274       err:
    275 	ERR(handle, "could not iterate over records");
    276 	return STATUS_ERR;
    277 }
    278 
    279 int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)),
    280 		    dbase_llist_t * dbase, const record_key_t * key)
    281 {
    282 
    283 	cache_entry_t *ptr, *prev = NULL;
    284 
    285 	for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
    286 		if (!dbase->rtable->compare(ptr->data, key)) {
    287 			if (prev != NULL)
    288 				prev->next = ptr->next;
    289 			else
    290 				dbase->cache = ptr->next;
    291 
    292 			if (ptr->next != NULL)
    293 				ptr->next->prev = ptr->prev;
    294 			else
    295 				dbase->cache_tail = ptr->prev;
    296 
    297 			dbase->rtable->free(ptr->data);
    298 			dbase->cache_sz--;
    299 			free(ptr);
    300 			dbase->modified = 1;
    301 			return STATUS_SUCCESS;
    302 		} else
    303 			prev = ptr;
    304 	}
    305 
    306 	handle = NULL;
    307 	return STATUS_SUCCESS;
    308 }
    309 
    310 int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase)
    311 {
    312 
    313 	int old_serial = dbase->cache_serial;
    314 
    315 	if (dbase_llist_set_serial(handle, dbase) < 0) {
    316 		ERR(handle, "could not set serial of cleared dbase");
    317 		return STATUS_ERR;
    318 	}
    319 
    320 	if (old_serial >= 0) {
    321 		cache_entry_t *prev, *ptr = dbase->cache;
    322 		while (ptr != NULL) {
    323 			prev = ptr;
    324 			ptr = ptr->next;
    325 			dbase->rtable->free(prev->data);
    326 			free(prev);
    327 		}
    328 	}
    329 
    330 	dbase->cache = NULL;
    331 	dbase->cache_tail = NULL;
    332 	dbase->cache_sz = 0;
    333 	dbase->modified = 1;
    334 	return STATUS_SUCCESS;
    335 }
    336 
    337 int dbase_llist_list(semanage_handle_t * handle,
    338 		     dbase_llist_t * dbase,
    339 		     record_t *** records, unsigned int *count)
    340 {
    341 
    342 	cache_entry_t *ptr;
    343 	record_t **tmp_records = NULL;
    344 	unsigned int tmp_count;
    345 	int i = 0;
    346 
    347 	tmp_count = dbase->cache_sz;
    348 	if (tmp_count > 0) {
    349 		tmp_records = (record_t **)
    350 		    calloc(tmp_count, sizeof(record_t *));
    351 
    352 		if (tmp_records == NULL)
    353 			goto omem;
    354 
    355 		for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
    356 			if (dbase->rtable->clone(handle,
    357 						 ptr->data,
    358 						 &tmp_records[i]) < 0)
    359 				goto err;
    360 			i++;
    361 		}
    362 	}
    363 
    364 	*records = tmp_records;
    365 	*count = tmp_count;
    366 	return STATUS_SUCCESS;
    367 
    368       omem:
    369 	ERR(handle, "out of memory");
    370 
    371       err:
    372 	if (tmp_records) {
    373 		for (; i >= 0; i--)
    374 			dbase->rtable->free(tmp_records[i]);
    375 		free(tmp_records);
    376 	}
    377 	ERR(handle, "could not allocate record array");
    378 	return STATUS_ERR;
    379 }
    380