Przeglądaj źródła

spiffs: Add vfs (f)truncate api support

Unit test cases added to verify truncate.

Closes https://github.com/espressif/esp-idf/issues/2234
Vamshi Gajjela 3 lat temu
rodzic
commit
0e5c9702c6

+ 42 - 0
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;

+ 1 - 1
components/spiffs/spiffs

@@ -1 +1 @@
-Subproject commit f5e26c4e933189593a71c6b82cda381a7b21e41c
+Subproject commit 2b73a7fd31f7608cd3ca46a2da8f53ff3da411b7

+ 120 - 0
components/spiffs/test/test_spiffs.c

@@ -8,6 +8,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <fcntl.h>
 #include <sys/time.h>
 #include <sys/unistd.h>
 #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();