*.o
-*.coquet*
+tmp/*
a.out
obj/*
bin/*
SRCFILES := unix.c util.c coquet.c superblock.c sha2.c testvfs.c
SRC := $(addprefix $(SRCDIR)/,$(SRCFILES))
-DEPSRC := $(wildcard $(SRCDIR)/*.c)
-DEPS = $(DEPSRC:$(SRCDIR)/%.c=$(OBJDIR)/%.d)
-OBJ := $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
+CLISRC := $(SRC) $(SRCDIR)/main.c
+TESTSRC := $(SRC) $(SRCDIR)/test.c
-TESTDEPS = $(DEPSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.d)
-TESTOBJ := $(SRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.o)
+MAINDEPS = $(CLISRC:$(SRCDIR)/%.c=$(OBJDIR)/%.d)
+TESTDEPS = $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.d)
+
+CLIOBJ := $(CLISRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
+TESTOBJ := $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.o)
LIBS =
CC = gcc
-CFLAGS = -g -Wall --std=c99
+CFLAGS = -Wall --std=c99
+MAINCFLAGS = -O3
+TESTCFLAGS = -g
.PHONY: default all clean test
default: $(BINDIR)/coquet-cli $(BINDIR)/coquet-test
all: default
-obj/test:
- -mkdir obj/test
+# .c -> .o
$(OBJDIR)/%.o: $(SRCDIR)/%.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) $(MAINCFLAGS) -c $< -o $@
+
+$(TESTOBJDIR)/%.o: $(SRCDIR)/%.c
+ $(CC) $(CFLAGS) $(TESTCFLAGS) -DCOQUET_TEST -c $< -o $@
-$(TESTOBJDIR)/%.o: $(SRCDIR)/%.c obj/test
- $(CC) $(CFLAGS) -DCOQUET_TEST -c $< -o $@
+# .c -> .d
$(OBJDIR)/%.d: $(SRCDIR)/%.c
$(CC) -MM -MP -MT $(@:.d=.o) $< > $@
-$(TESTOBJDIR)/%.d: $(SRCDIR)/%.c obj/test
+$(TESTOBJDIR)/%.d: $(SRCDIR)/%.c
$(CC) -DCOQUET_TEST -MM -MP -MT $(@:.d=.o) $< > $@
-$(BINDIR)/coquet-cli: $(OBJ) $(OBJDIR)/main.o
- $(CC) $(OBJ) $(OBJDIR)/main.o -Wall $(LIBS) -o $@
+# .o -> bin
+
+$(BINDIR)/coquet-cli: $(CLIOBJ)
+ $(CC) $(CLIOBJ) -Wall $(LIBS) -o $@
-$(BINDIR)/coquet-test: $(TESTOBJ) $(TESTOBJDIR)/test.o
- $(CC) $(TESTOBJ) $(TESTOBJDIR)/test.o -Wall $(LIBS) -o $@
+$(BINDIR)/coquet-test: $(TESTOBJ)
+ $(CC) $(TESTOBJ) -Wall $(LIBS) -o $@
# .PRECIOUS: $(TARGET) $(OBJECTS)
-rm -f $(TESTOBJDIR)/*
-rm -f $(BINDIR)/*
--include $(DEPS)
+-include $(MAINDEPS)
-include $(TESTDEPS)
#ifdef COQUET_TEST
void test_bail(coquet_t * cq, int error_code);
void test_unlink(char *path);
+void test_file_compare(char *got, char *expected);
+void test_assert(int is_true, char *msg);
#endif
#endif
* +-------------------+
* | block_size | 0 1
* | nursery_size | 1 1
+ * | unused | 2 126
* +-------------------+
- * | unused | 2 509
+ * | description | 128 128
* +-------------------+
- * | reserved | 511 1
+ * | unused | 256 256
* +-------------------+
- *
- * The reserved byte is to allow locking to work via superblock page.
- * Range must exist to write, hence lock code may write this byte at
- * offset 0x00007FFF
*/
struct cq_super default_super = {
return r;
}
- r = extract_half(super_bytes,&super_a);
- r2 = extract_half(super_bytes+HALF_BYTES,&super_b);
+ r = !!extract_half(super_bytes,&super_a);
+ r2 = !!extract_half(super_bytes+HALF_BYTES,&super_b);
switch(r*2+r2) {
case 3: /* both valid */
use_b = (super_b.sb_serial > super_a.sb_serial);
void test_superblock() {
coquet_t cq;
- int r;
+ int i,r;
struct cq_super super;
printf("testing superblock\n");
+
r = coquet_init(&cq,"tmp/test");
test_bail(&cq,r);
-
+ testvfs_fakerandom(cq.vfs_data,0xA5);
+
+ /* simple load/save test to check data is in the right place */
+
test_unlink("tmp/test.coquet");
+
r = (cq.vfs_funcs.open)(cq.vfs_data,COQUET_FILE_MAIN,COQUET_CMODE_EITHER);
test_bail(&cq,r);
- testvfs_fakerandom(cq.vfs_data,0xA5);
r = cq_super_load(&cq,&super,1);
test_bail(&cq,r);
cq_super_save(&cq,&super,1);
test_bail(&cq,r);
- testvfs_fakerandom(cq.vfs_data,-1);
+
+ super.desired.nursery_size = 11; /* change something for B */
+ cq_super_save(&cq,&super,1);
+ test_bail(&cq,r);
r = (cq.vfs_funcs.close)(cq.vfs_data,COQUET_FILE_MAIN);
test_bail(&cq,r);
+ test_file_compare("tmp/test.coquet","testdata/sb1.coquet");
+
+ /* reopen to check the marshalling */
+ r = (cq.vfs_funcs.open)(cq.vfs_data,COQUET_FILE_MAIN,COQUET_CMODE_EITHER);
+ test_bail(&cq,r);
+
+ r = cq_super_load(&cq,&super,1);
+ test_bail(&cq,r);
+
+ test_assert(super.version == COQUET_VERSION,"version");
+ test_assert(super.sb_serial == 2,"serial");
+ test_assert(super.from_b == 1,"from_b");
+ test_assert(super.current.block_size == 12,"cbsize");
+ test_assert(super.desired.block_size == 12,"dbsize");
+ test_assert(super.current.nursery_size == 10,"cnurs");
+ test_assert(super.desired.nursery_size == 11,"dnurs");
+ for(i=0;i<GLOBAL_IV_LEN;i++)
+ test_assert(super.global_iv[i] == 0xA5,"iv");
+
+ r = (cq.vfs_funcs.close)(cq.vfs_data,COQUET_FILE_MAIN);
+ test_bail(&cq,r);
+
+ testvfs_fakerandom(cq.vfs_data,-1);
r = coquet_finish(&cq);
test_bail(&cq,r);
}
+/* To test:
+
+creation
+corruption
+a/b choice
+magic
+
+*/
+
#endif
#define HALF_BYTES 2048
#define SUPER_BYTES (HALF_BYTES*2)
#define GLOBAL_IV_LEN 32
-#define SUPERBLOCK_LAST_OFFSET (SUPER_BYTES-1)
+#define NUM_LOCKS 32
struct cq_super_config {
uint8_t block_size; /* log2 bytes */
#include <stdlib.h>
#include <errno.h>
#include <string.h>
+#include <fcntl.h>
#include "sha2.h"
#include "superblock.h"
+void test_assert(int is_true, char *msg) {
+ if(!is_true) {
+ fprintf(stderr,"assertion '%s' failed\n",msg);
+ exit(1);
+ }
+}
+
void test_unlink(char *path) {
int r;
}
}
+#define RFBUFLEN 1024
+static void readfile(char *path, char **out, int *len) {
+ int fd, r;
+ char buffer[RFBUFLEN];
+
+ *out = NULL;
+ *len = 0;
+ fd = open(path,O_RDONLY);
+ if(fd<0) {
+ fprintf(stderr,"failed to read '%s': %s\n",path,strerror(errno));
+ exit(1);
+ }
+ while(1) {
+ r = read(fd,buffer,RFBUFLEN);
+ if(r<0) {
+ fprintf(stderr,"failed to read '%s': %s\n",path,strerror(errno));
+ exit(1);
+ } else if(r>0) {
+ *out = realloc(*out,(*len)+r);
+ if(*out == NULL) {
+ fprintf(stderr,"realloc failed\n");
+ exit(1);
+ }
+ memcpy((*out)+(*len),buffer,r);
+ *len += r;
+
+ } else {
+ break;
+ }
+ }
+}
+
+void test_file_compare(char *got, char *expected) {
+ char *got_data, *exp_data;
+ int got_len, exp_len;
+
+ readfile(got,&got_data,&got_len);
+ readfile(expected,&exp_data,&exp_len);
+ if(got_len != exp_len || memcmp(got_data,exp_data,exp_len)) {
+ /* different! */
+ fprintf(stderr,"'%s' (got) and '%s' (expected) differ\n",got,expected);
+ exit(1);
+ }
+ free(got_data);
+ free(exp_data);
+}
+
void test_bail(coquet_t * cq, int error_code) {
char *msg;
}
/* Lock region needs to exist. We can append zeroes.*/
- r = min_size(pd,SUPERBLOCK_LAST_OFFSET);
+ r = min_size(pd,SUPER_BYTES+LOCK_BLOCK*NUM_LOCKS);
if(r != COQUET_RET_OK) {
return r;
}