mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/fs_truncate_support' into 'master'
FATFS truncate support See merge request idf/esp-idf!2541
This commit is contained in:
commit
c77f84e788
@ -4694,7 +4694,6 @@ FRESULT f_truncate (
|
||||
FATFS *fs;
|
||||
DWORD ncl;
|
||||
|
||||
|
||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
|
||||
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
|
@ -85,6 +85,7 @@ static int vfs_fat_closedir(void* ctx, DIR* pdir);
|
||||
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 vfs_fat_ctx_t* s_fat_ctxs[FF_VOLUMES] = { NULL, NULL };
|
||||
//backwards-compatibility with esp_vfs_fat_unregister()
|
||||
@ -144,6 +145,7 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz
|
||||
.mkdir_p = &vfs_fat_mkdir,
|
||||
.rmdir_p = &vfs_fat_rmdir,
|
||||
.access_p = &vfs_fat_access,
|
||||
.truncate_p = &vfs_fat_truncate,
|
||||
};
|
||||
size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL);
|
||||
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) calloc(1, ctx_size);
|
||||
@ -751,3 +753,74 @@ static int vfs_fat_access(void* ctx, const char *path, int amode)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vfs_fat_truncate(void* ctx, const char *path, off_t length)
|
||||
{
|
||||
FRESULT res;
|
||||
FIL* file;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
|
||||
|
||||
_lock_acquire(&fat_ctx->lock);
|
||||
prepend_drive_to_path(fat_ctx, &path, NULL);
|
||||
|
||||
file = (FIL*) calloc(1, sizeof(FIL));
|
||||
if (file == NULL) {
|
||||
ESP_LOGD(TAG, "truncate alloc failed");
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = f_open(file, path, FA_WRITE);
|
||||
|
||||
if (res != FR_OK) {
|
||||
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
|
||||
errno = fresult_to_errno(res);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = f_size(file);
|
||||
|
||||
if (res < length) {
|
||||
ESP_LOGD(TAG, "truncate does not support extending size");
|
||||
errno = EPERM;
|
||||
ret = -1;
|
||||
goto close;
|
||||
}
|
||||
|
||||
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 close;
|
||||
}
|
||||
|
||||
res = f_truncate(file);
|
||||
|
||||
if (res != FR_OK) {
|
||||
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
|
||||
errno = fresult_to_errno(res);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
close:
|
||||
res = f_close(file);
|
||||
|
||||
if (res != FR_OK) {
|
||||
ESP_LOGE(TAG, "closing file opened for truncate failed");
|
||||
// Overwrite previous errors, since not being able to close
|
||||
// an opened file is a more critical issue.
|
||||
errno = fresult_to_errno(res);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
free(file);
|
||||
_lock_release(&fat_ctx->lock);
|
||||
return ret;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <errno.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
@ -137,6 +138,81 @@ void test_fatfs_lseek(const char* filename)
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
void test_fatfs_truncate_file(const char* filename)
|
||||
{
|
||||
int read = 0;
|
||||
int truncated_len = 0;
|
||||
|
||||
const char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
char output[sizeof(input)];
|
||||
|
||||
FILE* f = fopen(filename, "wb");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(strlen(input), fprintf(f, input));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
|
||||
// Extending file beyond size is not supported
|
||||
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, EPERM);
|
||||
|
||||
|
||||
// Truncating should succeed
|
||||
const char truncated_1[] = "ABCDEFGHIJ";
|
||||
truncated_len = strlen(truncated_1);
|
||||
|
||||
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_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(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, -1));
|
||||
TEST_ASSERT_EQUAL(EPERM, 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));
|
||||
|
||||
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_fatfs_stat(const char* filename, const char* root_dir)
|
||||
{
|
||||
struct tm tm;
|
||||
|
@ -46,6 +46,8 @@ 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_stat(const char* filename, const char* root_dir);
|
||||
|
||||
void test_fatfs_unlink(const char* filename);
|
||||
@ -63,3 +65,4 @@ void test_fatfs_opendir_readdir_rewinddir(const char* dir_prefix);
|
||||
void test_fatfs_opendir_readdir_rewinddir_utf_8(const char* dir_prefix);
|
||||
|
||||
void test_fatfs_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool write);
|
||||
|
||||
|
@ -95,7 +95,6 @@ TEST_CASE("(SD) overwrite and append file", "[fatfs][sd][test_env=UT_T1_SDMODE]"
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("(SD) can lseek", "[fatfs][sd][test_env=UT_T1_SDMODE]")
|
||||
{
|
||||
test_setup();
|
||||
@ -103,6 +102,13 @@ TEST_CASE("(SD) can lseek", "[fatfs][sd][test_env=UT_T1_SDMODE]")
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("(SD) can truncate", "[fatfs][sd][test_env=UT_T1_SDMODE]")
|
||||
{
|
||||
test_setup();
|
||||
test_fatfs_truncate_file("/sdcard/truncate.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("(SD) stat returns correct values", "[fatfs][test_env=UT_T1_SDMODE]")
|
||||
{
|
||||
test_setup();
|
||||
|
@ -96,6 +96,13 @@ TEST_CASE("(WL) can lseek", "[fatfs][wear_levelling]")
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("(WL) can truncate", "[fatfs][wear_levelling]")
|
||||
{
|
||||
test_setup();
|
||||
test_fatfs_truncate_file("/spiflash/truncate.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
|
||||
{
|
||||
test_setup();
|
||||
|
30
components/newlib/platform_include/sys/unistd.h
Normal file
30
components/newlib/platform_include/sys/unistd.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
|
||||
#ifndef _ESP_SYS_UNISTD_H
|
||||
#define _ESP_SYS_UNISTD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include_next <sys/unistd.h>
|
||||
|
||||
int _EXFUN(truncate, (const char *, off_t __length));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _SYS_UNISTD_H */
|
@ -174,6 +174,10 @@ typedef struct
|
||||
int (*access_p)(void* ctx, const char *path, int amode);
|
||||
int (*access)(const char *path, int amode);
|
||||
};
|
||||
union {
|
||||
int (*truncate_p)(void* ctx, const char *path, off_t length);
|
||||
int (*truncate)(const char *path, off_t length);
|
||||
};
|
||||
/** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
|
||||
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, SemaphoreHandle_t *signal_sem);
|
||||
/** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */
|
||||
|
@ -717,6 +717,20 @@ int access(const char *path, int amode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int truncate(const char *path, off_t length)
|
||||
{
|
||||
int ret;
|
||||
const vfs_entry_t* vfs = get_vfs_for_path(path);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
const char* path_within_vfs = translate_path(vfs, path);
|
||||
CHECK_AND_CALL(ret, r, vfs, truncate, path_within_vfs, length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple)
|
||||
{
|
||||
for (int i = 0; i < end_index; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user