|
Packit |
366192 |
/* Copyright (C) 2005 Red Hat, Inc. */
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Object: dbase_llist_t (Linked List)
|
|
Packit |
366192 |
* Partially Implements: dbase_t (Database)
|
|
Packit |
366192 |
*/
|
|
Packit |
366192 |
|
|
Packit |
366192 |
struct dbase_llist;
|
|
Packit |
366192 |
typedef struct dbase_llist dbase_t;
|
|
Packit |
366192 |
#define DBASE_DEFINED
|
|
Packit |
366192 |
|
|
Packit |
366192 |
#include <stdlib.h>
|
|
Packit |
366192 |
#include "debug.h"
|
|
Packit |
366192 |
#include "handle.h"
|
|
Packit |
366192 |
#include "database_llist.h"
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_needs_resync(semanage_handle_t * handle, dbase_llist_t * dbase)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int cache_serial;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase->cache_serial < 0)
|
|
Packit |
366192 |
return 1;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_serial = handle->funcs->get_serial(handle);
|
|
Packit |
366192 |
if (cache_serial < 0)
|
|
Packit |
366192 |
return 1;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (cache_serial != dbase->cache_serial) {
|
|
Packit |
366192 |
dbase_llist_drop_cache(dbase);
|
|
Packit |
366192 |
dbase->cache_serial = -1;
|
|
Packit |
366192 |
return 1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Helper for adding records to the cache */
|
|
Packit |
366192 |
int dbase_llist_cache_prepend(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase, const record_t * data)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Initialize */
|
|
Packit |
366192 |
cache_entry_t *entry = (cache_entry_t *) malloc(sizeof(cache_entry_t));
|
|
Packit |
366192 |
if (entry == NULL)
|
|
Packit |
366192 |
goto omem;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase->rtable->clone(handle, data, &entry->data) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
entry->prev = NULL;
|
|
Packit |
366192 |
entry->next = dbase->cache;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Link */
|
|
Packit |
366192 |
if (dbase->cache != NULL)
|
|
Packit |
366192 |
dbase->cache->prev = entry;
|
|
Packit |
366192 |
if (dbase->cache_tail == NULL)
|
|
Packit |
366192 |
dbase->cache_tail = entry;
|
|
Packit |
366192 |
dbase->cache = entry;
|
|
Packit |
366192 |
dbase->cache_sz++;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
omem:
|
|
Packit |
366192 |
ERR(handle, "out of memory");
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not cache record");
|
|
Packit |
366192 |
free(entry);
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void dbase_llist_drop_cache(dbase_llist_t * dbase)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase->cache_serial < 0)
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *prev, *ptr = dbase->cache;
|
|
Packit |
366192 |
while (ptr != NULL) {
|
|
Packit |
366192 |
prev = ptr;
|
|
Packit |
366192 |
ptr = ptr->next;
|
|
Packit |
366192 |
dbase->rtable->free(prev->data);
|
|
Packit |
366192 |
free(prev);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->cache_serial = -1;
|
|
Packit |
366192 |
dbase->modified = 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_set_serial(semanage_handle_t * handle, dbase_llist_t * dbase)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int cache_serial = handle->funcs->get_serial(handle);
|
|
Packit |
366192 |
if (cache_serial < 0) {
|
|
Packit |
366192 |
ERR(handle, "could not update cache serial");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->cache_serial = cache_serial;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Helper for finding records in the cache */
|
|
Packit |
366192 |
static int dbase_llist_cache_locate(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key,
|
|
Packit |
366192 |
cache_entry_t ** entry)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *ptr;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Implemented in parent */
|
|
Packit |
366192 |
if (dbase->dtable->cache(handle, dbase) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
|
|
Packit |
366192 |
if (!dbase->rtable->compare(ptr->data, key)) {
|
|
Packit |
366192 |
*entry = ptr;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return STATUS_NODATA;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not complete cache lookup");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_exists(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key, int *response)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *entry;
|
|
Packit |
366192 |
int status;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
status = dbase_llist_cache_locate(handle, dbase, key, &entry);
|
|
Packit |
366192 |
if (status < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
*response = (status != STATUS_NODATA);
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not check if record exists");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_add(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key __attribute__ ((unused)),
|
|
Packit |
366192 |
const record_t * data)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->modified = 1;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not add record to the database");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_set(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key, const record_t * data)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *entry;
|
|
Packit |
366192 |
int status;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
status = dbase_llist_cache_locate(handle, dbase, key, &entry);
|
|
Packit |
366192 |
if (status < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
if (status == STATUS_NODATA) {
|
|
Packit |
366192 |
ERR(handle, "record not found in the database");
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
} else {
|
|
Packit |
366192 |
dbase->rtable->free(entry->data);
|
|
Packit |
366192 |
if (dbase->rtable->clone(handle, data, &entry->data) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->modified = 1;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not set record value");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_modify(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key, const record_t * data)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *entry;
|
|
Packit |
366192 |
int status;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
status = dbase_llist_cache_locate(handle, dbase, key, &entry);
|
|
Packit |
366192 |
if (status < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
if (status == STATUS_NODATA) {
|
|
Packit |
366192 |
if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
} else {
|
|
Packit |
366192 |
dbase->rtable->free(entry->data);
|
|
Packit |
366192 |
if (dbase->rtable->clone(handle, data, &entry->data) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->modified = 1;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not modify record value");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)),
|
|
Packit |
366192 |
dbase_llist_t * dbase, unsigned int *response)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
*response = dbase->cache_sz;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_query(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
const record_key_t * key, record_t ** response)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *entry;
|
|
Packit |
366192 |
int status;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
status = dbase_llist_cache_locate(handle, dbase, key, &entry);
|
|
Packit |
366192 |
if (status < 0 || status == STATUS_NODATA)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase->rtable->clone(handle, entry->data, response) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not query record value");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_iterate(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
int (*fn) (const record_t * record,
|
|
Packit |
366192 |
void *fn_arg), void *arg)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int rc;
|
|
Packit |
366192 |
cache_entry_t *ptr;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
|
|
Packit |
366192 |
|
|
Packit |
366192 |
rc = fn(ptr->data, arg);
|
|
Packit |
366192 |
if (rc < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
else if (rc > 0)
|
|
Packit |
366192 |
break;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
ERR(handle, "could not iterate over records");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)),
|
|
Packit |
366192 |
dbase_llist_t * dbase, const record_key_t * key)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *ptr, *prev = NULL;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
|
|
Packit |
366192 |
if (!dbase->rtable->compare(ptr->data, key)) {
|
|
Packit |
366192 |
if (prev != NULL)
|
|
Packit |
366192 |
prev->next = ptr->next;
|
|
Packit |
366192 |
else
|
|
Packit |
366192 |
dbase->cache = ptr->next;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (ptr->next != NULL)
|
|
Packit |
366192 |
ptr->next->prev = ptr->prev;
|
|
Packit |
366192 |
else
|
|
Packit |
366192 |
dbase->cache_tail = ptr->prev;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->rtable->free(ptr->data);
|
|
Packit |
366192 |
dbase->cache_sz--;
|
|
Packit |
366192 |
free(ptr);
|
|
Packit |
366192 |
dbase->modified = 1;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
} else
|
|
Packit |
366192 |
prev = ptr;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int old_serial = dbase->cache_serial;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (dbase_llist_set_serial(handle, dbase) < 0) {
|
|
Packit |
366192 |
ERR(handle, "could not set serial of cleared dbase");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (old_serial >= 0) {
|
|
Packit |
366192 |
cache_entry_t *prev, *ptr = dbase->cache;
|
|
Packit |
366192 |
while (ptr != NULL) {
|
|
Packit |
366192 |
prev = ptr;
|
|
Packit |
366192 |
ptr = ptr->next;
|
|
Packit |
366192 |
dbase->rtable->free(prev->data);
|
|
Packit |
366192 |
free(prev);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
dbase->cache = NULL;
|
|
Packit |
366192 |
dbase->cache_tail = NULL;
|
|
Packit |
366192 |
dbase->cache_sz = 0;
|
|
Packit |
366192 |
dbase->modified = 1;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int dbase_llist_list(semanage_handle_t * handle,
|
|
Packit |
366192 |
dbase_llist_t * dbase,
|
|
Packit |
366192 |
record_t *** records, unsigned int *count)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cache_entry_t *ptr;
|
|
Packit |
366192 |
record_t **tmp_records = NULL;
|
|
Packit |
366192 |
unsigned int tmp_count;
|
|
Packit |
366192 |
int i = 0;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
tmp_count = dbase->cache_sz;
|
|
Packit |
366192 |
if (tmp_count > 0) {
|
|
Packit |
366192 |
tmp_records = (record_t **)
|
|
Packit |
366192 |
calloc(tmp_count, sizeof(record_t *));
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (tmp_records == NULL)
|
|
Packit |
366192 |
goto omem;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
|
|
Packit |
366192 |
if (dbase->rtable->clone(handle,
|
|
Packit |
366192 |
ptr->data,
|
|
Packit |
366192 |
&tmp_records[i]) < 0)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
i++;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
*records = tmp_records;
|
|
Packit |
366192 |
*count = tmp_count;
|
|
Packit |
366192 |
return STATUS_SUCCESS;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
omem:
|
|
Packit |
366192 |
ERR(handle, "out of memory");
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
if (tmp_records) {
|
|
Packit |
366192 |
for (; i >= 0; i--)
|
|
Packit |
366192 |
dbase->rtable->free(tmp_records[i]);
|
|
Packit |
366192 |
free(tmp_records);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
ERR(handle, "could not allocate record array");
|
|
Packit |
366192 |
return STATUS_ERR;
|
|
Packit |
366192 |
}
|