mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
fatfs: Add ftruncate api support for VFS and FAT-VFS
Unit test cases added to verify ftruncate within fatfs tests. Closes https://github.com/espressif/esp-idf/issues/8279
This commit is contained in:
parent
8efd164e7f
commit
ebb9cc3670
@ -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;
|
||||
|
@ -51,6 +51,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);
|
||||
|
@ -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();
|
||||
|
@ -89,6 +89,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
|
||||
|
||||
@ -154,6 +155,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
|
||||
};
|
||||
@ -960,6 +962,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;
|
||||
|
@ -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 */
|
||||
|
@ -787,6 +787,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
|
||||
@ -1251,6 +1265,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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user