summaryrefslogtreecommitdiff
path: root/lib/fatfs/vfs
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2025-07-25 13:33:07 +1000
committerjacqueline <me@jacqueline.id.au>2025-07-25 13:33:07 +1000
commitc8e79a926620e48830778714cfe4b2ea2453fcaf (patch)
tree8c756e08e01b8e147cf72bec128026f46bd854c5 /lib/fatfs/vfs
parent237136f3e93cb6b5be24670d7520adb17cc0fa36 (diff)
downloadtangara-fw-c8e79a926620e48830778714cfe4b2ea2453fcaf.tar.gz
Update forked idf components
Diffstat (limited to 'lib/fatfs/vfs')
-rw-r--r--lib/fatfs/vfs/esp_vfs_fat.h118
-rw-r--r--lib/fatfs/vfs/vfs_fat.c625
-rw-r--r--lib/fatfs/vfs/vfs_fat_internal.h47
-rw-r--r--lib/fatfs/vfs/vfs_fat_sdmmc.c85
-rw-r--r--lib/fatfs/vfs/vfs_fat_spiflash.c168
5 files changed, 819 insertions, 224 deletions
diff --git a/lib/fatfs/vfs/esp_vfs_fat.h b/lib/fatfs/vfs/esp_vfs_fat.h
index 3e7b165b..7b87818f 100644
--- a/lib/fatfs/vfs/esp_vfs_fat.h
+++ b/lib/fatfs/vfs/esp_vfs_fat.h
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,8 +7,7 @@
#pragma once
#include <stddef.h>
#include "esp_err.h"
-#include "driver/gpio.h"
-#include "driver/sdmmc_types.h"
+#include "sd_protocol_types.h"
#include "driver/sdspi_host.h"
#include "ff.h"
#include "wear_levelling.h"
@@ -18,9 +17,19 @@ extern "C" {
#endif
/**
+ * @brief Configuration structure for esp_vfs_fat_register
+ */
+typedef struct {
+ const char* base_path; /*!< Path prefix where FATFS should be registered, */
+ const char* fat_drive; /*!< FATFS drive specification; if only one drive is used, can be an empty string. */
+ size_t max_files; /*!< Maximum number of files which can be open at the same time. */
+} esp_vfs_fat_conf_t;
+
+/**
* @brief Register FATFS with VFS component
*
* This function registers given FAT drive in VFS, at the specified base path.
+ * Input arguments are held in esp_vfs_fat_conf_t structure.
* If only one drive is used, fat_drive argument can be an empty string.
* Refer to FATFS library documentation on how to specify FAT drive.
* This function also allocates FATFS structure which should be used for f_mount
@@ -30,17 +39,14 @@ extern "C" {
* POSIX and C standard library IO function with FATFS. You need to mount
* desired drive into FATFS separately.
*
- * @param base_path path prefix where FATFS should be registered
- * @param fat_drive FATFS drive specification; if only one drive is used, can be an empty string
- * @param max_files maximum number of files which can be open at the same time
+ * @param conf pointer to esp_vfs_fat_conf_t configuration structure
* @param[out] out_fs pointer to FATFS structure which can be used for FATFS f_mount call is returned via this argument.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_register was already called
* - ESP_ERR_NO_MEM if not enough memory or too many VFSes already registered
*/
-esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive,
- size_t max_files, FATFS** out_fs);
+esp_err_t esp_vfs_fat_register_cfg(const esp_vfs_fat_conf_t* conf, FATFS** out_fs);
/**
* @brief Un-register FATFS from VFS
@@ -96,8 +102,26 @@ typedef struct {
* Doesn't do anything for other memory storage media.
*/
bool disk_status_check_enable;
+ /**
+ * Use 1 FAT (File Allocation Tables) instead of 2.
+ * This decreases reliability, but makes more space available
+ * (usually only one sector).
+ * Note that this option has effect only when the filesystem is formatted.
+ * When mounting an already-formatted partition, the actual number of FATs
+ * may be different.
+ */
+ bool use_one_fat;
} esp_vfs_fat_mount_config_t;
+#define VFS_FAT_MOUNT_DEFAULT_CONFIG() \
+ { \
+ .format_if_mount_failed = false, \
+ .max_files = 5, \
+ .allocation_unit_size = 0, \
+ .disk_status_check_enable = false, \
+ .use_one_fat = false, \
+ }
+
// Compatibility definition
typedef esp_vfs_fat_mount_config_t esp_vfs_fat_sdmmc_mount_config_t;
@@ -208,6 +232,25 @@ esp_err_t esp_vfs_fat_sdmmc_unmount(void) __attribute__((deprecated("Please use
esp_err_t esp_vfs_fat_sdcard_unmount(const char* base_path, sdmmc_card_t *card);
/**
+ * @brief Format FAT filesystem with given configuration
+ *
+ * @note
+ * This API should be only called when the FAT is already mounted.
+ *
+ * @param base_path Path where partition should be registered (e.g. "/sdcard")
+ * @param card Pointer to the card handle, which should be initialised by calling `esp_vfs_fat_sdspi_mount` first
+ * @param cfg Pointer to structure with extra parameters for formatting FATFS (only relevant fields are used).
+ * If NULL, the previous configuration will be used.
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_ERR_INVALID_STATE: FAT partition isn't mounted, call esp_vfs_fat_sdmmc_mount or esp_vfs_fat_sdspi_mount first
+ * - ESP_ERR_NO_MEM: if memory can not be allocated
+ * - ESP_FAIL: fail to format it, or fail to mount back
+ */
+esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *card, esp_vfs_fat_mount_config_t *cfg);
+
+/**
* @brief Format FAT filesystem
*
* @note
@@ -268,6 +311,27 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path,
esp_err_t esp_vfs_fat_spiflash_unmount_rw_wl(const char* base_path, wl_handle_t wl_handle);
/**
+ * @brief Format FAT filesystem with given configuration
+ *
+ * @note
+ * This API can be called when the FAT is mounted / not mounted.
+ * If this API is called when the FAT isn't mounted (by calling esp_vfs_fat_spiflash_mount_rw_wl),
+ * this API will first mount the FAT then format it, then restore back to the original state.
+ *
+ * @param base_path Path where partition should be registered (e.g. "/spiflash")
+ * @param partition_label Label of the partition which should be used
+ * @param cfg Pointer to structure with extra parameters for formatting FATFS (only relevant fields are used).
+ * If NULL and mounted the previous configuration will be used.
+ * If NULL and unmounted the default configuration will be used.
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_ERR_NO_MEM: if memory can not be allocated
+ * - Other errors from esp_vfs_fat_spiflash_mount_rw_wl
+ */
+esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const char* partition_label, esp_vfs_fat_mount_config_t *cfg);
+
+/**
* @brief Format FAT filesystem
*
* @note
@@ -337,8 +401,46 @@ esp_err_t esp_vfs_fat_spiflash_unmount_ro(const char* base_path, const char* par
*/
esp_err_t esp_vfs_fat_info(const char* base_path, uint64_t* out_total_bytes, uint64_t* out_free_bytes);
+/**
+ * @brief Create a file with contiguous space at given path
+ *
+ * @note The file cannot exist before calling this function (or the file size has to be 0)
+ * For more information see documentation for `f_expand` from FATFS library
+ *
+ * @param base_path Base path of the partition examined (e.g. "/spiflash")
+ * @param full_path Full path of the file (e.g. "/spiflash/ABC.TXT")
+ * @param size File size expanded to, number of bytes in size to prepare or allocate for the file
+ * @param alloc_now True == allocate space now, false == prepare to allocate -- see `f_expand` from FATFS
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_INVALID_ARG if invalid arguments (e.g. any of arguments are NULL or size lower or equal to 0)
+ * - ESP_ERR_INVALID_STATE if partition not found
+ * - ESP_FAIL if another FRESULT error (saved in errno)
+ */
+esp_err_t esp_vfs_fat_create_contiguous_file(const char* base_path, const char* full_path, uint64_t size, bool alloc_now);
+
+/**
+ * @brief Test if a file is contiguous in the FAT filesystem
+ *
+ * @param base_path Base path of the partition examined (e.g. "/spiflash")
+ * @param full_path Full path of the file (e.g. "/spiflash/ABC.TXT")
+ * @param[out] is_contiguous True == allocate space now, false == prepare to allocate -- see `f_expand` from FATFS
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_INVALID_ARG if invalid arguments (e.g. any of arguments are NULL)
+ * - ESP_ERR_INVALID_STATE if partition not found
+ * - ESP_FAIL if another FRESULT error (saved in errno)
+ */
+esp_err_t esp_vfs_fat_test_contiguous_file(const char* base_path, const char* full_path, bool* is_contiguous);
+
/** @cond */
/**
+ * @deprecated Please use `esp_vfs_fat_register_cfg` instead
+ */
+esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive,
+ size_t max_files, FATFS** out_fs);
+
+/**
* @deprecated Please use `esp_vfs_fat_spiflash_mount_rw_wl` instead
*/
esp_err_t esp_vfs_fat_spiflash_mount(const char* base_path,
diff --git a/lib/fatfs/vfs/vfs_fat.c b/lib/fatfs/vfs/vfs_fat.c
index 4ae04c3d..b0b32fa9 100644
--- a/lib/fatfs/vfs/vfs_fat.c
+++ b/lib/fatfs/vfs/vfs_fat.c
@@ -1,21 +1,40 @@
/*
- * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
+#include <limits.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/lock.h>
+#include "esp_vfs_fat.h"
#include "esp_vfs.h"
#include "esp_log.h"
#include "ff.h"
#include "diskio_impl.h"
+#define F_WRITE_MALLOC_ZEROING_BUF_SIZE_LIMIT 512
+
+#ifdef CONFIG_VFS_SUPPORT_DIR
+struct cached_data{
+#if FF_USE_LFN
+ char file_path[FILENAME_MAX+1+FF_LFN_BUF+1]; //FILENAME_MAX+1: for dir_path, FF_LFN_BUF+1: for file name
+#else
+ char file_path[FILENAME_MAX+1+FF_SFN_BUF+1]; //FILENAME_MAX+1: for dir_path, FF_LFN_BUF+1: for file name
+#endif
+ FILINFO fileinfo;
+};
+#endif // CONFIG_VFS_SUPPORT_DIR
+
+#if !defined(FILENAME_MAX)
+#define FILENAME_MAX 255
+#endif
+
typedef struct {
char fat_drive[8]; /* FAT drive name */
char base_path[ESP_VFS_PATH_MAX]; /* base path in VFS where partition is registered */
@@ -24,8 +43,12 @@ typedef struct {
FATFS fs; /* fatfs library FS structure */
char tmp_path_buf[FILENAME_MAX+3]; /* temporary buffer used to prepend drive name to the path */
char tmp_path_buf2[FILENAME_MAX+3]; /* as above; used in functions which take two path arguments */
- bool *o_append; /* O_APPEND is stored here for each max_files entries (because O_APPEND is not compatible with FA_OPEN_APPEND) */
- FIL files[0]; /* array with max_files entries; must be the final member of the structure */
+ uint32_t *flags; /* file descriptor flags, array of max_files size */
+#ifdef CONFIG_VFS_SUPPORT_DIR
+ char dir_path[FILENAME_MAX]; /* variable to store path of opened directory*/
+ struct cached_data cached_fileinfo;
+#endif
+ FIL files[]; /* array with max_files entries; must be the final member of the structure */
} vfs_fat_ctx_t;
typedef struct {
@@ -66,6 +89,7 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode);
static int vfs_fat_close(void* ctx, int fd);
static int vfs_fat_fstat(void* ctx, int fd, struct stat * st);
static int vfs_fat_fsync(void* ctx, int fd);
+static int vfs_fat_fcntl(void* ctx, int fd, int cmd, int arg);
#ifdef CONFIG_VFS_SUPPORT_DIR
static int vfs_fat_stat(void* ctx, const char * path, struct stat * st);
static int vfs_fat_link(void* ctx, const char* n1, const char* n2);
@@ -90,6 +114,7 @@ static vfs_fat_ctx_t* s_fat_ctxs[FF_VOLUMES] = { NULL };
//backwards-compatibility with esp_vfs_fat_unregister()
static vfs_fat_ctx_t* s_fat_ctx = NULL;
+
static size_t find_context_index_by_path(const char* base_path)
{
for(size_t i=0; i<FF_VOLUMES; i++) {
@@ -112,7 +137,54 @@ static size_t find_unused_context_index(void)
esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, size_t max_files, FATFS** out_fs)
{
- size_t ctx = find_context_index_by_path(base_path);
+ esp_vfs_fat_conf_t conf = {
+ .base_path = base_path,
+ .fat_drive = fat_drive,
+ .max_files = max_files,
+ };
+ return esp_vfs_fat_register_cfg(&conf, out_fs);
+}
+
+#ifdef CONFIG_VFS_SUPPORT_DIR
+static const esp_vfs_dir_ops_t s_vfs_fat_dir = {
+ .stat_p = &vfs_fat_stat,
+ .link_p = &vfs_fat_link,
+ .unlink_p = &vfs_fat_unlink,
+ .rename_p = &vfs_fat_rename,
+ .opendir_p = &vfs_fat_opendir,
+ .closedir_p = &vfs_fat_closedir,
+ .readdir_p = &vfs_fat_readdir,
+ .readdir_r_p = &vfs_fat_readdir_r,
+ .seekdir_p = &vfs_fat_seekdir,
+ .telldir_p = &vfs_fat_telldir,
+ .mkdir_p = &vfs_fat_mkdir,
+ .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
+
+static const esp_vfs_fs_ops_t s_vfs_fat = {
+ .write_p = &vfs_fat_write,
+ .lseek_p = &vfs_fat_lseek,
+ .read_p = &vfs_fat_read,
+ .pread_p = &vfs_fat_pread,
+ .pwrite_p = &vfs_fat_pwrite,
+ .open_p = &vfs_fat_open,
+ .close_p = &vfs_fat_close,
+ .fstat_p = &vfs_fat_fstat,
+ .fcntl_p = &vfs_fat_fcntl,
+ .fsync_p = &vfs_fat_fsync,
+#ifdef CONFIG_VFS_SUPPORT_DIR
+ .dir = &s_vfs_fat_dir,
+#endif // CONFIG_VFS_SUPPORT_DIR
+};
+
+esp_err_t esp_vfs_fat_register_cfg(const esp_vfs_fat_conf_t* conf, FATFS** out_fs)
+{
+ size_t ctx = find_context_index_by_path(conf->base_path);
if (ctx < FF_VOLUMES) {
return ESP_ERR_INVALID_STATE;
}
@@ -122,55 +194,30 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz
return ESP_ERR_NO_MEM;
}
- const esp_vfs_t vfs = {
- .flags = ESP_VFS_FLAG_CONTEXT_PTR,
- .write_p = &vfs_fat_write,
- .lseek_p = &vfs_fat_lseek,
- .read_p = &vfs_fat_read,
- .pread_p = &vfs_fat_pread,
- .pwrite_p = &vfs_fat_pwrite,
- .open_p = &vfs_fat_open,
- .close_p = &vfs_fat_close,
- .fstat_p = &vfs_fat_fstat,
- .fsync_p = &vfs_fat_fsync,
-#ifdef CONFIG_VFS_SUPPORT_DIR
- .stat_p = &vfs_fat_stat,
- .link_p = &vfs_fat_link,
- .unlink_p = &vfs_fat_unlink,
- .rename_p = &vfs_fat_rename,
- .opendir_p = &vfs_fat_opendir,
- .closedir_p = &vfs_fat_closedir,
- .readdir_p = &vfs_fat_readdir,
- .readdir_r_p = &vfs_fat_readdir_r,
- .seekdir_p = &vfs_fat_seekdir,
- .telldir_p = &vfs_fat_telldir,
- .mkdir_p = &vfs_fat_mkdir,
- .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
- };
+ size_t max_files = conf->max_files;
+ if (max_files < 1) {
+ max_files = 1; // ff_memalloc(max_files * sizeof(bool)) below will fail if max_files == 0
+ }
+
size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL);
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ff_memalloc(ctx_size);
if (fat_ctx == NULL) {
return ESP_ERR_NO_MEM;
}
memset(fat_ctx, 0, ctx_size);
- fat_ctx->o_append = ff_memalloc(max_files * sizeof(bool));
- if (fat_ctx->o_append == NULL) {
+ fat_ctx->flags = ff_memalloc(max_files * sizeof(*fat_ctx->flags));
+ if (fat_ctx->flags == NULL) {
free(fat_ctx);
return ESP_ERR_NO_MEM;
}
- memset(fat_ctx->o_append, 0, max_files * sizeof(bool));
+ memset(fat_ctx->flags, 0, max_files * sizeof(*fat_ctx->flags));
fat_ctx->max_files = max_files;
- strlcpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1);
- strlcpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1);
+ strlcpy(fat_ctx->fat_drive, conf->fat_drive, sizeof(fat_ctx->fat_drive) - 1);
+ strlcpy(fat_ctx->base_path, conf->base_path, sizeof(fat_ctx->base_path) - 1);
- esp_err_t err = esp_vfs_register(base_path, &vfs, fat_ctx);
+ esp_err_t err = esp_vfs_register_fs(conf->base_path, &s_vfs_fat, ESP_VFS_FLAG_CONTEXT_PTR | ESP_VFS_FLAG_STATIC, fat_ctx);
if (err != ESP_OK) {
- free(fat_ctx->o_append);
+ free(fat_ctx->flags);
free(fat_ctx);
return err;
}
@@ -198,7 +245,7 @@ esp_err_t esp_vfs_fat_unregister_path(const char* base_path)
return err;
}
_lock_close(&fat_ctx->lock);
- free(fat_ctx->o_append);
+ free(fat_ctx->flags);
free(fat_ctx);
s_fat_ctxs[ctx] = NULL;
return ESP_OK;
@@ -386,7 +433,7 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode)
// Other VFS drivers handles O_APPEND well (to the best of my knowledge),
// therefore this flag is stored here (at this VFS level) in order to save
// memory.
- fat_ctx->o_append[fd] = (flags & O_APPEND) == O_APPEND;
+ fat_ctx->flags[fd] = (flags & (O_APPEND | O_ACCMODE));
_lock_release(&fat_ctx->lock);
return fd;
}
@@ -396,10 +443,12 @@ static ssize_t vfs_fat_write(void* ctx, int fd, const void * data, size_t size)
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
FIL* file = &fat_ctx->files[fd];
FRESULT res;
- if (fat_ctx->o_append[fd]) {
+ _lock_acquire(&fat_ctx->lock);
+ if (fat_ctx->flags[fd] & O_APPEND) {
if ((res = f_lseek(file, f_size(file))) != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res);
+ _lock_release(&fat_ctx->lock);
return -1;
}
}
@@ -407,18 +456,19 @@ static ssize_t vfs_fat_write(void* ctx, int fd, const void * data, size_t size)
res = f_write(file, data, size, &written);
if (((written == 0) && (size != 0)) && (res == 0)) {
errno = ENOSPC;
+ _lock_release(&fat_ctx->lock);
return -1;
}
if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res);
if (written == 0) {
+ _lock_release(&fat_ctx->lock);
return -1;
}
}
#if CONFIG_FATFS_IMMEDIATE_FSYNC
- _lock_acquire(&fat_ctx->lock);
if (written > 0) {
res = f_sync(file);
if (res != FR_OK) {
@@ -428,9 +478,8 @@ static ssize_t vfs_fat_write(void* ctx, int fd, const void * data, size_t size)
return -1;
}
}
- _lock_release(&fat_ctx->lock);
#endif
-
+ _lock_release(&fat_ctx->lock);
return written;
}
@@ -549,10 +598,8 @@ pwrite_release:
static int vfs_fat_fsync(void* ctx, int fd)
{
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
- _lock_acquire(&fat_ctx->lock);
FIL* file = &fat_ctx->files[fd];
FRESULT res = f_sync(file);
- _lock_release(&fat_ctx->lock);
int rc = 0;
if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
@@ -631,6 +678,26 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st)
return 0;
}
+static int vfs_fat_fcntl(void* ctx, int fd, int cmd, int arg)
+{
+ vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
+ switch (cmd) {
+ case F_GETFL:
+ return fat_ctx->flags[fd];
+ case F_SETFL:
+ fat_ctx->flags[fd] = arg;
+ return 0;
+ // no-ops:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_GETLK:
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
#ifdef CONFIG_VFS_SUPPORT_DIR
static inline mode_t get_stat_mode(bool is_dir)
@@ -639,6 +706,32 @@ static inline mode_t get_stat_mode(bool is_dir)
((is_dir) ? S_IFDIR : S_IFREG);
}
+static void update_stat_struct(struct stat *st, FILINFO *info)
+{
+ memset(st, 0, sizeof(*st));
+ st->st_size = info->fsize;
+ st->st_mode = get_stat_mode((info->fattrib & AM_DIR) != 0);
+ fat_date_t fdate = { .as_int = info->fdate };
+ fat_time_t ftime = { .as_int = info->ftime };
+ struct tm tm = {
+ .tm_mday = fdate.mday,
+ .tm_mon = fdate.mon - 1, /* unlike tm_mday, tm_mon is zero-based */
+ .tm_year = fdate.year + 80,
+ .tm_sec = ftime.sec * 2,
+ .tm_min = ftime.min,
+ .tm_hour = ftime.hour,
+ /* FAT doesn't keep track if the time was DST or not, ask the C library
+ * to try to figure this out. Note that this may yield incorrect result
+ * in the hour before the DST comes in effect, when the local time can't
+ * be converted to UTC uniquely.
+ */
+ .tm_isdst = -1
+ };
+ st->st_mtime = mktime(&tm);
+ st->st_atime = 0;
+ st->st_ctime = 0;
+}
+
static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
{
if (strcmp(path, "/") == 0) {
@@ -651,6 +744,16 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
}
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
+
+ //If fileinfo is already cached by readdir for requested filename,
+ //then return the same info else obtain fileinfo with f_stat function
+ if (strcmp(path, fat_ctx->cached_fileinfo.file_path) == 0) {
+ update_stat_struct(st, &fat_ctx->cached_fileinfo.fileinfo);
+ memset(&fat_ctx->cached_fileinfo, 0 ,sizeof(FILINFO));
+ return 0;
+ }
+
+ memset(&fat_ctx->cached_fileinfo, 0 ,sizeof(fat_ctx->cached_fileinfo));
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &path, NULL);
FILINFO info;
@@ -662,28 +765,7 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
return -1;
}
- memset(st, 0, sizeof(*st));
- st->st_size = info.fsize;
- st->st_mode = get_stat_mode((info.fattrib & AM_DIR) != 0);
- fat_date_t fdate = { .as_int = info.fdate };
- fat_time_t ftime = { .as_int = info.ftime };
- struct tm tm = {
- .tm_mday = fdate.mday,
- .tm_mon = fdate.mon - 1, /* unlike tm_mday, tm_mon is zero-based */
- .tm_year = fdate.year + 80,
- .tm_sec = ftime.sec * 2,
- .tm_min = ftime.min,
- .tm_hour = ftime.hour,
- /* FAT doesn't keep track if the time was DST or not, ask the C library
- * to try to figure this out. Note that this may yield incorrect result
- * in the hour before the DST comes in effect, when the local time can't
- * be converted to UTC uniquely.
- */
- .tm_isdst = -1
- };
- st->st_mtime = mktime(&tm);
- st->st_atime = 0;
- st->st_ctime = 0;
+ update_stat_struct(st, &info);
return 0;
}
@@ -707,74 +789,85 @@ static int vfs_fat_link(void* ctx, const char* n1, const char* n2)
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &n1, &n2);
- const size_t copy_buf_size = fat_ctx->fs.csize;
- FRESULT res;
+
+ FRESULT res = FR_OK;
+ int ret = 0;
+
FIL* pf1 = (FIL*) ff_memalloc(sizeof(FIL));
FIL* pf2 = (FIL*) ff_memalloc(sizeof(FIL));
+
+ const size_t copy_buf_size = fat_ctx->fs.csize;
void* buf = ff_memalloc(copy_buf_size);
if (buf == NULL || pf1 == NULL || pf2 == NULL) {
- _lock_release(&fat_ctx->lock);
ESP_LOGD(TAG, "alloc failed, pf1=%p, pf2=%p, buf=%p", pf1, pf2, buf);
- free(pf1);
- free(pf2);
- free(buf);
+ _lock_release(&fat_ctx->lock);
errno = ENOMEM;
- return -1;
+ ret = -1;
+ goto cleanup;
}
+
memset(pf1, 0, sizeof(*pf1));
memset(pf2, 0, sizeof(*pf2));
+
res = f_open(pf1, n1, FA_READ | FA_OPEN_EXISTING);
if (res != FR_OK) {
_lock_release(&fat_ctx->lock);
- goto fail1;
+ goto cleanup;
}
+
res = f_open(pf2, n2, FA_WRITE | FA_CREATE_NEW);
+
+#if !CONFIG_FATFS_LINK_LOCK
_lock_release(&fat_ctx->lock);
+#endif
+
if (res != FR_OK) {
- goto fail2;
+ goto close_old;
}
+
size_t size_left = f_size(pf1);
while (size_left > 0) {
size_t will_copy = (size_left < copy_buf_size) ? size_left : copy_buf_size;
size_t read;
res = f_read(pf1, buf, will_copy, &read);
if (res != FR_OK) {
- goto fail3;
+ goto close_both;
} else if (read != will_copy) {
res = FR_DISK_ERR;
- goto fail3;
+ goto close_both;
}
size_t written;
res = f_write(pf2, buf, will_copy, &written);
if (res != FR_OK) {
- goto fail3;
+ goto close_both;
} else if (written != will_copy) {
res = FR_DISK_ERR;
- goto fail3;
+ goto close_both;
}
size_left -= will_copy;
}
-#if CONFIG_FATFS_IMMEDIATE_FSYNC
- _lock_acquire(&fat_ctx->lock);
- res = f_sync(pf2);
+close_both:
+ f_close(pf2);
+
+close_old:
+ f_close(pf1);
+
+#if CONFIG_FATFS_LINK_LOCK
_lock_release(&fat_ctx->lock);
#endif
-fail3:
- f_close(pf2);
-fail2:
- f_close(pf1);
-fail1:
+cleanup:
free(buf);
free(pf2);
free(pf1);
- if (res != FR_OK) {
+ if (ret == 0 && res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res);
return -1;
}
- return 0;
+
+ return ret;
}
static int vfs_fat_rename(void* ctx, const char *src, const char *dst)
@@ -795,6 +888,7 @@ static int vfs_fat_rename(void* ctx, const char *src, const char *dst)
static DIR* vfs_fat_opendir(void* ctx, const char* name)
{
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
+ strlcpy(fat_ctx->dir_path, name, sizeof(fat_ctx->dir_path));
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &name, NULL);
vfs_fat_dir_t* fat_dir = ff_memalloc(sizeof(vfs_fat_dir_t));
@@ -832,6 +926,9 @@ static int vfs_fat_closedir(void* ctx, DIR* pdir)
static struct dirent* vfs_fat_readdir(void* ctx, DIR* pdir)
{
+ assert(ctx);
+ assert(pdir);
+ vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
struct dirent* out_dirent;
int err = vfs_fat_readdir_r(ctx, pdir, &fat_dir->cur_dirent, &out_dirent);
@@ -839,6 +936,25 @@ static struct dirent* vfs_fat_readdir(void* ctx, DIR* pdir)
errno = err;
return NULL;
}
+
+ //Store the FILEINFO in the cached_fileinfo. If the stat function is invoked immediately afterward,
+ //the cached_fileinfo will provide the FILEINFO directly, as it was already obtained during the readdir operation.
+ //During directory size calculation, this optimization can reduce the computation time.
+ memset(&fat_ctx->cached_fileinfo, 0 ,sizeof(fat_ctx->cached_fileinfo));
+ if (strcmp(fat_ctx->dir_path, "/") == 0) {
+ snprintf(fat_ctx->cached_fileinfo.file_path, sizeof(fat_ctx->cached_fileinfo.file_path),
+ "/%s", fat_dir->filinfo.fname);
+ } else {
+ char *temp_file_path = (char*) ff_memalloc(sizeof(fat_ctx->cached_fileinfo.file_path));
+ if (temp_file_path == NULL) {
+ return out_dirent;
+ }
+ snprintf(temp_file_path, sizeof(fat_ctx->cached_fileinfo.file_path),
+ "%s/%s", fat_ctx->dir_path, fat_dir->filinfo.fname);
+ memcpy(fat_ctx->cached_fileinfo.file_path, temp_file_path, sizeof(fat_ctx->cached_fileinfo.file_path));
+ ff_memfree(temp_file_path);
+ }
+ fat_ctx->cached_fileinfo.fileinfo = fat_dir->filinfo;
return out_dirent;
}
@@ -881,8 +997,10 @@ static long vfs_fat_telldir(void* ctx, DIR* pdir)
static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset)
{
assert(pdir);
+ vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
FRESULT res;
+ _lock_acquire(&fat_ctx->lock);
if (offset < fat_dir->offset) {
res = f_rewinddir(&fat_dir->ffdir);
if (res != FR_OK) {
@@ -901,6 +1019,7 @@ static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset)
}
fat_dir->offset++;
}
+ _lock_release(&fat_ctx->lock);
}
static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode)
@@ -962,6 +1081,49 @@ static int vfs_fat_access(void* ctx, const char *path, int amode)
return ret;
}
+static FRESULT f_write_zero_mem(FIL* fp, FSIZE_t data_size, FSIZE_t buf_size, UINT* bytes_written)
+{
+ if (fp == NULL || data_size <= 0 || buf_size <= 0) {
+ return FR_INVALID_PARAMETER;
+ }
+
+ void* buf = ff_memalloc(buf_size);
+ if (buf == NULL) {
+ return FR_DISK_ERR;
+ }
+ memset(buf, 0, buf_size);
+
+ FRESULT res = FR_OK;
+ UINT bw = 0;
+ FSIZE_t i = 0;
+ if (bytes_written != NULL) {
+ *bytes_written = 0;
+ }
+
+ if (data_size > buf_size) { // prevent unsigned underflow
+ for (; i < (data_size - buf_size); i += buf_size) { // write chunks of buf_size
+ res = f_write(fp, buf, (UINT) buf_size, &bw);
+ if (res != FR_OK) {
+ goto out;
+ }
+ if (bytes_written != NULL) {
+ *bytes_written += bw;
+ }
+ }
+ }
+
+ if (i < data_size) { // write the remaining data
+ res = f_write(fp, buf, (UINT) (data_size - i), &bw);
+ if (res == FR_OK && bytes_written != NULL) {
+ *bytes_written += bw;
+ }
+ }
+
+out:
+ ff_memfree(buf);
+ return res;
+}
+
static int vfs_fat_truncate(void* ctx, const char *path, off_t length)
{
FRESULT res;
@@ -1000,31 +1162,55 @@ static int vfs_fat_truncate(void* ctx, const char *path, off_t length)
goto out;
}
- long sz = f_size(file);
- if (sz < length) {
- _lock_release(&fat_ctx->lock);
- ESP_LOGD(TAG, "truncate does not support extending size");
- errno = EPERM;
- ret = -1;
- goto close;
- }
+ FSIZE_t seek_ptr_pos = (FSIZE_t) f_tell(file); // current seek pointer position
+ FSIZE_t sz = (FSIZE_t) f_size(file); // current file size (end of file position)
res = f_lseek(file, length);
- if (res != FR_OK) {
- _lock_release(&fat_ctx->lock);
- ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
- errno = fresult_to_errno(res);
- ret = -1;
- goto close;
+ if (res != FR_OK || f_tell(file) != length) {
+ goto lseek_or_write_fail;
}
- res = f_truncate(file);
+ if (sz < length) {
+ res = f_lseek(file, sz); // go to the previous end of file
+ if (res != FR_OK) {
+ goto lseek_or_write_fail;
+ }
- if (res != FR_OK) {
- ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
- errno = fresult_to_errno(res);
- ret = -1;
- goto close;
+ FSIZE_t new_free_space = ((FSIZE_t) length) - sz;
+ UINT written;
+
+ if (new_free_space > UINT32_MAX) {
+ _lock_release(&fat_ctx->lock);
+ ESP_LOGE(TAG, "%s: Cannot extend the file more than 4GB at once", __func__);
+ ret = -1;
+ goto close;
+ }
+
+ FSIZE_t buf_size_limit = F_WRITE_MALLOC_ZEROING_BUF_SIZE_LIMIT;
+ FSIZE_t buf_size = new_free_space < buf_size_limit ? new_free_space : buf_size_limit;
+ res = f_write_zero_mem(file, new_free_space, buf_size, &written);
+
+ if (res != FR_OK) {
+ goto lseek_or_write_fail;
+ } else if (written != (UINT) new_free_space) {
+ res = FR_DISK_ERR;
+ goto lseek_or_write_fail;
+ }
+
+ res = f_lseek(file, seek_ptr_pos); // return to the original position
+ if (res != FR_OK) {
+ goto lseek_or_write_fail;
+ }
+ } else {
+ res = f_truncate(file);
+
+ if (res != FR_OK) {
+ _lock_release(&fat_ctx->lock);
+ ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+ errno = fresult_to_errno(res);
+ ret = -1;
+ goto close;
+ }
}
#if CONFIG_FATFS_IMMEDIATE_FSYNC
@@ -1052,6 +1238,13 @@ close:
out:
free(file);
return ret;
+
+lseek_or_write_fail:
+ _lock_release(&fat_ctx->lock);
+ ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+ errno = fresult_to_errno(res);
+ ret = -1;
+ goto close;
}
static int vfs_fat_ftruncate(void* ctx, int fd, off_t length)
@@ -1078,29 +1271,50 @@ static int vfs_fat_ftruncate(void* ctx, int fd, off_t length)
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;
- }
+ FSIZE_t seek_ptr_pos = (FSIZE_t) f_tell(file); // current seek pointer position
+ FSIZE_t sz = (FSIZE_t) f_size(file); // current file size (end of file position)
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;
+ if (res != FR_OK || f_tell(file) != length) {
+ goto fail;
}
- res = f_truncate(file);
+ if (sz < length) {
+ res = f_lseek(file, sz); // go to the previous end of file
+ if (res != FR_OK) {
+ goto fail;
+ }
- if (res != FR_OK) {
- ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
- errno = fresult_to_errno(res);
- ret = -1;
- goto out;
+ FSIZE_t new_free_space = ((FSIZE_t) length) - sz;
+ UINT written;
+
+ if (new_free_space > UINT32_MAX) {
+ ESP_LOGE(TAG, "%s: Cannot extend the file more than 4GB at once", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ FSIZE_t buf_size_limit = F_WRITE_MALLOC_ZEROING_BUF_SIZE_LIMIT;
+ FSIZE_t buf_size = new_free_space < buf_size_limit ? new_free_space : buf_size_limit;
+ res = f_write_zero_mem(file, new_free_space, buf_size, &written);
+
+ if (res != FR_OK) {
+ goto fail;
+ } else if (written != (UINT) new_free_space) {
+ res = FR_DISK_ERR;
+ goto fail;
+ }
+
+ res = f_lseek(file, seek_ptr_pos); // return to the original position
+ if (res != FR_OK) {
+ goto fail;
+ }
+ } else {
+ res = f_truncate(file);
+
+ if (res != FR_OK) {
+ goto fail;
+ }
}
#if CONFIG_FATFS_IMMEDIATE_FSYNC
@@ -1115,6 +1329,12 @@ static int vfs_fat_ftruncate(void* ctx, int fd, off_t length)
out:
_lock_release(&fat_ctx->lock);
return ret;
+
+fail:
+ ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+ errno = fresult_to_errno(res);
+ ret = -1;
+ goto out;
}
static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *times)
@@ -1142,7 +1362,7 @@ static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *time
fat_date_t fdate;
fat_time_t ftime;
- // this time transformation is esentially the reverse of the one in vfs_fat_stat()
+ // this time transformation is essentially the reverse of the one in vfs_fat_stat()
fdate.mday = tm_time.tm_mday;
fdate.mon = tm_time.tm_mon + 1; // January in fdate.mon is 1, and 0 in tm_time.tm_mon
fdate.year = tm_time.tm_year - 80; // tm_time.tm_year=0 is 1900, tm_time.tm_year=0 is 1980
@@ -1170,3 +1390,142 @@ static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *time
}
#endif // CONFIG_VFS_SUPPORT_DIR
+
+esp_err_t esp_vfs_fat_create_contiguous_file(const char* base_path, const char* full_path, uint64_t size, bool alloc_now)
+{
+ if (base_path == NULL || full_path == NULL || size <= 0) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ size_t ctx = find_context_index_by_path(base_path);
+ if (ctx == FF_VOLUMES) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx];
+
+ _lock_acquire(&fat_ctx->lock);
+ const char* file_path = full_path + strlen(base_path); // shift the pointer and omit the base_path
+ prepend_drive_to_path(fat_ctx, &file_path, NULL);
+
+ FIL* file = (FIL*) ff_memalloc(sizeof(FIL));
+ if (file == NULL) {
+ _lock_release(&fat_ctx->lock);
+ ESP_LOGD(TAG, "esp_vfs_fat_create_contiguous_file alloc failed");
+ errno = ENOMEM;
+ return -1;
+ }
+ memset(file, 0, sizeof(*file));
+
+ FRESULT res = f_open(file, file_path, FA_WRITE | FA_OPEN_ALWAYS);
+ if (res != FR_OK) {
+ goto fail;
+ }
+
+ res = f_expand(file, size, alloc_now ? 1 : 0);
+ if (res != FR_OK) {
+ f_close(file);
+ goto fail;
+ }
+
+ res = f_close(file);
+ if (res != FR_OK) {
+ goto fail;
+ }
+
+ _lock_release(&fat_ctx->lock);
+ free(file);
+
+ return 0;
+fail:
+ _lock_release(&fat_ctx->lock);
+ free(file);
+ ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+ errno = fresult_to_errno(res);
+ return -1;
+}
+
+static FRESULT test_contiguous_file( // From FATFS examples
+ FIL* fp, /* [IN] Open file object to be checked */
+ int* cont /* [OUT] 1:Contiguous, 0:Fragmented or zero-length */
+) {
+ DWORD clst, clsz, step;
+ FSIZE_t fsz;
+ FRESULT fr;
+
+ *cont = 0;
+ fr = f_rewind(fp); /* Validates and prepares the file */
+ if (fr != FR_OK) return fr;
+
+#if FF_MAX_SS == FF_MIN_SS
+ clsz = (DWORD)fp->obj.fs->csize * FF_MAX_SS; /* Cluster size */
+#else
+ clsz = (DWORD)fp->obj.fs->csize * fp->obj.fs->ssize;
+#endif
+ fsz = f_size(fp);
+ if (fsz > 0) {
+ clst = fp->obj.sclust - 1; /* A cluster leading the first cluster for first test */
+ while (fsz) {
+ step = (fsz >= clsz) ? clsz : (DWORD)fsz;
+ fr = f_lseek(fp, f_tell(fp) + step); /* Advances file pointer a cluster */
+ if (fr != FR_OK) return fr;
+ if (clst + 1 != fp->clust) break; /* Is not the cluster next to previous one? */
+ clst = fp->clust; fsz -= step; /* Get current cluster for next test */
+ }
+ if (fsz == 0) *cont = 1; /* All done without fail? */
+ }
+
+ return FR_OK;
+}
+
+esp_err_t esp_vfs_fat_test_contiguous_file(const char* base_path, const char* full_path, bool* is_contiguous)
+{
+ if (base_path == NULL || full_path == NULL || is_contiguous == NULL) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ size_t ctx = find_context_index_by_path(base_path);
+ if (ctx == FF_VOLUMES) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx];
+
+ _lock_acquire(&fat_ctx->lock);
+ const char* file_path = full_path + strlen(base_path); // shift the pointer and omit the base_path
+ prepend_drive_to_path(fat_ctx, &file_path, NULL);
+
+ FIL* file = (FIL*) ff_memalloc(sizeof(FIL));
+ if (file == NULL) {
+ _lock_release(&fat_ctx->lock);
+ ESP_LOGD(TAG, "esp_vfs_fat_test_contiguous_file alloc failed");
+ errno = ENOMEM;
+ return -1;
+ }
+ memset(file, 0, sizeof(*file));
+
+ FRESULT res = f_open(file, file_path, FA_WRITE | FA_OPEN_ALWAYS);
+ if (res != FR_OK) {
+ goto fail;
+ }
+
+ res = test_contiguous_file(file, (int*) is_contiguous);
+ if (res != FR_OK) {
+ f_close(file);
+ goto fail;
+ }
+
+ res = f_close(file);
+ if (res != FR_OK) {
+ goto fail;
+ }
+
+ _lock_release(&fat_ctx->lock);
+ free(file);
+
+ return 0;
+fail:
+ _lock_release(&fat_ctx->lock);
+ free(file);
+ ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
+ errno = fresult_to_errno(res);
+ return -1;
+}
diff --git a/lib/fatfs/vfs/vfs_fat_internal.h b/lib/fatfs/vfs/vfs_fat_internal.h
index dc3bae27..5b894604 100644
--- a/lib/fatfs/vfs/vfs_fat_internal.h
+++ b/lib/fatfs/vfs/vfs_fat_internal.h
@@ -1,23 +1,41 @@
-// 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.
+/*
+ * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
#pragma once
#include "esp_vfs_fat.h"
+#include "diskio_impl.h"
+#include "esp_partition.h"
+#include "sdmmc_cmd.h"
#include <sys/param.h>
#include <stddef.h>
+typedef enum {
+ FORMATTED_DURING_LAST_MOUNT = 1 << 0, // The FATFS partition was formatted during the last mount
+} vfs_fat_x_ctx_flags_t;
+
+typedef struct vfs_fat_spiflash_ctx_t {
+ const esp_partition_t *partition; //The partition where the FAT is located
+ bool by_label; //If the partition is mounted by label or not
+ BYTE pdrv; //Drive number that is mounted
+ FATFS *fs; //FAT structure pointer that is registered
+ wl_handle_t wlhandle; //WL handle
+ esp_vfs_fat_mount_config_t mount_config; //Mount configuration
+ vfs_fat_x_ctx_flags_t flags; //Flags
+} vfs_fat_spiflash_ctx_t;
+
+typedef struct vfs_fat_sd_ctx_t {
+ BYTE pdrv; //Drive number that is mounted
+ esp_vfs_fat_mount_config_t mount_config; //Mount configuration
+ FATFS *fs; //FAT structure pointer that is registered
+ sdmmc_card_t *card; //Card info
+ char *base_path; //Path where partition is registered
+ vfs_fat_x_ctx_flags_t flags; //Flags
+} vfs_fat_sd_ctx_t;
+
static inline size_t esp_vfs_fat_get_allocation_unit_size(
size_t sector_size, size_t requested_size)
{
@@ -28,3 +46,6 @@ static inline size_t esp_vfs_fat_get_allocation_unit_size(
alloc_unit_size = MIN(alloc_unit_size, max_size);
return alloc_unit_size;
}
+
+vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle);
+vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card);
diff --git a/lib/fatfs/vfs/vfs_fat_sdmmc.c b/lib/fatfs/vfs/vfs_fat_sdmmc.c
index f62d6e7c..cd012d4d 100644
--- a/lib/fatfs/vfs/vfs_fat_sdmmc.c
+++ b/lib/fatfs/vfs/vfs_fat_sdmmc.c
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,7 +16,7 @@
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "soc/soc_caps.h"
-#include "driver/sdmmc_defs.h"
+#include "sd_protocol_defs.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
@@ -31,14 +31,6 @@ static const char* TAG = "vfs_fat_sdmmc";
} \
} while(0)
-typedef struct vfs_fat_sd_ctx_t {
- BYTE pdrv; //Drive number that is mounted
- esp_vfs_fat_mount_config_t mount_config; //Mount configuration
- FATFS *fs; //FAT structure pointer that is registered
- sdmmc_card_t *card; //Card info
- char *base_path; //Path where partition is registered
-} vfs_fat_sd_ctx_t;
-
static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {};
/**
* This `s_saved_ctx_id` is only used by `esp_vfs_fat_sdmmc_unmount`, which is deprecated.
@@ -75,6 +67,15 @@ static uint32_t s_get_unused_context_id(void)
return FF_VOLUMES;
}
+vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card)
+{
+ uint32_t id = FF_VOLUMES;
+ if (s_get_context_id_by_card(card, &id)) {
+ return s_ctx[id];
+ }
+ return NULL;
+}
+
static esp_err_t mount_prepare_mem(const char *base_path,
BYTE *out_pdrv,
char **out_dup_path,
@@ -116,7 +117,7 @@ cleanup:
return err;
}
-static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config)
+static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags)
{
esp_err_t err = ESP_OK;
FRESULT res = f_mount(fs, drv, 1);
@@ -134,20 +135,28 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8
return err;
}
+ if (out_flags) {
+ *out_flags |= FORMATTED_DURING_LAST_MOUNT; // set flag
+ }
+
ESP_LOGW(TAG, "mounting again");
- res = f_mount(fs, drv, 0);
+ res = f_mount(fs, drv, 1);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res);
return err;
}
+ } else {
+ if (out_flags) {
+ *out_flags &= ~FORMATTED_DURING_LAST_MOUNT; // reset flag
+ }
}
return ESP_OK;
}
static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv,
- const char *base_path, FATFS **out_fs)
+ const char *base_path, FATFS **out_fs, vfs_fat_x_ctx_flags_t *out_flags)
{
FATFS *fs = NULL;
esp_err_t err;
@@ -157,17 +166,22 @@ static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config
char drv[3] = {(char)('0' + pdrv), ':', 0};
// connect FATFS to VFS
- err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
+ esp_vfs_fat_conf_t conf = {
+ .base_path = base_path,
+ .fat_drive = drv,
+ .max_files = mount_config->max_files,
+ };
+ err = esp_vfs_fat_register_cfg(&conf, &fs);
*out_fs = fs;
if (err == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (err != ESP_OK) {
- ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", err);
+ ESP_LOGD(TAG, "esp_vfs_fat_register_cfg failed 0x(%x)", err);
goto fail;
}
// Try to mount partition
- err = s_f_mount(card, fs, drv, pdrv, mount_config);
+ err = s_f_mount(card, fs, drv, pdrv, mount_config, out_flags);
if (err != ESP_OK) {
goto fail;
}
@@ -207,7 +221,7 @@ static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config,
card->csd.sector_size,
mount_config->allocation_unit_size);
ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
- const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
+ const MKFS_PARM opt = {(BYTE)FM_ANY, (mount_config->use_one_fat ? 1 : 2), 0, 0, alloc_unit_size};
res = f_mkfs(drv, &opt, workbuf, workbuf_size);
if (res != FR_OK) {
err = ESP_FAIL;
@@ -265,7 +279,9 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
- err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs);
+ vfs_fat_x_ctx_flags_t flags = 0;
+
+ err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
@@ -276,7 +292,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
s_saved_ctx_id = 0;
}
- ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
+ ctx = calloc(1, sizeof(vfs_fat_sd_ctx_t));
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
@@ -285,6 +301,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
+ ctx->flags = flags;
ctx_id = s_get_unused_context_id();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
@@ -360,7 +377,9 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path,
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
- err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs);
+ vfs_fat_x_ctx_flags_t flags = 0;
+
+ err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
@@ -371,7 +390,7 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path,
s_saved_ctx_id = 0;
}
- ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
+ ctx = calloc(1, sizeof(vfs_fat_sd_ctx_t));
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
@@ -380,6 +399,7 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path,
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
+ ctx->flags = flags;
ctx_id = s_get_unused_context_id();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
@@ -450,7 +470,7 @@ esp_err_t esp_vfs_fat_sdcard_unmount(const char *base_path, sdmmc_card_t *card)
return err;
}
-esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card)
+esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *card, esp_vfs_fat_mount_config_t *cfg)
{
esp_err_t ret = ESP_OK;
if (!card) {
@@ -480,13 +500,22 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card)
//format
uint32_t id = FF_VOLUMES;
- bool found = s_get_context_id_by_card(card, &id);
- assert(found);
+
+ {
+ const bool found = s_get_context_id_by_card(card, &id);
+ (void)found;
+ assert(found);
+ }
+
+ if (cfg) {
+ s_ctx[id]->mount_config = *cfg;
+ }
+
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(
card->csd.sector_size,
s_ctx[id]->mount_config.allocation_unit_size);
ESP_LOGI(TAG, "Formatting card, allocation unit size=%d", alloc_unit_size);
- const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
+ const MKFS_PARM opt = {(BYTE)FM_ANY, (s_ctx[id]->mount_config.use_one_fat ? 1 : 2), 0, 0, alloc_unit_size};
res = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
if (res != FR_OK) {
@@ -495,7 +524,7 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card)
}
//mount back
- esp_err_t err = s_f_mount(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config);
+ esp_err_t err = s_f_mount(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config, NULL);
if (err != ESP_OK) {
unmount_card_core(base_path, card);
ESP_LOGE(TAG, "failed to format, resources recycled, please mount again");
@@ -503,3 +532,7 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card)
return ret;
}
+
+esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) {
+ return esp_vfs_fat_sdcard_format_cfg(base_path, card, NULL);
+}
diff --git a/lib/fatfs/vfs/vfs_fat_spiflash.c b/lib/fatfs/vfs/vfs_fat_spiflash.c
index 98e4160f..0ee00e25 100644
--- a/lib/fatfs/vfs/vfs_fat_spiflash.c
+++ b/lib/fatfs/vfs/vfs_fat_spiflash.c
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,16 +15,11 @@
#include "wear_levelling.h"
#include "diskio_wl.h"
-static const char* TAG = "vfs_fat_spiflash";
+// If the available sectors based on partition size are less than 128,
+// the root directory sector should be set to 1.
+#define MIN_REQ_SEC 128
-typedef struct vfs_fat_spiflash_ctx_t {
- const esp_partition_t *partition; //The partition where the FAT is located
- bool by_label; //If the partition is mounted by lable or not
- BYTE pdrv; //Drive number that is mounted
- FATFS *fs; //FAT structure pointer that is registered
- wl_handle_t wlhandle; //WL handle
- esp_vfs_fat_mount_config_t mount_config; //Mount configuration
-} vfs_fat_spiflash_ctx_t;
+static const char* TAG = "vfs_fat_spiflash";
static vfs_fat_spiflash_ctx_t *s_ctx[FF_VOLUMES] = {};
@@ -74,35 +69,78 @@ static uint32_t s_get_unused_context_id(void)
return FF_VOLUMES;
}
-static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config)
+vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle)
{
- FRESULT fresult = f_mount(fs, drv, 1);
- if (fresult != FR_OK) {
- ESP_LOGW(TAG, "f_mount failed (%d)", fresult);
+ uint32_t id = FF_VOLUMES;
+ if (s_get_context_id_by_wl_handle(wlhandle, &id)) {
+ return s_ctx[id];
+ }
+ return NULL;
+}
- bool need_mount_again = (fresult == FR_NO_FILESYSTEM || fresult == FR_INT_ERR) && mount_config->format_if_mount_failed;
- if (!need_mount_again) {
- return ESP_FAIL;
+static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags, size_t sec_num)
+{
+ FRESULT fresult = f_mount(fs, drv, 1);
+ if (fresult == FR_OK) {
+ if (out_flags) {
+ *out_flags &= ~FORMATTED_DURING_LAST_MOUNT; // reset flag
}
+ return ESP_OK;
+ }
- const size_t workbuf_size = 4096;
- void *workbuf = ff_memalloc(workbuf_size);
- if (workbuf == NULL) {
- return ESP_ERR_NO_MEM;
- }
+ const char *msg = "Unknown";
+ const char *note = "";
+ bool recoverable = false;
+
+ switch (fresult) {
+ case FR_NO_FILESYSTEM:
+ msg = "No filesystem detected";
+ note = "(This may indicate corrupt FS, or attempt to mount read-only fatfsgen image for write)";
+ recoverable = true;
+ break;
+ case FR_INT_ERR:
+ msg = "Assertion failed";
+ recoverable = true;
+ break;
+ default:
+ break;
+ }
+
+ if (!recoverable || !mount_config->format_if_mount_failed) {
+ ESP_LOGE(TAG, "f_mount failed with error: \"%s\" [%d]. %s", msg, fresult, note);
+ return ESP_FAIL;
+ }
+
+ ESP_LOGW(TAG, "FatFS mount (f_mount) failed with error: \"%s\" [%d]. Retrying after format...", msg, fresult);
- size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, mount_config->allocation_unit_size);
- ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
- const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, alloc_unit_size};
- fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);
- free(workbuf);
- workbuf = NULL;
- ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mkfs failed (%d)", fresult);
-
- ESP_LOGI(TAG, "Mounting again");
- fresult = f_mount(fs, drv, 0);
- ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mount failed after formatting (%d)", fresult);
+ const size_t workbuf_size = 4096;
+ void *workbuf = ff_memalloc(workbuf_size);
+ if (workbuf == NULL) {
+ return ESP_ERR_NO_MEM;
}
+
+ size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, mount_config->allocation_unit_size);
+ ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
+ UINT root_dir_entries;
+ if (CONFIG_WL_SECTOR_SIZE == 512) {
+ root_dir_entries = 16;
+ } else {
+ root_dir_entries = 128;
+ }
+ const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (mount_config->use_one_fat ? 1 : 2), 0, (sec_num <= MIN_REQ_SEC ? root_dir_entries : 0), alloc_unit_size};
+ fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);
+ free(workbuf);
+ workbuf = NULL;
+ ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mkfs failed (%d)", fresult);
+
+ if (out_flags) {
+ *out_flags |= FORMATTED_DURING_LAST_MOUNT; // set flag
+ }
+
+ ESP_LOGI(TAG, "Mounting again");
+ fresult = f_mount(fs, drv, 1);
+ ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mount failed after formatting (%d)", fresult);
+
return ESP_OK;
}
@@ -134,27 +172,36 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path,
ESP_GOTO_ON_ERROR(ff_diskio_register_wl_partition(pdrv, *wl_handle), fail, TAG, "ff_diskio_register_wl_partition failed pdrv=%i, error - 0x(%x)", pdrv, ret);
FATFS *fs;
- ret = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
+ esp_vfs_fat_conf_t conf = {
+ .base_path = base_path,
+ .fat_drive = drv,
+ .max_files = mount_config->max_files,
+ };
+ ret = esp_vfs_fat_register_cfg(&conf, &fs);
if (ret == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (ret != ESP_OK) {
- ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", ret);
+ ESP_LOGD(TAG, "esp_vfs_fat_register_cfg failed 0x(%x)", ret);
goto fail;
}
+ vfs_fat_x_ctx_flags_t flags = 0;
+
+ size_t sec_num = wl_size(*wl_handle) / wl_sector_size(*wl_handle);
// Try to mount partition
- ret = s_f_mount_rw(fs, drv, mount_config);
+ ret = s_f_mount_rw(fs, drv, mount_config, &flags, sec_num);
if (ret != ESP_OK) {
goto fail;
}
- ctx = calloc(sizeof(vfs_fat_spiflash_ctx_t), 1);
+ ctx = calloc(1, sizeof(vfs_fat_spiflash_ctx_t));
ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, fail, TAG, "no mem");
ctx->partition = data_partition;
ctx->by_label = (partition_label != NULL);
ctx->pdrv = pdrv;
ctx->fs = fs;
ctx->wlhandle = *wl_handle;
+ ctx->flags = flags;
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
ctx_id = s_get_unused_context_id();
//At this stage, we should always get a free context, otherwise program should return already
@@ -201,25 +248,43 @@ esp_err_t esp_vfs_fat_spiflash_unmount_rw_wl(const char* base_path, wl_handle_t
return err;
}
-esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* partition_label)
+esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const char* partition_label, esp_vfs_fat_mount_config_t *cfg)
{
esp_err_t ret = ESP_OK;
bool partition_was_mounted = false;
wl_handle_t temp_handle = WL_INVALID_HANDLE;
uint32_t id = FF_VOLUMES;
+ size_t sec_num = 0;
bool found = s_get_context_id_by_label(partition_label, &id);
if (!found) {
- const esp_vfs_fat_mount_config_t mount_config = {
+ esp_vfs_fat_mount_config_t default_mount_config = {
.max_files = 1,
.format_if_mount_failed = true,
};
- ESP_RETURN_ON_ERROR(esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, &mount_config, &temp_handle), TAG, "Failed to mount");
+ esp_vfs_fat_mount_config_t *mount_cfg = NULL;
+ if (cfg) {
+ mount_cfg = cfg;
+ } else {
+ mount_cfg = &default_mount_config;
+ }
+ ESP_RETURN_ON_ERROR(esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, mount_cfg, &temp_handle), TAG, "Failed to mount");
found = s_get_context_id_by_label(partition_label, &id);
+ sec_num = wl_size(temp_handle) / wl_sector_size(temp_handle);
assert(found);
+ if (s_ctx[id]->flags & FORMATTED_DURING_LAST_MOUNT) {
+ ESP_LOGD(TAG, "partition was formatted during mounting, skipping another format");
+ ret = ESP_OK;
+ goto mount_back;
+ }
} else {
partition_was_mounted = true;
+ if (cfg) {
+ s_ctx[id]->mount_config = *cfg;
+ }
+ temp_handle = s_ctx[id]->wlhandle;
+ sec_num = wl_size(temp_handle) / wl_sector_size(temp_handle);
}
//unmount
@@ -236,7 +301,13 @@ esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* p
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, s_ctx[id]->mount_config.allocation_unit_size);
ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
- const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, alloc_unit_size};
+ UINT root_dir_entries;
+ if (CONFIG_WL_SECTOR_SIZE == 512) {
+ root_dir_entries = 16;
+ } else {
+ root_dir_entries = 128;
+ }
+ const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (s_ctx[id]->mount_config.use_one_fat ? 1 : 2), 0, (sec_num <= MIN_REQ_SEC ? root_dir_entries : 0), alloc_unit_size};
fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
workbuf = NULL;
@@ -244,7 +315,7 @@ esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* p
mount_back:
if (partition_was_mounted) {
- esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config);
+ esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config, NULL, sec_num);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to mount back, go to recycle");
goto recycle;
@@ -265,6 +336,10 @@ recycle:
return ret;
}
+esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* partition_label)
+{
+ return esp_vfs_fat_spiflash_format_cfg_rw_wl(base_path, partition_label, NULL);
+}
esp_err_t esp_vfs_fat_spiflash_mount_ro(const char* base_path,
const char* partition_label,
@@ -287,11 +362,16 @@ esp_err_t esp_vfs_fat_spiflash_mount_ro(const char* base_path,
ESP_GOTO_ON_ERROR(ff_diskio_register_raw_partition(pdrv, data_partition), fail, TAG, "ff_diskio_register_raw_partition failed pdrv=%i, error - 0x(%x)", pdrv, ret);
FATFS *fs;
- ret = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
+ esp_vfs_fat_conf_t conf = {
+ .base_path = base_path,
+ .fat_drive = drv,
+ .max_files = mount_config->max_files,
+ };
+ ret = esp_vfs_fat_register_cfg(&conf, &fs);
if (ret == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (ret != ESP_OK) {
- ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", ret);
+ ESP_LOGD(TAG, "esp_vfs_fat_register_cfg failed 0x(%x)", ret);
goto fail;
}