From 5bf71fa43ef76bdcce54d682ebc915da2338c0ef Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 3 Aug 2019 11:58:19 -0500 Subject: [PATCH] lfs: do not reposition seek pointer on truncate When using lfs_file_truncate() to make a file shorter the file block and off were incorrectly positioned at the new end, resulting in invalid data accessed when reading. Lift the seek pointer restoration to apply to both increasing and reducing truncates. Signed-off-by: Peter A. Bigot --- lfs.c | 15 ++++++------- tests/test_truncate.sh | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/lfs.c b/lfs.c index c4ef89a..9fe7563 100644 --- a/lfs.c +++ b/lfs.c @@ -2981,6 +2981,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { return LFS_ERR_INVAL; } + lfs_off_t pos = file->pos; lfs_off_t oldsize = lfs_file_size(lfs, file); if (size < oldsize) { // need to flush since directly changing metadata @@ -3003,8 +3004,6 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { file->ctz.size = size; file->flags |= LFS_F_DIRTY | LFS_F_READING; } else if (size > oldsize) { - lfs_off_t pos = file->pos; - // flush+seek if not already at end if (file->pos != oldsize) { int err = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); @@ -3022,13 +3021,13 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { return res; } } + } - // restore pos - int err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); - if (err < 0) { - LFS_TRACE("lfs_file_truncate -> %d", err); - return err; - } + // restore pos + int err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); + if (err < 0) { + LFS_TRACE("lfs_file_truncate -> %d", err); + return err; } LFS_TRACE("lfs_file_truncate -> %d", 0); diff --git a/tests/test_truncate.sh b/tests/test_truncate.sh index ee42693..f33717d 100755 --- a/tests/test_truncate.sh +++ b/tests/test_truncate.sh @@ -107,6 +107,57 @@ scripts/test.py << TEST lfs_unmount(&lfs) => 0; TEST +echo "--- Write, truncate, and read ---" +scripts/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "sequence", + LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; + + lfs_size_t size = lfs.cfg->cache_size; + lfs_size_t qsize = size / 4; + uint8_t *wb = buffer; + uint8_t *rb = buffer + size; + for (lfs_off_t j = 0; j < size; ++j) { + wb[j] = j; + } + + /* Spread sequence over size */ + lfs_file_write(&lfs, &file, wb, size) => size; + lfs_file_size(&lfs, &file) => size; + lfs_file_tell(&lfs, &file) => size; + + lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; + lfs_file_tell(&lfs, &file) => 0; + + /* Chop off the last quarter */ + lfs_size_t trunc = size - qsize; + lfs_file_truncate(&lfs, &file, trunc) => 0; + lfs_file_tell(&lfs, &file) => 0; + lfs_file_size(&lfs, &file) => trunc; + + /* Read should produce first 3/4 */ + lfs_file_read(&lfs, &file, rb, size) => trunc; + memcmp(rb, wb, trunc) => 0; + + /* Move to 1/4 */ + lfs_file_size(&lfs, &file) => trunc; + lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; + lfs_file_tell(&lfs, &file) => qsize; + + /* Chop to 1/2 */ + trunc -= qsize; + lfs_file_truncate(&lfs, &file, trunc) => 0; + lfs_file_tell(&lfs, &file) => qsize; + lfs_file_size(&lfs, &file) => trunc; + + /* Read should produce second quarter */ + lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; + memcmp(rb, wb + qsize, trunc - qsize) => 0; + + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +TEST + echo "--- Truncate and write ---" scripts/test.py << TEST lfs_mount(&lfs, &cfg) => 0;