From 73fd57b1e4e02fe10ee68bf523d8df85d8133cc0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 27 Nov 2019 11:27:30 -0600 Subject: [PATCH] Fixed issue with superblock breaking lfs_dir_seek The superblock entry takes up id 0 in the root directory (not all entries are files, though currently the superblock is the only exception). Normally, reading a directory correctly skips the superblock and only reports non-superblock files. However, this doesn't work perfectly for lfs_dir_seek, which tries to be clever to not touch the disk. Fortunately, we can fix this by adding an offset for the superblock. This will only work while the superblock is the only non-file entry, otherwise we would need to touch the disk to properly seek in a directory (though we already touch the disk a bit to get dir-tails during seeks). Found by jhartika --- lfs.c | 14 ++++++--- tests/test_seek.sh | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/lfs.c b/lfs.c index 95a3b6a..3419e41 100644 --- a/lfs.c +++ b/lfs.c @@ -2064,10 +2064,14 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { dir->pos = lfs_min(2, off); off -= dir->pos; - while (off != 0) { - dir->id = lfs_min(dir->m.count, off); - dir->pos += dir->id; - off -= dir->id; + // skip superblock entry + dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0); + + while (off > 0) { + int diff = lfs_min(dir->m.count - dir->id, off); + dir->id += diff; + dir->pos += diff; + off -= diff; if (dir->id == dir->m.count) { if (!dir->m.split) { @@ -2080,6 +2084,8 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { LFS_TRACE("lfs_dir_seek -> %d", err); return err; } + + dir->id = 0; } } diff --git a/tests/test_seek.sh b/tests/test_seek.sh index e5696d0..e136aa0 100755 --- a/tests/test_seek.sh +++ b/tests/test_seek.sh @@ -428,4 +428,78 @@ scripts/test.py << TEST TEST done +echo "--- Root seek test ---" +./scripts/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + for (int i = 3; i < $MEDIUMSIZE; i++) { + sprintf(path, "hi%03d", i); + lfs_mkdir(&lfs, path) => 0; + } + + lfs_dir_open(&lfs, &dir, "/") => 0; + for (int i = 0; i < $MEDIUMSIZE; i++) { + if (i == 0) { + sprintf(path, "."); + } else if (i == 1) { + sprintf(path, ".."); + } else if (i == 2) { + sprintf(path, "hello"); + } else { + sprintf(path, "hi%03d", i); + } + lfs_dir_read(&lfs, &dir, &info) => 1; + strcmp(path, info.name) => 0; + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + for (int j = 0; j < $MEDIUMSIZE; j++) { + lfs_soff_t off = -1; + + lfs_dir_open(&lfs, &dir, "/") => 0; + for (int i = 0; i < $MEDIUMSIZE; i++) { + if (i == 0) { + sprintf(path, "."); + } else if (i == 1) { + sprintf(path, ".."); + } else if (i == 2) { + sprintf(path, "hello"); + } else { + sprintf(path, "hi%03d", i); + } + + if (i == j) { + off = lfs_dir_tell(&lfs, &dir); + off >= 0 => true; + } + + lfs_dir_read(&lfs, &dir, &info) => 1; + strcmp(path, info.name) => 0; + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_seek(&lfs, &dir, off) => 0; + for (int i = j; i < $MEDIUMSIZE; i++) { + if (i == 0) { + sprintf(path, "."); + } else if (i == 1) { + sprintf(path, ".."); + } else if (i == 2) { + sprintf(path, "hello"); + } else { + sprintf(path, "hi%03d", i); + } + + lfs_dir_read(&lfs, &dir, &info) => 1; + strcmp(path, info.name) => 0; + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + } + + lfs_unmount(&lfs) => 0; +TEST + scripts/results.py