From 0e5c9702c661997e4e4c9bb8563e260ce85af4e9 Mon Sep 17 00:00:00 2001 From: Vamshi Gajjela Date: Fri, 18 Mar 2022 15:19:18 +0530 Subject: [PATCH] spiffs: Add vfs (f)truncate api support Unit test cases added to verify truncate. Closes https://github.com/espressif/esp-idf/issues/2234 --- components/spiffs/esp_spiffs.c | 42 ++++++++++ components/spiffs/spiffs | 2 +- components/spiffs/test/test_spiffs.c | 120 +++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/components/spiffs/esp_spiffs.c b/components/spiffs/esp_spiffs.c index 5eb870cd12..4cb32822e7 100644 --- a/components/spiffs/esp_spiffs.c +++ b/components/spiffs/esp_spiffs.c @@ -68,6 +68,8 @@ static long vfs_spiffs_telldir(void* ctx, DIR* pdir); static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset); static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode); static int vfs_spiffs_rmdir(void* ctx, const char* name); +static int vfs_spiffs_truncate(void* ctx, const char *path, off_t length); +static int vfs_spiffs_ftruncate(void* ctx, int fd, off_t length); #ifdef CONFIG_SPIFFS_USE_MTIME static int vfs_spiffs_utime(void *ctx, const char *path, const struct utimbuf *times); #endif // CONFIG_SPIFFS_USE_MTIME @@ -352,6 +354,8 @@ esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf) .telldir_p = &vfs_spiffs_telldir, .mkdir_p = &vfs_spiffs_mkdir, .rmdir_p = &vfs_spiffs_rmdir, + .truncate_p = &vfs_spiffs_truncate, + .ftruncate_p = &vfs_spiffs_ftruncate, #ifdef CONFIG_SPIFFS_USE_MTIME .utime_p = &vfs_spiffs_utime, #else @@ -725,6 +729,44 @@ static int vfs_spiffs_rmdir(void* ctx, const char* name) return -1; } +static int vfs_spiffs_truncate(void* ctx, const char *path, off_t length) +{ + assert(path); + esp_spiffs_t * efs = (esp_spiffs_t *)ctx; + int fd = SPIFFS_open(efs->fs, path, SPIFFS_WRONLY, 0); + if (fd < 0) { + goto err; + } + + int res = SPIFFS_ftruncate(efs->fs, fd, length); + if (res < 0) { + (void)SPIFFS_close(efs->fs, fd); + goto err; + } + + res = SPIFFS_close(efs->fs, fd); + if (res < 0) { + goto err; + } + return res; +err: + errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); + SPIFFS_clearerr(efs->fs); + return -1; +} + +static int vfs_spiffs_ftruncate(void* ctx, int fd, off_t length) +{ + esp_spiffs_t * efs = (esp_spiffs_t *)ctx; + int res = SPIFFS_ftruncate(efs->fs, fd, length); + if (res < 0) { + errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); + SPIFFS_clearerr(efs->fs); + return -1; + } + return res; +} + static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2) { errno = ENOTSUP; diff --git a/components/spiffs/spiffs b/components/spiffs/spiffs index f5e26c4e93..2b73a7fd31 160000 --- a/components/spiffs/spiffs +++ b/components/spiffs/spiffs @@ -1 +1 @@ -Subproject commit f5e26c4e933189593a71c6b82cda381a7b21e41c +Subproject commit 2b73a7fd31f7608cd3ca46a2da8f53ff3da411b7 diff --git a/components/spiffs/test/test_spiffs.c b/components/spiffs/test/test_spiffs.c index a84ebfc0c2..cf800f18f8 100644 --- a/components/spiffs/test/test_spiffs.c +++ b/components/spiffs/test/test_spiffs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "unity.h" @@ -165,6 +166,111 @@ void test_spiffs_rename(const char* filename_prefix) TEST_ASSERT_EQUAL(0, fclose(fdst)); } +void test_spiffs_truncate(const char *filename) +{ + int read = 0; + int truncated_len = 0; + + const char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char output[sizeof(input)]; + + test_spiffs_create_file_with_text(filename, input); + + // Extending file beyond size is not supported + TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1)); + TEST_ASSERT_EQUAL(-1, truncate(filename, -1)); + + // Truncating should succeed + const char truncated_1[] = "ABCDEFGHIJ"; + truncated_len = strlen(truncated_1); + TEST_ASSERT_EQUAL(0, truncate(filename, truncated_len)); + + + FILE* f = fopen(filename, "rb"); + TEST_ASSERT_NOT_NULL(f); + memset(output, 0, sizeof(output)); + read = fread(output, 1, sizeof(output), f); + TEST_ASSERT_EQUAL(truncated_len, read); + TEST_ASSERT_EQUAL_STRING_LEN(truncated_1, output, truncated_len); + TEST_ASSERT_EQUAL(0, fclose(f)); + + // 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(-1, truncate(filename, strlen(input))); + TEST_ASSERT_EQUAL(-1, truncate(filename, strlen(input) + 1)); + TEST_ASSERT_EQUAL(-1, truncate(filename, -1)); + + + // Truncating a truncated file should succeed + const char truncated_2[] = "ABCDE"; + truncated_len = strlen(truncated_2); + TEST_ASSERT_EQUAL(0, truncate(filename, truncated_len)); + + f = fopen(filename, "rb"); + TEST_ASSERT_NOT_NULL(f); + memset(output, 0, sizeof(output)); + read = fread(output, 1, sizeof(output), f); + TEST_ASSERT_EQUAL(truncated_len, read); + TEST_ASSERT_EQUAL_STRING_LEN(truncated_2, output, truncated_len); + TEST_ASSERT_EQUAL(0, fclose(f)); +} + +void test_spiffs_ftruncate(const char *filename) +{ + int truncated_len = 0; + + const char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char output[sizeof(input)]; + + int fd = open(filename, O_WRONLY | 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(-1, ftruncate(fd, -1)); + + // Truncating should succeed + const char truncated_1[] = "ABCDEFGHIJ"; + truncated_len = strlen(truncated_1); + TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len)); + TEST_ASSERT_EQUAL(0, close(fd)); + + fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + memset(output, 0, sizeof(output)); + TEST_ASSERT_EQUAL(truncated_len, read(fd, output, sizeof(output))); + TEST_ASSERT_EQUAL_STRING_LEN(truncated_1, output, truncated_len); + TEST_ASSERT_EQUAL(0, close(fd)); + + // 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(-1, ftruncate(fd, strlen(input))); + TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input) + 1)); + TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1)); + + // Truncating a truncated file should succeed + const char truncated_2[] = "ABCDE"; + truncated_len = strlen(truncated_2); + + TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len)); + TEST_ASSERT_EQUAL(0, close(fd)); + + // open file for reading and validate the content + fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + memset(output, 0, sizeof(output)); + TEST_ASSERT_EQUAL(truncated_len, read(fd, output, sizeof(output))); + TEST_ASSERT_EQUAL_STRING_LEN(truncated_2, output, truncated_len); + TEST_ASSERT_EQUAL(0, close(fd)); +} + void test_spiffs_can_opendir(const char* path) { char name_dir_file[64]; @@ -574,6 +680,20 @@ TEST_CASE("rename moves a file", "[spiffs]") test_teardown(); } +TEST_CASE("truncate a file", "[spiffs]") +{ + test_setup(); + test_spiffs_truncate("/spiffs/truncate.txt"); + test_teardown(); +} + +TEST_CASE("ftruncate a file", "[spiffs]") +{ + test_setup(); + test_spiffs_ftruncate("/spiffs/ftrunc.txt"); + test_teardown(); +} + TEST_CASE("can opendir root directory of FS", "[spiffs]") { test_setup();