#include #include #include #include #include #include "api.h" #include "error_codes.h" #include "6_database.h" api_plugin_t version = {.id = 6, .flag = 0, .major = 1, .minor = 0}; #pragma pack(push, 1) typedef struct p6_database_entry_s { uint32_t name; api_plugin_t creator; uint32_t length; // size_t would be better but its size is platfom dependant void *content; TAILQ_ENTRY(p6_database_entry_s) entries; } p6_database_entry_t; #pragma pack(pop) TAILQ_HEAD(tailhead, p6_database_entry_s) db_p = TAILQ_HEAD_INITIALIZER(db_p); uint8_t init = 0; static int p_init_db() { FILE *file; TAILQ_INIT(&db_p); if ((file = fopen("./.db", "a+")) == NULL) { // TODO: kill plugin perror("fopen"); return ERR_SYSCALL; } while (1) { p6_database_entry_t *new_entry; uint32_t r; if ((new_entry = malloc(sizeof *new_entry)) == NULL) { perror("malloc"); return ERR_MEMORY; } if ((r = fread(new_entry, 1, sizeof(new_entry->name) + sizeof(new_entry->creator) + sizeof(new_entry->length), file)) == 0 && ferror(file)) { perror("fread"); return ERR_READ; } // If file is truncated if (r != sizeof(new_entry->name) + sizeof(new_entry->creator) + sizeof(new_entry->length)) { free(new_entry); break; } else { void *data; uint32_t r; if ((data = malloc(new_entry->length)) == NULL) { perror("malloc"); return ERR_MEMORY; } if ((r = fread(data, 1, new_entry->length, file)) == 0 && ferror(file)) { perror("fread"); return ERR_READ; } // If file is truncated else if (r != new_entry->length) { free(new_entry); free(data); break; } else { new_entry->content = data; TAILQ_INSERT_TAIL(&db_p, new_entry, entries); } } } fclose(file); init = 1; return SUCCESS; } static int p_save_to_file() { FILE *file; p6_database_entry_t *entry; if ((file = fopen("./.db", "w")) == NULL) { perror("fopen"); return ERR_SYSCALL; } TAILQ_FOREACH(entry, &db_p, entries) { fwrite(&entry->name, 1, sizeof entry->name, file); fwrite(&entry->creator, 1, sizeof entry->creator, file); fwrite(&entry->length, 1, sizeof entry->length, file); fwrite(entry->content, 1, entry->length, file); } fclose(file); return SUCCESS; } static int p_add_data(uint32_t name, size_t length, void *content, api_plugin_t from) { p6_database_entry_t *entry; uint32_t found = 0; TAILQ_FOREACH(entry, &db_p, entries) { if (entry->name == name) { free(entry->content); found = 1; break; } } if (!found) { if ((entry = malloc(sizeof *entry)) == NULL){ perror("malloc"); return ERR_MEMORY; } entry->name = name; entry->creator = from; TAILQ_INSERT_TAIL(&db_p, entry, entries); } entry->length = length; if ((entry->content = malloc(length)) == NULL) { perror("malloc"); return ERR_MEMORY; } memcpy(entry->content, content, length); p_save_to_file(); return SUCCESS; } static void *p_retrieve_data(uint32_t name) { p6_database_entry_t *entry; TAILQ_FOREACH(entry, &db_p, entries) { if (entry->name == name) return entry; } return NULL; } static uint32_t p_remove_data(uint32_t name) { p6_database_entry_t *entry; TAILQ_FOREACH(entry, &db_p, entries) { if (entry->name == name) { free(entry->content); TAILQ_REMOVE(&db_p, entry, entries); free(entry); p_save_to_file(); return ERR_NOT_FOUND; } } return 0; } static void p_exec() { if (init == 0) { p_init_db(); /* p_add_data(3, 7, "biffle", (api_plugin_t){4, 0, 0, 0}); */ /* p6_database_entry_t *entry; */ /* entry = p_retrieve_data(3); */ /* printf("%s\n", entry->content); */ /* p_remove_data(3); */ /* entry = p_retrieve_data(3); */ /* printf("%p\n", entry); */ } p6_query_t *req; p6_response_t res; size_t length; api_plugin_t from = {0}; while (api_receive_message(&from, (void **)&req, &length) == 0) { res.content = NULL; res.length = 0; if (req->type == DB_QUERY_ADD) { p_add_data(req->name, req->length, req->content, from); res.err_code = SUCCESS; } else if (req->type == DB_QUERY_DELETE) { p_remove_data(req->name); res.err_code = SUCCESS; } else if (req->type == DB_QUERY_GET) { p6_database_entry_t *data = p_retrieve_data(req->name); res.length = data == NULL ? 0 : data->length; res.err_code = data == NULL ? ERR_NOT_FOUND : SUCCESS; res.content = data == NULL ? NULL : data->content; } api_send_message(from, &res, sizeof res, 1); } } void run() { p_exec(); } void run_instant() { p_exec(); }