| /* Copyright (C) 2005 Red Hat, Inc. */ |
| |
| /* Object: dbase_file_t (File) |
| * Extends: dbase_llist_t (Linked List) |
| * Implements: dbase_t (Database) |
| */ |
| |
| struct dbase_file; |
| typedef struct dbase_file dbase_t; |
| #define DBASE_DEFINED |
| |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdio_ext.h> |
| #include "debug.h" |
| #include "handle.h" |
| #include "parse_utils.h" |
| #include "database_file.h" |
| #include "database_llist.h" |
| #include "semanage_store.h" |
| |
| /* FILE dbase */ |
| struct dbase_file { |
| |
| /* Parent object - must always be |
| * the first field - here we are using |
| * a linked list to store the records */ |
| dbase_llist_t llist; |
| |
| /* Backing path for read-only[0] and transaction[1] */ |
| const char *path[2]; |
| |
| /* FILE extension */ |
| record_file_table_t *rftable; |
| }; |
| |
| static int dbase_file_cache(semanage_handle_t * handle, dbase_file_t * dbase) |
| { |
| |
| record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); |
| record_file_table_t *rftable = dbase->rftable; |
| |
| record_t *process_record = NULL; |
| int pstatus = STATUS_SUCCESS; |
| |
| parse_info_t *parse_info = NULL; |
| const char *fname = NULL; |
| |
| /* Already cached */ |
| if (!dbase_llist_needs_resync(handle, &dbase->llist)) |
| return STATUS_SUCCESS; |
| |
| /* Update cache serial */ |
| dbase_llist_cache_init(&dbase->llist); |
| if (dbase_llist_set_serial(handle, &dbase->llist) < 0) |
| goto err; |
| |
| fname = dbase->path[handle->is_in_transaction]; |
| |
| if (parse_init(handle, fname, NULL, &parse_info) < 0) |
| goto err; |
| |
| if (parse_open(handle, parse_info) < 0) |
| goto err; |
| |
| /* Main processing loop */ |
| do { |
| |
| /* Create record */ |
| if (rtable->create(handle, &process_record) < 0) |
| goto err; |
| |
| /* Parse record */ |
| pstatus = rftable->parse(handle, parse_info, process_record); |
| |
| /* Parse error */ |
| if (pstatus < 0) |
| goto err; |
| |
| /* End of file */ |
| else if (pstatus == STATUS_NODATA) |
| break; |
| |
| /* Prepend to cache */ |
| if (dbase_llist_cache_prepend(handle, &dbase->llist, |
| process_record) < 0) |
| goto err; |
| |
| rtable->free(process_record); |
| process_record = NULL; |
| |
| } while (pstatus != STATUS_NODATA); |
| |
| rtable->free(process_record); |
| parse_close(parse_info); |
| parse_release(parse_info); |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not cache file database"); |
| rtable->free(process_record); |
| if (parse_info) { |
| parse_close(parse_info); |
| parse_release(parse_info); |
| } |
| dbase_llist_drop_cache(&dbase->llist); |
| return STATUS_ERR; |
| } |
| |
| /* Flush database to file */ |
| static int dbase_file_flush(semanage_handle_t * handle, dbase_file_t * dbase) |
| { |
| |
| record_file_table_t *rftable = dbase->rftable; |
| |
| cache_entry_t *ptr; |
| const char *fname = NULL; |
| FILE *str = NULL; |
| |
| if (!dbase_llist_is_modified(&dbase->llist)) |
| return STATUS_SUCCESS; |
| |
| fname = dbase->path[handle->is_in_transaction]; |
| |
| str = fopen(fname, "w"); |
| if (!str) { |
| ERR(handle, "could not open %s for writing: %s", |
| fname, strerror(errno)); |
| goto err; |
| } |
| __fsetlocking(str, FSETLOCKING_BYCALLER); |
| |
| if (fprintf(str, "# This file is auto-generated by libsemanage\n" |
| "# Do not edit directly.\n\n") < 0) { |
| |
| ERR(handle, "could not write file header for %s", fname); |
| goto err; |
| } |
| |
| for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) { |
| if (rftable->print(handle, ptr->data, str) < 0) |
| goto err; |
| } |
| |
| dbase_llist_set_modified(&dbase->llist, 0); |
| fclose(str); |
| return STATUS_SUCCESS; |
| |
| err: |
| if (str != NULL) |
| fclose(str); |
| |
| ERR(handle, "could not flush database to file"); |
| return STATUS_ERR; |
| } |
| |
| int dbase_file_init(semanage_handle_t * handle, |
| const char *path_ro, |
| const char *path_rw, |
| record_table_t * rtable, |
| record_file_table_t * rftable, dbase_file_t ** dbase) |
| { |
| |
| dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t)); |
| |
| if (!tmp_dbase) |
| goto omem; |
| |
| tmp_dbase->path[0] = path_ro; |
| tmp_dbase->path[1] = path_rw; |
| tmp_dbase->rftable = rftable; |
| dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE); |
| |
| *dbase = tmp_dbase; |
| |
| return STATUS_SUCCESS; |
| |
| omem: |
| ERR(handle, "out of memory, could not initialize file database"); |
| free(tmp_dbase); |
| return STATUS_ERR; |
| } |
| |
| /* Release dbase resources */ |
| void dbase_file_release(dbase_file_t * dbase) |
| { |
| |
| dbase_llist_drop_cache(&dbase->llist); |
| free(dbase); |
| } |
| |
| /* FILE dbase - method table implementation */ |
| dbase_table_t SEMANAGE_FILE_DTABLE = { |
| |
| /* Cache/Transactions */ |
| .cache = dbase_file_cache, |
| .drop_cache = (void *)dbase_llist_drop_cache, |
| .flush = dbase_file_flush, |
| .is_modified = (void *)dbase_llist_is_modified, |
| |
| /* Database API */ |
| .iterate = (void *)dbase_llist_iterate, |
| .exists = (void *)dbase_llist_exists, |
| .list = (void *)dbase_llist_list, |
| .add = (void *)dbase_llist_add, |
| .set = (void *)dbase_llist_set, |
| .del = (void *)dbase_llist_del, |
| .clear = (void *)dbase_llist_clear, |
| .modify = (void *)dbase_llist_modify, |
| .query = (void *)dbase_llist_query, |
| .count = (void *)dbase_llist_count, |
| |
| /* Polymorphism */ |
| .get_rtable = (void *)dbase_llist_get_rtable |
| }; |