mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 08:48:31 +01:00
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>
356 lines
12 KiB
Bash
Executable File
356 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
set -eu
|
|
export TEST_FILE=$0
|
|
trap 'export TEST_LINE=$LINENO' DEBUG
|
|
|
|
echo "=== Truncate tests ==="
|
|
|
|
SMALLSIZE=32
|
|
MEDIUMSIZE=2048
|
|
LARGESIZE=8192
|
|
|
|
rm -rf blocks
|
|
scripts/test.py << TEST
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
TEST
|
|
|
|
echo "--- Simple truncate ---"
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldynoop",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
|
|
strcpy((char*)buffer, "hair");
|
|
lfs_size_t size = strlen((char*)buffer);
|
|
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_size_t size = strlen("hair");
|
|
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "hair", size) => 0;
|
|
}
|
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
|
|
echo "--- Truncate and read ---"
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldyread",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
|
|
strcpy((char*)buffer, "hair");
|
|
lfs_size_t size = strlen((char*)buffer);
|
|
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_size_t size = strlen("hair");
|
|
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "hair", size) => 0;
|
|
}
|
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_size_t size = strlen("hair");
|
|
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "hair", size) => 0;
|
|
}
|
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
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;
|
|
lfs_file_open(&lfs, &file, "baldywrite",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
|
|
strcpy((char*)buffer, "hair");
|
|
lfs_size_t size = strlen((char*)buffer);
|
|
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
|
|
lfs_file_size(&lfs, &file) => $LARGESIZE;
|
|
|
|
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
strcpy((char*)buffer, "bald");
|
|
lfs_size_t size = strlen((char*)buffer);
|
|
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
|
|
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
|
|
|
|
lfs_size_t size = strlen("bald");
|
|
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "bald", size) => 0;
|
|
}
|
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
|
|
# More aggressive general truncation tests
|
|
truncate_test() {
|
|
STARTSIZES="$1"
|
|
STARTSEEKS="$2"
|
|
HOTSIZES="$3"
|
|
COLDSIZES="$4"
|
|
scripts/test.py << TEST
|
|
static const lfs_off_t startsizes[] = {$STARTSIZES};
|
|
static const lfs_off_t startseeks[] = {$STARTSEEKS};
|
|
static const lfs_off_t hotsizes[] = {$HOTSIZES};
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
|
|
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
|
|
sprintf(path, "hairyhead%d", i);
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
strcpy((char*)buffer, "hair");
|
|
lfs_size_t size = strlen((char*)buffer);
|
|
for (lfs_off_t j = 0; j < startsizes[i]; j += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_size(&lfs, &file) => startsizes[i];
|
|
|
|
if (startseeks[i] != startsizes[i]) {
|
|
lfs_file_seek(&lfs, &file,
|
|
startseeks[i], LFS_SEEK_SET) => startseeks[i];
|
|
}
|
|
|
|
lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0;
|
|
lfs_file_size(&lfs, &file) => hotsizes[i];
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
static const lfs_off_t startsizes[] = {$STARTSIZES};
|
|
static const lfs_off_t hotsizes[] = {$HOTSIZES};
|
|
static const lfs_off_t coldsizes[] = {$COLDSIZES};
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
|
|
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
|
|
sprintf(path, "hairyhead%d", i);
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0;
|
|
lfs_file_size(&lfs, &file) => hotsizes[i];
|
|
|
|
lfs_size_t size = strlen("hair");
|
|
lfs_off_t j = 0;
|
|
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "hair", size) => 0;
|
|
}
|
|
|
|
for (; j < hotsizes[i]; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "\0\0\0\0", size) => 0;
|
|
}
|
|
|
|
lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0;
|
|
lfs_file_size(&lfs, &file) => coldsizes[i];
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
scripts/test.py << TEST
|
|
static const lfs_off_t startsizes[] = {$STARTSIZES};
|
|
static const lfs_off_t hotsizes[] = {$HOTSIZES};
|
|
static const lfs_off_t coldsizes[] = {$COLDSIZES};
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
|
|
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
|
|
sprintf(path, "hairyhead%d", i);
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
lfs_file_size(&lfs, &file) => coldsizes[i];
|
|
|
|
lfs_size_t size = strlen("hair");
|
|
lfs_off_t j = 0;
|
|
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
|
|
j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "hair", size) => 0;
|
|
}
|
|
|
|
for (; j < coldsizes[i]; j += size) {
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "\0\0\0\0", size) => 0;
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
TEST
|
|
}
|
|
|
|
echo "--- Cold shrinking truncate ---"
|
|
truncate_test \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE"
|
|
|
|
echo "--- Cold expanding truncate ---"
|
|
truncate_test \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE"
|
|
|
|
echo "--- Warm shrinking truncate ---"
|
|
truncate_test \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, 0, 0, 0, 0"
|
|
|
|
echo "--- Warm expanding truncate ---"
|
|
truncate_test \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE"
|
|
|
|
echo "--- Mid-file shrinking truncate ---"
|
|
truncate_test \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
" $LARGESIZE, $LARGESIZE, $LARGESIZE, $LARGESIZE, $LARGESIZE" \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, 0, 0, 0, 0"
|
|
|
|
echo "--- Mid-file expanding truncate ---"
|
|
truncate_test \
|
|
" 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE, 2*$LARGESIZE" \
|
|
" 0, 0, $SMALLSIZE, $MEDIUMSIZE, $LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
|
|
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE"
|
|
|
|
scripts/results.py
|