203 lines
4.8 KiB
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();
|
|
}
|