feat(fatfs): Allow expanding files with seeking and truncating functions

Closes https://github.com/espressif/esp-idf/issues/13100
This commit is contained in:
Adam Múdry
2024-02-07 19:43:50 +01:00
parent 8d3e79971e
commit 35e312c48e
6 changed files with 277 additions and 82 deletions

View File

@@ -190,7 +190,14 @@ TEST_CASE("(WL) can lseek", "[fatfs][wear_levelling]")
TEST_CASE("(WL) can truncate", "[fatfs][wear_levelling]")
{
test_setup();
test_fatfs_truncate_file("/spiflash/truncate.txt");
test_fatfs_truncate_file("/spiflash/truncate.txt", true);
test_teardown();
}
TEST_CASE("(WL) can ftruncate", "[fatfs][wear_levelling]")
{
test_setup();
test_fatfs_ftruncate_file("/spiflash/ftrunc.txt", true);
test_teardown();
}

View File

@@ -186,7 +186,7 @@ TEST_CASE("(SD) can truncate", "[fatfs][sdmmc]")
{
sdmmc_card_t *card = NULL;
test_setup_sdmmc(&card);
test_fatfs_truncate_file("/sdcard/truncate.txt");
test_fatfs_truncate_file("/sdcard/truncate.txt", true);
test_teardown_sdmmc(card);
}
@@ -194,7 +194,7 @@ TEST_CASE("(SD) can ftruncate", "[fatfs][sdmmc]")
{
sdmmc_card_t *card = NULL;
test_setup_sdmmc(&card);
test_fatfs_ftruncate_file("/sdcard/ftrunc.txt");
test_fatfs_ftruncate_file("/sdcard/ftrunc.txt", true);
test_teardown_sdmmc(card);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -20,6 +20,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "test_fatfs_common.h"
#include "ff.h"
const char* fatfs_test_hello_str = "Hello, World!\n";
const char* fatfs_test_hello_str_utf = "世界,你好!\n";
@@ -252,7 +253,7 @@ void test_fatfs_lseek(const char* filename)
}
void test_fatfs_truncate_file(const char* filename)
void test_fatfs_truncate_file(const char* filename, bool allow_expanding_files)
{
int read = 0;
int truncated_len = 0;
@@ -267,14 +268,44 @@ void test_fatfs_truncate_file(const char* filename)
TEST_ASSERT_EQUAL(0, fclose(f));
struct stat st;
size_t size;
// Extending file beyond size is not supported
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1));
TEST_ASSERT_EQUAL(errno, EPERM);
stat(filename, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(strlen(input), size);
TEST_ASSERT_EQUAL(-1, truncate(filename, -1));
TEST_ASSERT_EQUAL(errno, EINVAL);
if (allow_expanding_files) {
size_t trunc_add = 2;
size_t new_size = strlen(input) + trunc_add;
TEST_ASSERT_EQUAL(0, truncate(filename, new_size));
stat(filename, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(new_size, size);
f = fopen(filename, "rb");
TEST_ASSERT_NOT_NULL(f);
char expanded_output[sizeof(input) + trunc_add];
memset(expanded_output, 42, sizeof(expanded_output)); // set to something else than 0 (42)
read = fread(expanded_output, 1, sizeof(input) + trunc_add, f);
TEST_ASSERT_EQUAL(new_size, read);
TEST_ASSERT_EQUAL('Z', expanded_output[strlen(input) - 1]); // 'Z' character
TEST_ASSERT_EQUAL('\0', expanded_output[sizeof(input) + trunc_add - 3]); // zeroed expanded space
TEST_ASSERT_EQUAL('\0', expanded_output[sizeof(input) + trunc_add - 2]); // zeroed expanded space
TEST_ASSERT_EQUAL(42, expanded_output[sizeof(input) + trunc_add - 1]); // 42 set with memset, end of the array
TEST_ASSERT_EQUAL(0, fclose(f));
} else {
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1));
TEST_ASSERT_EQUAL(errno, EPERM);
TEST_ASSERT_EQUAL(-1, truncate(filename, -1));
TEST_ASSERT_EQUAL(errno, EINVAL);
}
// Truncating should succeed
const char truncated_1[] = "ABCDEFGHIJ";
@@ -282,6 +313,10 @@ void test_fatfs_truncate_file(const char* filename)
TEST_ASSERT_EQUAL(0, truncate(filename, truncated_len));
stat(filename, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(strlen(truncated_1), size);
f = fopen(filename, "rb");
TEST_ASSERT_NOT_NULL(f);
@@ -293,28 +328,34 @@ void test_fatfs_truncate_file(const char* filename)
TEST_ASSERT_EQUAL(0, fclose(f));
if (allow_expanding_files) {
TEST_ASSERT_EQUAL(0, truncate(filename, truncated_len + 1));
} else {
// Once truncated, the new file size should be the basis
// whether truncation should succeed or not when `allow_expanding_files == false`
TEST_ASSERT_EQUAL(-1, truncate(filename, truncated_len + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
// Once truncated, the new file size should be the basis
// whether truncation should succeed or not
TEST_ASSERT_EQUAL(-1, truncate(filename, truncated_len + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input)));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input)));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
}
TEST_ASSERT_EQUAL(-1, truncate(filename, -1));
TEST_ASSERT_EQUAL(EINVAL, errno);
// Truncating a truncated file should succeed
const char truncated_2[] = "ABCDE";
truncated_len = strlen(truncated_2);
TEST_ASSERT_EQUAL(0, truncate(filename, truncated_len));
stat(filename, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(strlen(truncated_2), size);
f = fopen(filename, "rb");
TEST_ASSERT_NOT_NULL(f);
@@ -327,29 +368,63 @@ void test_fatfs_truncate_file(const char* filename)
TEST_ASSERT_EQUAL(0, fclose(f));
}
void test_fatfs_ftruncate_file(const char* filename)
void test_fatfs_ftruncate_file(const char* filename, bool allow_expanding_files)
{
int truncated_len = 0;
const char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char output[sizeof(input)];
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC);
TEST_ASSERT_NOT_EQUAL(-1, fd);
TEST_ASSERT_EQUAL(strlen(input), write(fd, input, strlen(input)));
// Extending file beyond size is not supported
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input) + 1));
TEST_ASSERT_EQUAL(errno, EPERM);
struct stat st;
size_t size;
TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1));
TEST_ASSERT_EQUAL(errno, EINVAL);
fstat(fd, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(strlen(input), size);
if (allow_expanding_files) {
size_t trunc_add = 2;
size_t new_size = strlen(input) + trunc_add;
TEST_ASSERT_EQUAL(0, ftruncate(fd, new_size));
fstat(fd, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(new_size, size);
char expanded_output[sizeof(input) + trunc_add];
memset(expanded_output, 42, sizeof(expanded_output)); // set to something else than 0 (42)
lseek(fd, 0, SEEK_SET);
int r = read(fd, expanded_output, sizeof(input) + trunc_add);
TEST_ASSERT_NOT_EQUAL(-1, r);
TEST_ASSERT_EQUAL(new_size, r);
TEST_ASSERT_EQUAL('Z', expanded_output[strlen(input) - 1]); // 'Z' character
TEST_ASSERT_EQUAL('\0', expanded_output[sizeof(input) + trunc_add - 3]); // zeroed expanded space
TEST_ASSERT_EQUAL('\0', expanded_output[sizeof(input) + trunc_add - 2]); // zeroed expanded space
TEST_ASSERT_EQUAL(42, expanded_output[sizeof(input) + trunc_add - 1]); // 42 set with memset, end of the array
} else {
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input) + 1));
TEST_ASSERT_EQUAL(errno, EPERM);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1));
TEST_ASSERT_EQUAL(errno, EINVAL);
}
// Truncating should succeed
const char truncated_1[] = "ABCDEFGHIJ";
truncated_len = strlen(truncated_1);
TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len));
fstat(fd, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(truncated_len, size);
TEST_ASSERT_EQUAL(0, close(fd));
// open file for reading and validate the content
@@ -367,25 +442,35 @@ void test_fatfs_ftruncate_file(const char* filename)
// further truncate the file
fd = open(filename, O_WRONLY);
TEST_ASSERT_NOT_EQUAL(-1, fd);
// Once truncated, the new file size should be the basis
// whether truncation should succeed or not
TEST_ASSERT_EQUAL(-1, ftruncate(fd, truncated_len + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input)));
TEST_ASSERT_EQUAL(EPERM, errno);
if (allow_expanding_files) {
TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len + 1));
} else {
// Once truncated, the new file size should be the basis
// whether truncation should succeed or not when `allow_expanding_files == false`
TEST_ASSERT_EQUAL(-1, ftruncate(fd, truncated_len + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input) + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input)));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1));
TEST_ASSERT_EQUAL(EINVAL, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input) + 1));
TEST_ASSERT_EQUAL(EPERM, errno);
TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1));
TEST_ASSERT_EQUAL(EINVAL, errno);
}
// Truncating a truncated file should succeed
const char truncated_2[] = "ABCDE";
truncated_len = strlen(truncated_2);
TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len));
fstat(fd, &st);
size = st.st_size;
TEST_ASSERT_EQUAL(truncated_len, size);
TEST_ASSERT_EQUAL(0, close(fd));
// open file for reading and validate the content

View File

@@ -45,9 +45,9 @@ void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count);
void test_fatfs_lseek(const char* filename);
void test_fatfs_truncate_file(const char* path);
void test_fatfs_truncate_file(const char* path, bool allow_expanding_files);
void test_fatfs_ftruncate_file(const char* path);
void test_fatfs_ftruncate_file(const char* path, bool allow_expanding_files);
void test_fatfs_stat(const char* filename, const char* root_dir);