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