From 7bac1cdea882b31cfe28b87d6625ae0035d22aba Mon Sep 17 00:00:00 2001 From: Dan Sheppard Date: Wed, 23 Apr 2025 14:08:13 +0100 Subject: [PATCH] File size vfs method; in-memory test FS for slow tests. --- .vscode/settings.json | 3 +- Makefile | 10 +++--- doc/TODO | 4 ++- src/constants.h | 1 + src/coquet.c | 1 + src/superblock.c | 6 ++-- src/testvfs.c | 80 +++++++++++++++++++++++++++++++++++++++++-- src/unix.c | 16 +++++++++ src/vfs.h | 6 +++- 9 files changed, 115 insertions(+), 12 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4b4779a..b05135a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,6 @@ "files.associations": { "coquet.h": "c", "superblock.h": "c" - } + }, + "C_Cpp.dimInactiveRegions": false } \ No newline at end of file diff --git a/Makefile b/Makefile index a5b373f..63f8bb7 100644 --- a/Makefile +++ b/Makefile @@ -16,11 +16,11 @@ TESTDEPS = $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.d) CLIOBJ := $(CLISRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o) TESTOBJ := $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.o) -LIBS = -CC = gcc -CFLAGS = -Wall --std=c99 -MAINCFLAGS = -O3 -TESTCFLAGS = -g +LIBS := +CC := gcc +CFLAGS := -Wall --std=c99 +MAINCFLAGS := -O3 +TESTCFLAGS := -g .PHONY: default all clean test diff --git a/doc/TODO b/doc/TODO index d098b5c..6c87af5 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,3 +1,5 @@ * "Eventually" inserts * Replication -* Strict locking +* Strict locking option +* lock timeout + diff --git a/src/constants.h b/src/constants.h index ab0d70c..55e4e7d 100644 --- a/src/constants.h +++ b/src/constants.h @@ -10,6 +10,7 @@ #define COQUET_FILE_MAIN 0 #define COQUET_FILE_OLD 1 #define COQUET_FILE_TMP 2 +#define COQUET_FILE_NUM 3 /* remember to update messages */ #define COQUET_RET_OK 0 diff --git a/src/coquet.c b/src/coquet.c index 0da0fcb..aa3e3c5 100644 --- a/src/coquet.c +++ b/src/coquet.c @@ -15,6 +15,7 @@ vfs_t vfs_null = { .lock = NULL, .open = NULL, .close = NULL, + .size = NULL, .write = NULL, .read = NULL, .finish = NULL diff --git a/src/superblock.c b/src/superblock.c index bb6bd8a..d72b499 100644 --- a/src/superblock.c +++ b/src/superblock.c @@ -366,7 +366,8 @@ static void make_superblock(coquet_t *cq, bool also_b, struct cq_super super; uint8_t d; - test_unlink("tmp/test.coquet"); + r = (cq->vfs_funcs.delete)(cq->vfs_data,COQUET_FILE_MAIN); + test_bail(cq,r); test_open(cq); r = cq_super_load(cq,&super,1); @@ -399,6 +400,7 @@ void test_superblock_corruption() { r = coquet_init(&cq,"tmp/test"); test_bail(&cq,r); + testvfs_virtual(cq.vfs_data,1); testvfs_fakerandom(cq.vfs_data,0xA5); test_unlink("tmp/test.coquet"); @@ -424,6 +426,7 @@ void test_superblock_corruption() { make_superblock(&cq,1,2048+pos,12); } + testvfs_virtual(cq.vfs_data,0); testvfs_fakerandom(cq.vfs_data,-1); r = coquet_finish(&cq); test_bail(&cq,r); @@ -436,7 +439,6 @@ void test_superblock() { /* To test: -move tests to external drive to avoid wear creation a/b choice magic diff --git a/src/testvfs.c b/src/testvfs.c index 5d539a2..608fbc0 100644 --- a/src/testvfs.c +++ b/src/testvfs.c @@ -6,20 +6,28 @@ #include "coquet.h" struct test_data { - int fake_random; + int fake_random, virtual; + uint8_t * vfiles[COQUET_FILE_NUM]; + uint64_t vfile_len[COQUET_FILE_NUM]; vfs_t vfs_funcs; void *vfs_data; }; void * testvfs_make(vfs_t *vfs_funcs, void *vfs_data) { struct test_data *td; + int i; td = malloc(sizeof(struct test_data)); if(td == NULL) return NULL; td->fake_random = -1; + td->virtual = 0; td->vfs_funcs = *vfs_funcs; td->vfs_data = vfs_data; + for(i=0;ivfiles[i] = NULL; + td->vfile_len[i] = 0; + } return td; } @@ -32,11 +40,14 @@ static int test_start(void * vfs_data, char *filename) { static int test_finish(void *vfs_data) { struct test_data * td = (struct test_data *)vfs_data; - int r; + int i, r; r = (td->vfs_funcs.finish)(td->vfs_data); if(r != COQUET_RET_OK) return r; + for(i=0;ivfiles[i]); + } free(td); return COQUET_RET_OK; } @@ -51,19 +62,49 @@ static int test_open(void * vfs_data, int which_file, int mode) { struct test_data * td = (struct test_data *)vfs_data; + if(td->virtual) + return COQUET_RET_OK; return (td->vfs_funcs.open)(td->vfs_data,which_file,mode); } static int test_close(void * vfs_data, int which_file) { struct test_data * td = (struct test_data *)vfs_data; + if(td->virtual) + return COQUET_RET_OK; return (td->vfs_funcs.close)(td->vfs_data,which_file); } +static uint8_t * vf_ensure(struct test_data *td, int which_file, int size) { + uint8_t **vf; + uint64_t *vfl; + uint8_t *r; + + vf = &(td->vfiles[which_file]); + vfl = &(td->vfile_len[which_file]); + if(*vfl < size) { + r = realloc(*vf,size); + if(r == NULL) + return NULL; + *vf = r; + memset((*vf)+(*vfl),0,size-*vfl); + *vfl = size; + } + return *vf; +} + static int test_write(void * vfs_data, int which_file, uint8_t * data, off_t offset, uint64_t length) { struct test_data * td = (struct test_data *)vfs_data; + uint8_t *vf; + if(td->virtual) { + vf = vf_ensure(td,which_file,offset+length); + if(vf == NULL) + return COQUET_RET_HEAPERR; + memcpy(vf+offset,data,length); + return COQUET_RET_OK; + } return (td->vfs_funcs.write)(td->vfs_data, which_file, data, offset, length); } @@ -71,7 +112,15 @@ static int test_write(void * vfs_data, int which_file, uint8_t * data, static int test_read(void * vfs_data, int which_file, uint8_t * data, uint64_t offset, uint64_t length) { struct test_data * td = (struct test_data *)vfs_data; + uint8_t *vf; + if(td->virtual) { + vf = vf_ensure(td,which_file,offset+length); + if(vf == NULL) + return COQUET_RET_HEAPERR; + memcpy(data,vf+offset,length); + return COQUET_RET_OK; + } return (td->vfs_funcs.read)(td->vfs_data, which_file, data, offset, length); } @@ -80,6 +129,8 @@ static int test_lock(void * vfs_data, int which_lock, int lock_mode, bool wait) { struct test_data * td = (struct test_data *)vfs_data; + if(td->virtual) + return COQUET_RET_OK; return (td->vfs_funcs.lock)(td->vfs_data, which_lock, lock_mode, wait); } @@ -87,15 +138,33 @@ static int test_lock(void * vfs_data, int which_lock, int lock_mode, static int test_delete(void *vfs_data, int which_file) { struct test_data * td = (struct test_data *)vfs_data; + if(td->virtual) { + free(td->vfiles[which_file]); + td->vfiles[which_file] = NULL; + td->vfile_len[which_file] = 0; + return COQUET_RET_OK; + } return (td->vfs_funcs.delete)(td->vfs_data, which_file); } static int test_sync(void * vfs_data, int which_file, bool data_only) { struct test_data * td = (struct test_data *)vfs_data; + if(td->virtual) + return COQUET_RET_OK; return (td->vfs_funcs.sync)(td->vfs_data, which_file, data_only); } +static int test_size(void * vfs_data, int which_file, off_t * size) { + struct test_data * td = (struct test_data *)vfs_data; + + if(td->virtual) { + *size = td->vfile_len[which_file]; + return COQUET_RET_OK; + } + return (td->vfs_funcs.size)(td->vfs_data, which_file, size); +} + static int test_random(void * vfs_data, uint8_t *out, int len) { struct test_data * td = (struct test_data *)vfs_data; @@ -113,11 +182,18 @@ void testvfs_fakerandom(void * vfs_data, int setting) { td->fake_random = setting; } +void testvfs_virtual(void * vfs_data, bool yn) { + struct test_data * td = (struct test_data *)vfs_data; + + td->virtual = yn; +} + vfs_t vfs_test = { .start = test_start, .get_error_text = test_get_error_text, .lock = test_lock, .open = test_open, + .size = test_size, .close = test_close, .write = test_write, .read = test_read, diff --git a/src/unix.c b/src/unix.c index 6c1e17b..a41972c 100644 --- a/src/unix.c +++ b/src/unix.c @@ -455,12 +455,28 @@ static int unix_random(void * vfs_data, uint8_t *out, int len) { return COQUET_RET_OK; } +static int unix_size(void * vfs_data, int which_file, off_t * size) { + struct unix_data * pd = (struct unix_data *)vfs_data; + off_t r_off; + int *fd; + + fd = file_fd(pd,which_file); + r_off = lseek(*fd,0,SEEK_END); + if(r_off == -1) { + set_error(pd,"seek failed",1); + return COQUET_RET_VFSERR; + } + *size = r_off; + return COQUET_RET_OK; +} + vfs_t vfs_unix = { .start = unix_start, .get_error_text = unix_get_error_text, .lock = unix_lock, .open = unix_open, .close = unix_close, + .size = unix_size, .write = unix_write, .read = unix_read, .finish = unix_finish, diff --git a/src/vfs.h b/src/vfs.h index ab48168..c974426 100644 --- a/src/vfs.h +++ b/src/vfs.h @@ -58,7 +58,10 @@ typedef struct vfs { int (*write)(void * vfs_data, int which_file, uint8_t * data, off_t offset, uint64_t length); - // TODO write end + /* Offset to the end of the file. Note this is only the start of the + * end discovery process: don't just go appending here. + */ + int (*size)(void * vfs_data, int which_file, off_t *size); /* Read given data of given length at offset from to indicated file. * which file must be drawn from a COQUET_FILE_* constant. If the @@ -93,6 +96,7 @@ extern vfs_t vfs_test; void * testvfs_make(vfs_t *vfs_funcs, void *vfs_data); void testvfs_fakerandom(void * vfs_data, int setting); +void testvfs_virtual(void * vfs_data, bool yn); #endif /* COQUET_TEST */ -- 2.30.2