Просмотр исходного кода

Merge branch 'feature/ftruncate_vfs_fatfs_support' into 'master'

fatfs: Implement ftruncate function in VFS and FAT VFS

Closes IDFGH-6641

See merge request espressif/esp-idf!17389
Vamshi Gajjela 3 лет назад
Родитель
Сommit
bee6053fc0

+ 78 - 13
components/fatfs/test/test_fatfs_common.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -315,6 +307,79 @@ void test_fatfs_truncate_file(const char* filename)
     TEST_ASSERT_EQUAL(0, fclose(f));
 }
 
+void test_fatfs_ftruncate_file(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(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));
+    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_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(EPERM, errno);
+
+    TEST_ASSERT_EQUAL(-1, ftruncate(fd, strlen(input)));
+    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, -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));
+    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_fatfs_stat(const char* filename, const char* root_dir)
 {
     struct tm tm;

+ 2 - 0
components/fatfs/test/test_fatfs_common.h

@@ -43,6 +43,8 @@ void test_fatfs_lseek(const char* filename);
 
 void test_fatfs_truncate_file(const char* path);
 
+void test_fatfs_ftruncate_file(const char* path);
+
 void test_fatfs_stat(const char* filename, const char* root_dir);
 
 void test_fatfs_utime(const char* filename, const char* root_dir);

+ 7 - 0
components/fatfs/test/test_fatfs_sdmmc.c

@@ -143,6 +143,13 @@ TEST_CASE("(SD) can truncate", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
     test_teardown();
 }
 
+TEST_CASE("(SD) can ftruncate", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
+{
+    test_setup();
+    test_fatfs_ftruncate_file("/sdcard/ftrunc.txt");
+    test_teardown();
+}
+
 TEST_CASE("(SD) stat returns correct values", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
 {
     test_setup();

+ 55 - 0
components/fatfs/vfs/vfs_fat.c

@@ -81,6 +81,7 @@ static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode);
 static int vfs_fat_rmdir(void* ctx, const char* name);
 static int vfs_fat_access(void* ctx, const char *path, int amode);
 static int vfs_fat_truncate(void* ctx, const char *path, off_t length);
+static int vfs_fat_ftruncate(void* ctx, int fd, off_t length);
 static int vfs_fat_utime(void* ctx, const char *path, const struct utimbuf *times);
 #endif // CONFIG_VFS_SUPPORT_DIR
 
@@ -146,6 +147,7 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz
         .rmdir_p = &vfs_fat_rmdir,
         .access_p = &vfs_fat_access,
         .truncate_p = &vfs_fat_truncate,
+        .ftruncate_p = &vfs_fat_ftruncate,
         .utime_p = &vfs_fat_utime,
 #endif // CONFIG_VFS_SUPPORT_DIR
     };
@@ -952,6 +954,59 @@ out:
     return ret;
 }
 
+static int vfs_fat_ftruncate(void* ctx, int fd, off_t length)
+{
+    FRESULT res;
+    FIL* file = NULL;
+
+    int ret = 0;
+
+    vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
+
+    if (length < 0) {
+        errno = EINVAL;
+        ret = -1;
+        return ret;
+    }
+
+    _lock_acquire(&fat_ctx->lock);
+    file = &fat_ctx->files[fd];
+    if (file == NULL) {
+        ESP_LOGD(TAG, "ftruncate NULL file pointer");
+        errno = EINVAL;
+        ret = -1;
+        goto out;
+    }
+
+    long sz = f_size(file);
+    if (sz < length) {
+        ESP_LOGD(TAG, "ftruncate does not support extending size");
+        errno = EPERM;
+        ret = -1;
+        goto out;
+    }
+
+    res = f_lseek(file, length);
+    if (res != FR_OK) {
+        ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+        errno = fresult_to_errno(res);
+        ret = -1;
+        goto out;
+    }
+
+    res = f_truncate(file);
+
+    if (res != FR_OK) {
+        ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+        errno = fresult_to_errno(res);
+        ret = -1;
+    }
+
+out:
+    _lock_release(&fat_ctx->lock);
+    return ret;
+}
+
 static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *times)
 {
     FILINFO filinfo_time;

+ 4 - 0
components/vfs/include/esp_vfs.h

@@ -195,6 +195,10 @@ typedef struct
         int (*truncate_p)(void* ctx, const char *path, off_t length);                               /*!< truncate with context pointer */
         int (*truncate)(const char *path, off_t length);                                            /*!< truncate without context pointer */
     };
+    union {
+        int (*ftruncate_p)(void* ctx, int fd, off_t length);                                        /*!< ftruncate with context pointer */
+        int (*ftruncate)(int fd, off_t length);                                                     /*!< ftruncate without context pointer */
+    };
     union {
         int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times);                   /*!< utime with context pointer */
         int (*utime)(const char *path, const struct utimbuf *times);                                /*!< utime without context pointer */

+ 16 - 0
components/vfs/vfs.c

@@ -792,6 +792,20 @@ int esp_vfs_truncate(const char *path, off_t length)
     return ret;
 }
 
+int esp_vfs_ftruncate(int fd, off_t length)
+{
+    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
+    int local_fd = get_local_fd(vfs, fd);
+    struct _reent* r = __getreent();
+    if (vfs == NULL || local_fd < 0) {
+        __errno_r(r) = EBADF;
+        return -1;
+    }
+    int ret;
+    CHECK_AND_CALL(ret, r, vfs, ftruncate, local_fd, length);
+    return ret;
+}
+
 #endif // CONFIG_VFS_SUPPORT_DIR
 
 #ifdef CONFIG_VFS_SUPPORT_SELECT
@@ -1256,6 +1270,8 @@ int _rename_r(struct _reent *r, const char *src, const char *dst)
     __attribute__((alias("esp_vfs_rename")));
 int truncate(const char *path, off_t length)
     __attribute__((alias("esp_vfs_truncate")));
+int ftruncate(int fd, off_t length)
+    __attribute__((alias("esp_vfs_ftruncate")));
 int access(const char *path, int amode)
     __attribute__((alias("esp_vfs_access")));
 int utime(const char *path, const struct utimbuf *times)

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -789,7 +789,6 @@ components/fatfs/src/ff.h
 components/fatfs/src/ffconf.h
 components/fatfs/src/ffsystem.c
 components/fatfs/src/ffunicode.c
-components/fatfs/test/test_fatfs_common.c
 components/fatfs/test/test_fatfs_rawflash.c
 components/fatfs/test_fatfs_host/main.cpp
 components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h