chiark / gitweb /
File size vfs method; in-memory test FS for slow tests.
authorDan Sheppard <dan.sheppard.circle@gmail.com>
Wed, 23 Apr 2025 13:08:13 +0000 (14:08 +0100)
committerDan Sheppard <dan.sheppard.circle@gmail.com>
Wed, 23 Apr 2025 13:08:13 +0000 (14:08 +0100)
.vscode/settings.json
Makefile
doc/TODO
src/constants.h
src/coquet.c
src/superblock.c
src/testvfs.c
src/unix.c
src/vfs.h

index 4b4779a788a5b16bc979d69f6581de36179b3732..b05135a636441172e57c087931062fc1121dc7a6 100644 (file)
@@ -10,5 +10,6 @@
     "files.associations": {
         "coquet.h": "c",
         "superblock.h": "c"
-    }
+    },
+    "C_Cpp.dimInactiveRegions": false
 }
\ No newline at end of file
index a5b373f04ce1df7509afe7e578dd0e18995293fb..63f8bb71e1aed2c80c64709c43e851fcba6d8189 100644 (file)
--- 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
 
index d098b5c4331732df60ebcdf896da4639aa30f81c..6c87af5c2e983e6ff1023ec1b9a91a539802655c 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -1,3 +1,5 @@
 * "Eventually" inserts
 * Replication
-* Strict locking
+* Strict locking option
+* lock timeout
+
index ab0d70cfae300e17094d4fa061be70b9dfba9e94..55e4e7d00cab7699444cd9ecddca6e54fb540ce6 100644 (file)
@@ -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
index 0da0fcb6427a091dd2fe1fcebc8330c0d0c999df..aa3e3c598585739b59780788a99cf323f5a8e0b3 100644 (file)
@@ -15,6 +15,7 @@ vfs_t vfs_null = {
     .lock = NULL,
     .open = NULL,
     .close = NULL,
+    .size = NULL,
     .write = NULL,
     .read = NULL,
     .finish = NULL
index bb6bd8a6523d2ca91dbf7faf06912934311c7504..d72b499a8931f6970af96b1087d9d3e749e41282 100644 (file)
@@ -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
index 5d539a26595cb4d35818ca8f101b290964f4d27e..608fbc010da0bc909c71bb28cdc9ecbdcb7f6962 100644 (file)
@@ -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;i<COQUET_FILE_NUM;i++) {
+        td->vfiles[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;i<COQUET_FILE_NUM;i++) {
+        free(td->vfiles[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,
index 6c1e17b34a738f7ca9c79c8dd39f1d33de1c4cd4..a41972c10dd9a99217737f0f13d581b1caa946c5 100644 (file)
@@ -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,
index ab481689ec4ee7e62ec2f8e92ea85385be6cb886..c9744266a2ddabd5d9c2d7e35d553a1db64a2b70 100644 (file)
--- 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 */