Explorar o código

Added dir tests, test fixes, config

Christopher Haster %!s(int64=8) %!d(string=hai) anos
pai
achega
a711675607
Modificáronse 7 ficheiros con 248 adicións e 60 borrados
  1. 5 3
      Makefile
  2. 134 34
      lfs.c
  3. 25 4
      lfs.h
  4. 2 2
      tests/stats.py
  5. 8 2
      tests/template.fmt
  6. 59 0
      tests/test_dirs.sh
  7. 15 15
      tests/test_format.sh

+ 5 - 3
Makefile

@@ -9,7 +9,7 @@ OBJ := $(SRC:.c=.o)
 DEP := $(SRC:.c=.d)
 ASM := $(SRC:.c=.s)
 
-TEST := $(wildcard tests/test_*)
+TEST := $(patsubst tests/%.sh,%,$(wildcard tests/test_*))
 
 ifdef DEBUG
 CFLAGS += -O0 -g3
@@ -30,8 +30,10 @@ asm: $(ASM)
 size: $(OBJ)
 	$(SIZE) -t $^
 
-test:
-	for t in $(TEST) ; do ./$$t ; done
+.SUFFIXES:
+test: $(TEST)
+test_%: tests/test_%.sh
+	./$<
 
 -include $(DEP)
 

+ 134 - 34
lfs.c

@@ -39,9 +39,9 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
         lfs_off_t off, lfs_size_t size, const void *buffer) {
     const uint8_t *data = buffer;
 
-    while (off < size) {
+    for (lfs_off_t i = 0; i < size; i++) {
         uint8_t c;
-        int err = lfs_bd_read(lfs, block, off, 1, &c);
+        int err = lfs_bd_read(lfs, block, off+i, 1, &c);
         if (err) {
             return err;
         }
@@ -51,7 +51,6 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
         }
 
         data += 1;
-        off += 1;
     }
 
     return true;
@@ -329,29 +328,35 @@ static int lfs_dir_create(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t parent[2]) {
     dir->d.rev += 1;
 
     // Calculate total size
-    dir->d.size = sizeof(dir->d);
-    if (parent) {
-        dir->d.size += sizeof(struct lfs_disk_entry);
-    }
+    dir->d.size = sizeof(dir->d) + 2*sizeof(struct lfs_disk_entry) + 3;
+    dir->off = sizeof(dir->d);
 
     // Other defaults
-    dir->off = dir->d.size;
     dir->d.tail[0] = 0;
     dir->d.tail[1] = 0;
     dir->d.free = lfs->free;
 
     // Write out to memory
     return lfs_pair_commit(lfs, dir->pair,
-        1 + (parent ? 2 : 0), (struct lfs_commit_region[]){
+        5, (struct lfs_commit_region[]){
             {0, sizeof(dir->d), &dir->d},
             {sizeof(dir->d), sizeof(struct lfs_disk_entry),
              &(struct lfs_disk_entry){
                 .type     = LFS_TYPE_DIR,
-                .len      = 12+2,
-                .u.dir[0] = parent ? parent[0] : 0,
-                .u.dir[1] = parent ? parent[1] : 0,
+                .len      = sizeof(struct lfs_disk_entry)+1,
+                .u.dir[0] = dir->pair[0],
+                .u.dir[1] = dir->pair[1],
+            }},
+            {sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
+            {sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
+             sizeof(struct lfs_disk_entry),
+             &(struct lfs_disk_entry){
+                .type     = LFS_TYPE_DIR,
+                .len      = sizeof(struct lfs_disk_entry)+2,
+                .u.dir[0] = parent ? parent[0] : dir->pair[0],
+                .u.dir[1] = parent ? parent[1] : dir->pair[1],
             }},
-            {sizeof(dir->d)+sizeof(struct lfs_disk_entry), 2, ".."},
+            {sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
         });
 }
 
@@ -473,9 +478,19 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
 }
 
 int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
-    int err = lfs_dir_fetch(lfs, dir, lfs->cwd);
+    if (path[0] == '/') {
+        dir->pair[0] = lfs->root[0];
+        dir->pair[1] = lfs->root[1];
+    } else {
+        dir->pair[0] = lfs->cwd[0];
+        dir->pair[1] = lfs->cwd[1];
+    }
+
+    int err = lfs_dir_fetch(lfs, dir, dir->pair);
     if (err) {
         return err;
+    } else if (strcmp(path, "/") == 0) {
+        return 0;
     }
     
     lfs_entry_t entry;
@@ -494,6 +509,29 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
     return 0;
 }
 
+int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
+    memset(info, 0, sizeof(*info));
+
+    lfs_entry_t entry;
+    int err = lfs_dir_next(lfs, dir, &entry);
+    if (err) {
+        return (err == LFS_ERROR_NO_ENTRY) ? 0 : err;
+    }
+
+    info->type = entry.d.type & 0xff;
+    if (info->type == LFS_TYPE_REG) {
+        info->size = entry.d.u.file.size;
+    }
+
+    err = lfs_bd_read(lfs, entry.dir[0], entry.off + sizeof(entry.d),
+            entry.d.len - sizeof(entry.d), info->name);
+    if (err) {
+        return err;
+    }
+
+    return 1;
+}
+
 
 /// File operations ///
 
@@ -548,6 +586,8 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
                  file->entry.d.len-sizeof(file->entry.d),
                  path}
             });
+    } else if (file->entry.d.type == LFS_TYPE_DIR) {
+        return LFS_ERROR_IS_DIR;
     } else {
         file->head = file->entry.d.u.file.head;
         file->size = file->entry.d.u.file.size;
@@ -675,9 +715,9 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
 
 
 /// Generic filesystem operations ///
-int lfs_format(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
-    lfs->bd = bd;
-    lfs->bd_ops = bd_ops;
+static int lfs_configure(lfs_t *lfs, const struct lfs_config *config) {
+    lfs->bd = config->bd;
+    lfs->bd_ops = config->bd_ops;
 
     struct lfs_bd_info info;
     int err = lfs_bd_info(lfs, &info);
@@ -685,11 +725,67 @@ int lfs_format(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
         return err;
     }
 
-    lfs->read_size  = info.read_size;
-    lfs->prog_size  = info.prog_size;
-    lfs->block_size = info.erase_size;
-    lfs->block_count = info.total_size / info.erase_size;
-    lfs->words = info.erase_size / sizeof(uint32_t);
+    if (config->read_size) {
+        if (config->read_size < info.read_size ||
+            config->read_size % info.read_size != 0) {
+            LFS_ERROR("Invalid read size %u, device has %u\n",
+                config->read_size, info.read_size);
+            return LFS_ERROR_INVALID;
+        }
+
+        lfs->read_size = config->read_size;
+    } else {
+        lfs->read_size = info.read_size;
+    }
+
+    if (config->prog_size) {
+        if (config->prog_size < info.prog_size ||
+            config->prog_size % info.prog_size != 0) {
+            LFS_ERROR("Invalid prog size %u, device has %u\n",
+                config->prog_size, info.prog_size);
+            return LFS_ERROR_INVALID;
+        }
+
+        lfs->prog_size = config->prog_size;
+    } else {
+        lfs->prog_size = info.prog_size;
+    }
+
+    if (config->block_size) {
+        if (config->block_size < info.erase_size ||
+            config->block_size % info.erase_size != 0) {
+            LFS_ERROR("Invalid block size %u, device has %u\n",
+                config->prog_size, info.prog_size);
+            return LFS_ERROR_INVALID;
+        }
+
+        lfs->block_size = config->block_size;
+    } else {
+        lfs->block_size = lfs_min(512, info.erase_size);
+    }
+
+    if (config->block_count) {
+        if (config->block_count > info.total_size/info.erase_size) {
+            LFS_ERROR("Invalid block size %u, device has %u\n",
+                config->block_size,
+                (uint32_t)(info.total_size/info.erase_size));
+            return LFS_ERROR_INVALID;
+        }
+
+        lfs->block_count = config->block_count;
+    } else {
+        lfs->block_count = info.total_size / info.erase_size;
+    }
+
+    lfs->words = lfs->block_size / sizeof(uint32_t);
+    return 0;
+}
+
+int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
+    int err = lfs_configure(lfs, config);
+    if (err) {
+        return err;
+    }
 
     // Create free list
     lfs->free.begin = 2;
@@ -701,6 +797,8 @@ int lfs_format(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
     if (err) {
         return err;
     }
+    lfs->root[0] = root.pair[0];
+    lfs->root[1] = root.pair[1];
     lfs->cwd[0] = root.pair[0];
     lfs->cwd[1] = root.pair[1];
 
@@ -736,22 +834,12 @@ int lfs_format(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
     return 0;
 }
 
-int lfs_mount(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
-    lfs->bd = bd;
-    lfs->bd_ops = bd_ops;
-
-    struct lfs_bd_info info;
-    int err = lfs_bd_info(lfs, &info);
+int lfs_mount(lfs_t *lfs, const struct lfs_config *config) {
+    int err = lfs_configure(lfs, config);
     if (err) {
         return err;
     }
 
-    lfs->read_size  = info.read_size;
-    lfs->prog_size  = info.prog_size;
-    lfs->block_size = info.erase_size;
-    lfs->block_count = info.total_size / info.erase_size;
-    lfs->words = info.erase_size / sizeof(uint32_t);
-
     lfs_superblock_t superblock = {
         .pair = {0, 1},
     };
@@ -767,9 +855,21 @@ int lfs_mount(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops) {
         return LFS_ERROR_CORRUPT;
     }
 
+    lfs->root[0] = superblock.d.root[0];
+    lfs->root[1] = superblock.d.root[1];
     lfs->cwd[0] = superblock.d.root[0];
     lfs->cwd[1] = superblock.d.root[1];
 
+    // TODO this is wrong, needs to check all dirs
+    lfs_dir_t dir;
+    err = lfs_dir_fetch(lfs, &dir, lfs->cwd);
+    if (err) {
+        return err;
+    }
+
+    lfs->free.begin = dir.d.free.begin;
+    lfs->free.end = dir.d.free.end;
+
     return err;
 }
 

+ 25 - 4
lfs.h

@@ -18,8 +18,9 @@ enum lfs_error {
     LFS_ERROR_NO_ENTRY = -4,
     LFS_ERROR_EXISTS   = -5,
     LFS_ERROR_NOT_DIR  = -6,
-    LFS_ERROR_INVALID  = -7,
-    LFS_ERROR_NO_SPACE = -8,
+    LFS_ERROR_IS_DIR   = -7,
+    LFS_ERROR_INVALID  = -8,
+    LFS_ERROR_NO_SPACE = -9,
 };
 
 enum lfs_type {
@@ -39,6 +40,22 @@ enum lfs_open_flags {
 };
 
 
+struct lfs_config {
+    lfs_bd_t *bd;
+    const struct lfs_bd_ops *bd_ops;
+
+    lfs_size_t read_size;
+    lfs_size_t prog_size;
+
+    lfs_size_t block_size;
+    lfs_size_t block_count;
+};
+
+struct lfs_info {
+    uint8_t type;
+    lfs_size_t size;
+    char name[LFS_NAME_MAX+1];
+};
 
 typedef struct lfs_entry {
     lfs_block_t dir[2];
@@ -104,6 +121,7 @@ typedef struct lfs {
     lfs_bd_t *bd;
     const struct lfs_bd_ops *bd_ops;
 
+    lfs_block_t root[2];
     lfs_block_t cwd[2];
     struct lfs_disk_free free;
 
@@ -115,11 +133,14 @@ typedef struct lfs {
 } lfs_t;
 
 // Functions
-int lfs_format(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops);
-int lfs_mount(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops);
+int lfs_format(lfs_t *lfs, const struct lfs_config *config);
+int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
 int lfs_unmount(lfs_t *lfs);
 
 int lfs_mkdir(lfs_t *lfs, const char *path);
+int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
+int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
+int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
 
 int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
         const char *path, int flags);

+ 2 - 2
tests/stats.py

@@ -18,13 +18,13 @@ def main():
         os.path.getsize(os.path.join('blocks', f))
         for f in os.listdir('blocks') if re.match('\d+', f))
 
-    print 'runtime: %.3f' % (time.time() - os.stat('blocks').st_ctime)
-
     with open('blocks/stats') as file:
         s = struct.unpack('<QQQ', file.read())
         print 'read_count: %d' % s[0]
         print 'prog_count: %d' % s[1]
         print 'erase_count: %d' % s[2]
 
+    print 'runtime: %.3f' % (time.time() - os.stat('blocks').st_ctime)
+
 if __name__ == "__main__":
     main(*sys.argv[1:])

+ 8 - 2
tests/template.fmt

@@ -23,8 +23,9 @@ lfs_t lfs;
 lfs_emubd_t bd;
 lfs_file_t file[4];
 lfs_dir_t dir[4];
-struct lfs_bd_info info;
-struct lfs_bd_stats stats;
+struct lfs_bd_info bd_info;
+struct lfs_bd_stats bd_stats;
+struct lfs_info info;
 
 uint8_t buffer[1024];
 uint8_t wbuffer[1024];
@@ -35,6 +36,11 @@ lfs_size_t rsize;
 
 uintmax_t res;
 
+const struct lfs_config config = {{
+    .bd = &bd,
+    .bd_ops = &lfs_emubd_ops,
+}};
+
 
 int main() {{
     lfs_emubd_create(&bd, "blocks");

+ 59 - 0
tests/test_dirs.sh

@@ -0,0 +1,59 @@
+#!/bin/bash
+set -eu
+
+echo "=== Directory tests ==="
+rm -rf blocks
+
+echo "--- Root directory ---"
+tests/test.py << TEST
+    lfs_format(&lfs, &config) => 0;
+
+    lfs_dir_open(&lfs, &dir[0], "/") => 0;
+    lfs_dir_close(&lfs, &dir[0]) => 0;
+TEST
+
+echo "--- Directory creation ---"
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
+    lfs_mkdir(&lfs, "potato") => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+
+echo "--- File creation ---"
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
+    lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0;
+    lfs_file_close(&lfs, &file[0]) => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+
+echo "--- Directory iteration ---"
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
+    lfs_dir_open(&lfs, &dir[0], "/") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, ".") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "..") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "potato") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "burito") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 0;
+    lfs_dir_close(&lfs, &dir[0]) => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+
+echo "--- Directory failures ---"
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
+    lfs_mkdir(&lfs, "potato") => LFS_ERROR_EXISTS;
+    lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERROR_NO_ENTRY;
+    lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERROR_NOT_DIR;
+    lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERROR_NO_ENTRY;
+    lfs_file_open(&lfs, &file[0], "potato", LFS_O_RDONLY) => LFS_ERROR_IS_DIR;
+    lfs_unmount(&lfs) => 0;
+TEST
+
+echo "--- Results ---"
+tests/stats.py

+ 15 - 15
tests/test_format.sh

@@ -5,41 +5,41 @@ echo "=== Formatting tests ==="
 rm -rf blocks
 
 echo "--- Basic formatting ---"
-./tests/test.py << TEST
-    lfs_format(&lfs, &bd, &lfs_emubd_ops) => 0;
+tests/test.py << TEST
+    lfs_format(&lfs, &config) => 0;
 TEST
 
 echo "--- Invalid superblocks ---"
 ln -f -s /dev/null blocks/0
-./tests/test.py << TEST
-    lfs_format(&lfs, &bd, &lfs_emubd_ops) => LFS_ERROR_CORRUPT;
+tests/test.py << TEST
+    lfs_format(&lfs, &config) => LFS_ERROR_CORRUPT;
 TEST
 rm blocks/0
 
 echo "--- Basic mounting ---"
-./tests/test.py << TEST
-    lfs_mount(&lfs, &bd, &lfs_emubd_ops) => 0;
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
     lfs_unmount(&lfs) => 0;
 TEST
 
 echo "--- Invalid mount ---"
-./tests/test.py << TEST
-    lfs_format(&lfs, &bd, &lfs_emubd_ops) => 0;
+tests/test.py << TEST
+    lfs_format(&lfs, &config) => 0;
 TEST
 rm blocks/0 blocks/1
-./tests/test.py << TEST
-    lfs_mount(&lfs, &bd, &lfs_emubd_ops) => LFS_ERROR_CORRUPT;
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => LFS_ERROR_CORRUPT;
 TEST
 
 echo "--- Valid corrupt mount ---"
-./tests/test.py << TEST
-    lfs_format(&lfs, &bd, &lfs_emubd_ops) => 0;
+tests/test.py << TEST
+    lfs_format(&lfs, &config) => 0;
 TEST
 rm blocks/0
-./tests/test.py << TEST
-    lfs_mount(&lfs, &bd, &lfs_emubd_ops) => 0;
+tests/test.py << TEST
+    lfs_mount(&lfs, &config) => 0;
     lfs_unmount(&lfs) => 0;
 TEST
 
 echo "--- Results ---"
-./tests/stats.py
+tests/stats.py