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 <pab@pabigot.com>
This commit is contained in:
Peter A. Bigot
2019-08-03 11:58:19 -05:00
parent 55fb1416c7
commit 5bf71fa43e
2 changed files with 58 additions and 8 deletions

5
lfs.c
View File

@@ -2981,6 +2981,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
return LFS_ERR_INVAL; return LFS_ERR_INVAL;
} }
lfs_off_t pos = file->pos;
lfs_off_t oldsize = lfs_file_size(lfs, file); lfs_off_t oldsize = lfs_file_size(lfs, file);
if (size < oldsize) { if (size < oldsize) {
// need to flush since directly changing metadata // 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->ctz.size = size;
file->flags |= LFS_F_DIRTY | LFS_F_READING; file->flags |= LFS_F_DIRTY | LFS_F_READING;
} else if (size > oldsize) { } else if (size > oldsize) {
lfs_off_t pos = file->pos;
// flush+seek if not already at end // flush+seek if not already at end
if (file->pos != oldsize) { if (file->pos != oldsize) {
int err = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); int err = lfs_file_seek(lfs, file, 0, LFS_SEEK_END);
@@ -3022,6 +3021,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
return res; return res;
} }
} }
}
// restore pos // restore pos
int err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); int err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET);
@@ -3029,7 +3029,6 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
LFS_TRACE("lfs_file_truncate -> %d", err); LFS_TRACE("lfs_file_truncate -> %d", err);
return err; return err;
} }
}
LFS_TRACE("lfs_file_truncate -> %d", 0); LFS_TRACE("lfs_file_truncate -> %d", 0);
return 0; return 0;

View File

@@ -107,6 +107,57 @@ scripts/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST 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 ---" echo "--- Truncate and write ---"
scripts/test.py << TEST scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;