modular-worm/plugins/6_database.c

203 lines
4.8 KiB
C

#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <sys/queue.h>
#include <unistd.h>
#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();
}