From 6e99fa9319d17f0aef418ae3989befc04ecf9096 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 26 Sep 2017 20:09:29 -0500 Subject: [PATCH] Squashed 'littlefs/' changes from c2283a2..9843402 9843402 Fixed incorrect return value from lfs_file_seek 273cb7c Fixed problem with lookaheads larger than block device d9367e0 Fixed collection of multiblock directories a83b2fe Added checks for out-of-bound seeks a8fa5e6 Fixed some corner cases with paths 26dd49a Fixed issue with negative modulo with unaligned lookaheads 0982020 Fixed issue with cold-write after seek to block boundary git-subtree-dir: littlefs git-subtree-split: 984340225befc1e2330dd3b88f4048373eda0fce --- .travis.yml | 6 +- lfs.c | 139 +++++++++++++++++++++++++++++--------------- lfs.h | 7 ++- tests/test_dirs.sh | 34 ++++++++++- tests/test_paths.sh | 37 ++++++++++++ tests/test_seek.sh | 88 ++++++++++++++++++++++++---- 6 files changed, 248 insertions(+), 63 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0651efc961..a4ff97650b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,10 @@ script: -include stdio.h -Werror' make all size # run tests - - CFLAGS="-DLFS_READ_SIZE=16 -DLFS_PROG_SIZE=16" make test + - make test + + # run tests with a few different configurations - CFLAGS="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" make test - CFLAGS="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" make test + - CFLAGS="-DLFS_BLOCK_COUNT=1023" make test + - CFLAGS="-DLFS_LOOKAHEAD=2047" make test diff --git a/lfs.c b/lfs.c index b2c0a631aa..dc4a955ef3 100644 --- a/lfs.c +++ b/lfs.c @@ -262,9 +262,12 @@ int lfs_deorphan(lfs_t *lfs); static int lfs_alloc_lookahead(void *p, lfs_block_t block) { lfs_t *lfs = p; - lfs_block_t off = (block - lfs->free.start) % lfs->cfg->block_count; - if (off < lfs->cfg->lookahead) { - lfs->free.lookahead[off / 32] |= 1U << (off % 32); + lfs_block_t off = (((lfs_soff_t)(block - lfs->free.begin) + % (lfs_soff_t)(lfs->cfg->block_count)) + + lfs->cfg->block_count) % lfs->cfg->block_count; + + if (off < lfs->free.lookahead) { + lfs->free.buffer[off / 32] |= 1U << (off % 32); } return 0; @@ -282,30 +285,30 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { while (true) { // check if we have looked at all blocks since last ack - if (lfs->free.start + lfs->free.off == lfs->free.end) { + if (lfs->free.begin + lfs->free.off == lfs->free.end) { LFS_WARN("No more free space %d", lfs->free.end); return LFS_ERR_NOSPC; } - if (lfs->free.off >= lfs->cfg->lookahead) { + if (lfs->free.off >= lfs->free.lookahead) { break; } lfs_block_t off = lfs->free.off; lfs->free.off += 1; - if (!(lfs->free.lookahead[off / 32] & (1U << (off % 32)))) { + if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { // found a free block - *block = (lfs->free.start + off) % lfs->cfg->block_count; + *block = (lfs->free.begin + off) % lfs->cfg->block_count; return 0; } } - lfs->free.start += lfs->cfg->lookahead; + lfs->free.begin += lfs->free.lookahead; lfs->free.off = 0; // find mask of free blocks from tree - memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8); + memset(lfs->free.buffer, 0, lfs->free.lookahead/8); int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs); if (err) { return err; @@ -314,7 +317,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { } static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.end = lfs->free.start + lfs->free.off + lfs->cfg->block_count; + lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count; } @@ -343,6 +346,10 @@ static inline bool lfs_pairsync( (paira[0] == pairb[1] && paira[1] == pairb[0]); } +static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) { + return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; +} + static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { // allocate pair of dir blocks for (int i = 0; i < 2; i++) { @@ -568,8 +575,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry, const void *data) { // check if we fit, if top bit is set we do not and move on while (true) { - if (dir->d.size + 4+entry->d.elen+entry->d.alen+entry->d.nlen - <= lfs->cfg->block_size) { + if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) { entry->off = dir->d.size - 4; return lfs_dir_commit(lfs, dir, (struct lfs_region[]){ {entry->off, 0, &entry->d, sizeof(entry->d)}, @@ -611,7 +617,8 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { // either shift out the one entry or remove the whole dir block - if (dir->d.size == sizeof(dir->d)+4) { + if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 + + lfs_entry_size(entry)) { lfs_dir_t pdir; int res = lfs_pred(lfs, dir->pair, &pdir); if (res < 0) { @@ -620,18 +627,17 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { if (!(pdir.d.size & 0x80000000)) { return lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, 4+entry->d.elen+entry->d.alen+entry->d.nlen, - NULL, 0}, + {entry->off, lfs_entry_size(entry), NULL, 0}, }, 1); } else { + pdir.d.size &= dir->d.size | 0x7fffffff; pdir.d.tail[0] = dir->d.tail[0]; pdir.d.tail[1] = dir->d.tail[1]; - return lfs_dir_commit(lfs, dir, NULL, 0); + return lfs_dir_commit(lfs, &pdir, NULL, 0); } } else { return lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, 4+entry->d.elen+entry->d.alen+entry->d.nlen, - NULL, 0}, + {entry->off, lfs_entry_size(entry), NULL, 0}, }, 1); } } @@ -659,8 +665,8 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { } entry->off = dir->off; - dir->off += 4+entry->d.elen+entry->d.alen+entry->d.nlen; - dir->pos += 4+entry->d.elen+entry->d.alen+entry->d.nlen; + dir->off += lfs_entry_size(entry); + dir->pos += lfs_entry_size(entry); return 0; } @@ -706,6 +712,9 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, suffix += sufflen; } + // update what we've found + *path = pathname; + // find path while (true) { int err = lfs_dir_next(lfs, dir, entry); @@ -747,8 +756,6 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, if (err) { return err; } - - *path = pathname; } return 0; @@ -766,7 +773,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_entry_t entry; err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err != LFS_ERR_NOENT) { + if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) { return err ? err : LFS_ERR_EXISTS; } @@ -814,8 +821,8 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { return err; } + // check for root, can only be something like '/././../.' if (strspn(path, "/.") == strlen(path)) { - // can only be something like '/././../.' dir->head[0] = dir->pair[0]; dir->head[1] = dir->pair[1]; dir->pos = sizeof(dir->d) - 2; @@ -975,6 +982,7 @@ static int lfs_index_find(lfs_t *lfs, return err; } + assert(head >= 2 && head <= lfs->cfg->block_count); current -= 1 << skip; } @@ -993,6 +1001,7 @@ static int lfs_index_extend(lfs_t *lfs, if (err) { return err; } + assert(*block >= 2 && *block <= lfs->cfg->block_count); err = lfs_bd_erase(lfs, *block); if (err) { @@ -1054,6 +1063,8 @@ static int lfs_index_extend(lfs_t *lfs, return err; } } + + assert(head >= 2 && head <= lfs->cfg->block_count); } *off = 4*skips; @@ -1111,7 +1122,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, lfs_entry_t entry; err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err && err != LFS_ERR_NOENT) { + if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)) { return err; } @@ -1369,6 +1380,11 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, } } + if (file->pos >= file->size) { + // eof if past end + return 0; + } + size = lfs_min(size, file->size - file->pos); nsize = size; @@ -1424,22 +1440,34 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos = file->size; } + if (!(file->flags & LFS_F_WRITING) && file->pos > file->size) { + // fill with zeros + lfs_off_t pos = file->pos; + file->pos = file->size; + + while (file->pos < pos) { + lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + if (res < 0) { + return res; + } + } + } + while (nsize > 0) { // check if we need a new block if (!(file->flags & LFS_F_WRITING) || file->off == lfs->cfg->block_size) { - if (!(file->flags & LFS_F_WRITING)) { + if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { // find out which block we're extending from int err = lfs_index_find(lfs, &file->cache, NULL, file->head, file->size, - file->pos, &file->block, &file->off); + file->pos-1, &file->block, &file->off); if (err) { return err; } // mark cache as dirty since we may have read data into it file->cache.block = 0xffffffff; - file->flags |= LFS_F_WRITING; } // extend file with new blocks @@ -1450,6 +1478,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if (err) { return err; } + + file->flags |= LFS_F_WRITING; } // program as much as we can in current block @@ -1492,17 +1522,23 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, } // update pos - lfs_off_t pos = file->pos; - if (whence == LFS_SEEK_SET) { file->pos = off; } else if (whence == LFS_SEEK_CUR) { + if (-off > file->pos) { + return LFS_ERR_INVAL; + } + file->pos = file->pos + off; } else if (whence == LFS_SEEK_END) { + if (-off > file->size) { + return LFS_ERR_INVAL; + } + file->pos = file->size + off; } - return pos; + return file->pos; } lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { @@ -1525,6 +1561,14 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { /// General fs oprations /// int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + // check for root, can only be something like '/././../.' + if (strspn(path, "/.") == strlen(path)) { + memset(info, 0, sizeof(*info)); + info->type = LFS_TYPE_DIR; + strcpy(info->name, "/"); + return 0; + } + lfs_dir_t cwd; int err = lfs_dir_fetch(lfs, &cwd, lfs->root); if (err) { @@ -1592,7 +1636,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { f->pair[0] = 0xffffffff; f->pair[1] = 0xffffffff; } else if (f->poff > entry.off) { - f->poff -= 4 + entry.d.elen + entry.d.alen + entry.d.nlen; + f->poff -= lfs_entry_size(&entry); } } } @@ -1632,7 +1676,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_entry_t preventry; err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath); - if (err && err != LFS_ERR_NOENT) { + if (err && (err != LFS_ERR_NOENT || strchr(newpath, '/') != NULL)) { return err; } bool prevexists = (err != LFS_ERR_NOENT); @@ -1696,7 +1740,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { f->pair[0] = 0xffffffff; f->pair[1] = 0xffffffff; } else if (f->poff > oldentry.off) { - f->poff -= 4+oldentry.d.elen+oldentry.d.alen+oldentry.d.nlen; + f->poff -= lfs_entry_size(&oldentry); } } } @@ -1740,12 +1784,15 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { } } - // setup lookahead + // setup lookahead, round down to nearest 32-bits + lfs->free.lookahead = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count); + lfs->free.lookahead = 32 * (lfs->free.lookahead / 32); + assert(lfs->free.lookahead > 0); if (lfs->cfg->lookahead_buffer) { - lfs->free.lookahead = lfs->cfg->lookahead_buffer; + lfs->free.buffer = lfs->cfg->lookahead_buffer; } else { - lfs->free.lookahead = malloc(lfs->cfg->lookahead/8); - if (!lfs->free.lookahead) { + lfs->free.buffer = malloc(lfs->free.lookahead/8); + if (!lfs->free.buffer) { return LFS_ERR_NOMEM; } } @@ -1770,7 +1817,7 @@ static int lfs_deinit(lfs_t *lfs) { } if (!lfs->cfg->lookahead_buffer) { - free(lfs->free.lookahead); + free(lfs->free.buffer); } return 0; @@ -1783,10 +1830,10 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { } // create free lookahead - memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8); - lfs->free.start = 0; + memset(lfs->free.buffer, 0, lfs->free.lookahead/8); + lfs->free.begin = 0; lfs->free.off = 0; - lfs->free.end = lfs->free.start + lfs->cfg->block_count; + lfs->free.end = lfs->free.begin + lfs->cfg->block_count; // create superblock dir lfs_alloc_ack(lfs); @@ -1862,9 +1909,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { } // setup free lookahead - lfs->free.start = -lfs->cfg->lookahead; - lfs->free.off = lfs->cfg->lookahead; - lfs->free.end = lfs->free.start + lfs->cfg->block_count; + lfs->free.begin = -lfs->free.lookahead; + lfs->free.off = lfs->free.lookahead; + lfs->free.end = lfs->free.begin + lfs->cfg->block_count; // load superblock lfs_dir_t dir; @@ -1931,7 +1978,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { return err; } - dir.off += 4+entry.d.elen+entry.d.alen+entry.d.nlen; + dir.off += lfs_entry_size(&entry); if ((0xf & entry.d.type) == (0xf & LFS_TYPE_REG)) { int err = lfs_index_traverse(lfs, &lfs->rcache, NULL, entry.d.u.file.head, entry.d.u.file.size, cb, data); diff --git a/lfs.h b/lfs.h index 1b11ba79cf..ed232f68f6 100644 --- a/lfs.h +++ b/lfs.h @@ -225,10 +225,11 @@ typedef struct lfs_superblock { } lfs_superblock_t; typedef struct lfs_free { + lfs_size_t lookahead; + lfs_block_t begin; lfs_block_t end; - lfs_block_t start; lfs_block_t off; - uint32_t *lookahead; + uint32_t *buffer; } lfs_free_t; // The littlefs type @@ -237,12 +238,12 @@ typedef struct lfs { lfs_block_t root[2]; lfs_file_t *files; - bool deorphaned; lfs_cache_t rcache; lfs_cache_t pcache; lfs_free_t free; + bool deorphaned; } lfs_t; diff --git a/tests/test_dirs.sh b/tests/test_dirs.sh index 815b88bd22..5a7ea58b7e 100755 --- a/tests/test_dirs.sh +++ b/tests/test_dirs.sh @@ -124,7 +124,6 @@ tests/test.py << TEST TEST echo "--- Directory remove ---" -# TESTING HERE tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_remove(&lfs, "potato") => LFS_ERR_INVAL; @@ -283,5 +282,38 @@ tests/test.py << TEST lfs_unmount(&lfs) => 0; TEST +echo "--- Multi-block remove ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "cactus") => LFS_ERR_INVAL; + + for (int i = 0; i < $LARGESIZE; i++) { + sprintf((char*)buffer, "cactus/test%d", i); + lfs_remove(&lfs, (char*)buffer) => 0; + } + + lfs_remove(&lfs, "cactus") => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir[0], "/") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "burito") => 0; + info.type => LFS_TYPE_REG; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "coldpotato") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_dir_close(&lfs, &dir[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + echo "--- Results ---" tests/stats.py diff --git a/tests/test_paths.sh b/tests/test_paths.sh index 769f37fcea..9bc1f5b171 100755 --- a/tests/test_paths.sh +++ b/tests/test_paths.sh @@ -31,6 +31,10 @@ tests/test.py << TEST strcmp(info.name, "hottea") => 0; lfs_stat(&lfs, "/tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; + + lfs_mkdir(&lfs, "/milk1") => 0; + lfs_stat(&lfs, "/milk1", &info) => 0; + strcmp(info.name, "milk1") => 0; lfs_unmount(&lfs) => 0; TEST @@ -43,6 +47,10 @@ tests/test.py << TEST strcmp(info.name, "hottea") => 0; lfs_stat(&lfs, "///tea///hottea", &info) => 0; strcmp(info.name, "hottea") => 0; + + lfs_mkdir(&lfs, "///milk2") => 0; + lfs_stat(&lfs, "///milk2", &info) => 0; + strcmp(info.name, "milk2") => 0; lfs_unmount(&lfs) => 0; TEST @@ -57,6 +65,10 @@ tests/test.py << TEST strcmp(info.name, "hottea") => 0; lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; strcmp(info.name, "hottea") => 0; + + lfs_mkdir(&lfs, "/./milk3") => 0; + lfs_stat(&lfs, "/./milk3", &info) => 0; + strcmp(info.name, "milk3") => 0; lfs_unmount(&lfs) => 0; TEST @@ -71,6 +83,10 @@ tests/test.py << TEST strcmp(info.name, "hottea") => 0; lfs_stat(&lfs, "coffee/../soda/../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; + + lfs_mkdir(&lfs, "coffee/../milk4") => 0; + lfs_stat(&lfs, "coffee/../milk4", &info) => 0; + strcmp(info.name, "milk4") => 0; lfs_unmount(&lfs) => 0; TEST @@ -79,6 +95,27 @@ tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; + + lfs_mkdir(&lfs, "coffee/../../../../../../milk5") => 0; + lfs_stat(&lfs, "coffee/../../../../../../milk5", &info) => 0; + strcmp(info.name, "milk5") => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Root tests ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_stat(&lfs, "/", &info) => 0; + info.type => LFS_TYPE_DIR; + strcmp(info.name, "/") => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Sketchy path tests ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs_unmount(&lfs) => 0; TEST diff --git a/tests/test_seek.sh b/tests/test_seek.sh index 8c0093852e..6600cb2f5c 100755 --- a/tests/test_seek.sh +++ b/tests/test_seek.sh @@ -133,15 +133,15 @@ tests/test.py << TEST lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; @@ -174,15 +174,15 @@ tests/test.py << TEST lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; @@ -211,7 +211,7 @@ tests/test.py << TEST lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_write(&lfs, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos+size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; @@ -219,11 +219,11 @@ tests/test.py << TEST lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; @@ -254,7 +254,7 @@ tests/test.py << TEST lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_write(&lfs, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos+size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; @@ -262,11 +262,11 @@ tests/test.py << TEST lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => size; + lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) => pos+size; + lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; @@ -277,5 +277,69 @@ tests/test.py << TEST lfs_unmount(&lfs) => 0; TEST +echo "--- Boundary seek and write ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + + size = strlen("hedgehoghog"); + const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; + + for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { + lfs_soff_t off = offsets[i]; + memcpy(buffer, "hedgehoghog", size); + lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; + lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "hedgehoghog", size) => 0; + + lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_SET) => 0; + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "kittycatcat", size) => 0; + + lfs_file_sync(&lfs, &file[0]) => 0; + } + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Out-of-bounds seek ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + + size = strlen("kittycatcat"); + lfs_file_size(&lfs, &file[0]) => $LARGESIZE*size; + lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, + LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; + lfs_file_read(&lfs, &file[0], buffer, size) => 0; + + memcpy(buffer, "porcupineee", size); + lfs_file_write(&lfs, &file[0], buffer, size) => size; + + lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, + LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "porcupineee", size) => 0; + + lfs_file_seek(&lfs, &file[0], $LARGESIZE*size, + LFS_SEEK_SET) => $LARGESIZE*size; + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; + + lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+$SMALLSIZE)*size), + LFS_SEEK_CUR) => LFS_ERR_INVAL; + lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; + + lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size), + LFS_SEEK_END) => LFS_ERR_INVAL; + lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + echo "--- Results ---" tests/stats.py