Archived
1
0
Fork 0

Initial commit

This commit is contained in:
Henrik Hautakoski 2011-06-08 18:46:58 +02:00
commit b2df740514
19 changed files with 1640 additions and 0 deletions

225
cconf.c Normal file
View file

@ -0,0 +1,225 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <openssl/sha.h>
#include <arpa/inet.h>
#include "cconf.h"
/* we count NULL as part of the string ondisk */
#define strsize(str) (strlen(str) + 1)
static int sha1_write(SHA_CTX *ctx, int fd, void *buf, size_t size) {
SHA1_Update(ctx, buf, size);
return write(fd, buf, size);
}
static void write_int(SHA_CTX *ctx, int fd, int val) {
val = htonl(val);
sha1_write(ctx, fd, &val, sizeof val);
}
static void* read_entry_nr(void *buf, unsigned int *out) {
memcpy(out, buf, sizeof(*out));
*out = ntohl(*out);
return buf + sizeof(*out);
}
void cconf_free(struct cconf *c) {
int i, j;
if (!c)
return;
if (c->map.buf) {
free(c->target);
munmap(c->map.buf, c->map.size);
} else if (c->nr) {
for(i=0; i < c->nr; i++) {
struct target *t = c->target + i;
free(t->src);
free(t->dest);
for(j=0; j < t->nr; j++)
free(t->filter[j]);
free(t->filter);
}
free(c->target);
}
}
struct target* cconf_new_target(struct cconf *c) {
struct target *t;
c->target = realloc(c->target, (sizeof(struct target) * (c->nr + 1)));
t = c->target + (c->nr++);
memset(t, 0, sizeof(*t));
return t;
}
void cconf_add_filter(struct target *t, char *filter) {
if (!filter)
return;
t->filter = realloc(t->filter, sizeof(t->filter) * (t->nr + 1));
t->filter[t->nr++] = filter;
}
static size_t parse_filter(void *buf, struct target *target) {
size_t offset = read_entry_nr(buf, &target->nr) - buf;
if (target->nr) {
int i;
target->filter = malloc(sizeof(char *) * target->nr);
for(i=0; i < target->nr; i++) {
target->filter[i] = (char *) buf + offset;
offset += strsize(buf + offset);
}
}
return offset;
}
static size_t parse_target(void *buf, struct target *target) {
size_t offset;
target->src = (char *) buf;
offset = strsize(buf);
target->dest = (char *) buf + offset;
offset += strsize(buf + offset);
return offset;
}
static struct cconf* parse(void *buf, size_t size) {
struct cconf *c = calloc(1, sizeof(struct cconf));
int i;
/* move! */
c->map.buf = buf;
c->map.size = size;
buf = read_entry_nr(buf + sizeof(struct cconf_header), &c->nr);
c->target = calloc(sizeof(struct target), c->nr);
for(i=0; i < c->nr; i++) {
struct target *target = c->target + i;
buf += parse_target(buf, target);
buf += parse_filter(buf, target);
}
return c;
}
static int validate_hdr(struct cconf_header *hdr, size_t size) {
SHA_CTX ctx;
unsigned char sha1[20];
if (hdr->signature != htonl(CCONF_SIGNATURE) ||
hdr->version != htonl(1))
return -1;
SHA1_Init(&ctx);
SHA1_Update(&ctx, hdr, offsetof(struct cconf_header, crc));
SHA1_Update(&ctx, hdr + 1, size - sizeof(*hdr));
SHA1_Final(sha1, &ctx);
if (memcmp(sha1, hdr->crc, sizeof(hdr->crc)))
return -1;
return 0;
}
struct cconf* cconf_read(const char *file) {
int fd;
struct stat st;
void *buf;
fd = open(file, O_RDONLY);
if (fd < 0)
return NULL;
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
buf = MAP_FAILED;
if (!fstat(fd, &st) && st.st_size > sizeof(struct cconf_header)) {
buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
}
close(fd);
if (buf == MAP_FAILED)
return NULL;
if (validate_hdr(buf, st.st_size) < 0)
goto error;
return parse(buf, st.st_size);
error:
munmap(buf, st.st_size);
return NULL;
}
int cconf_write(int fd, struct cconf *c) {
int i;
SHA_CTX ctx;
struct cconf_header hdr;
hdr.signature = htonl(CCONF_SIGNATURE);
hdr.version = htonl(1);
SHA1_Init(&ctx);
SHA1_Update(&ctx, &hdr, offsetof(struct cconf_header, crc));
/* leave room for the header to be written later as CRC
will be calculated as we write the rest of the data */
lseek(fd, sizeof(hdr), SEEK_SET);
/* put number of targets */
write_int(&ctx, fd, c->nr);
for(i = 0; i < c->nr; i++) {
int j;
struct target *target = c->target + i;
if (!target->src || !target->dest)
return -1;
sha1_write(&ctx, fd, target->src, strsize(target->src));
sha1_write(&ctx, fd, target->dest, strsize(target->dest));
/* write number of filters */
write_int(&ctx, fd, target->nr);
for(j=0; j < target->nr; j++) {
sha1_write(&ctx, fd, target->filter[j],
strsize(target->filter[j]));
}
}
SHA1_Final(hdr.crc, &ctx);
/* write header */
lseek(fd, 0, SEEK_SET);
sha1_write(&ctx, fd, &hdr, sizeof(hdr));
return 0;
}