vfs_fat: fix prepend_drive_to_path

Originally, prepend_drive_to_path was designed to be a macro, and it
modified local path variables to point to a temporary buffers.
When it was converted into a function, modification to path variables
were no longer visible outside of this function.

In addition to that, prepend_drive_to_path allocated 2k bytes on the
stack for temporary path buffers. This is replaced with path buffers
allocated as part of vfs_fat context object. Locking is added around
parts of code which use these temporary buffers.

Additionally, _lock member of vfs_fat_ctx_t was placed after the
variable-sized files array, which caused the first entry in the
array to be never used. This change fixes the order of members
and adds comments.
This commit is contained in:
Ivan Grokhotkov
2017-05-04 14:46:11 +08:00
parent b65779eefe
commit 1a73b41b10

View File

@@ -22,17 +22,17 @@
#include "esp_vfs.h" #include "esp_vfs.h"
#include "esp_log.h" #include "esp_log.h"
#include "ff.h" #include "ff.h"
#include "diskio.h" #include "diskio.h"
typedef struct { typedef struct {
char fat_drive[8]; char fat_drive[8]; /* FAT drive name */
char base_path[ESP_VFS_PATH_MAX]; char base_path[ESP_VFS_PATH_MAX]; /* base path in VFS where partition is registered */
size_t max_files; size_t max_files; /* max number of simultaneously open files; size of files[] array */
FATFS fs; _lock_t lock; /* guard for access to this structure */
FIL files[0]; FATFS fs; /* fatfs library FS structure */
_lock_t lock; 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 */
FIL files[0]; /* array with max_files entries; must be the final member of the structure */
} vfs_fat_ctx_t; } vfs_fat_ctx_t;
typedef struct { typedef struct {
@@ -245,23 +245,31 @@ static void file_cleanup(vfs_fat_ctx_t* ctx, int fd)
memset(&ctx->files[fd], 0, sizeof(FIL)); memset(&ctx->files[fd], 0, sizeof(FIL));
} }
static void prepend_drive_to_path(void * ctx, const char * path, const char * path2){ /**
static char buf[FILENAME_MAX+3]; * @brief Prepend drive letters to path names
static char buf2[FILENAME_MAX+3]; * This function returns new path path pointers, pointing to a temporary buffer
sprintf(buf, "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); * inside ctx.
path = (const char *)buf; * @note Call this function with ctx->lock acquired. Paths are valid while the
* lock is held.
* @param ctx vfs_fat_ctx_t context
* @param[inout] path as input, pointer to the path; as output, pointer to the new path
* @param[inout] path2 as input, pointer to the path; as output, pointer to the new path
*/
static void prepend_drive_to_path(vfs_fat_ctx_t * ctx, const char ** path, const char ** path2){
snprintf(ctx->tmp_path_buf, sizeof(ctx->tmp_path_buf), "%s%s", ctx->fat_drive, *path);
*path = ctx->tmp_path_buf;
if(path2){ if(path2){
sprintf(buf2, "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path2); snprintf(ctx->tmp_path_buf2, sizeof(ctx->tmp_path_buf2), "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, *path2);
path2 = (const char *)buf; *path2 = ctx->tmp_path_buf2;
} }
} }
static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) static int vfs_fat_open(void* ctx, const char * path, int flags, int mode)
{ {
prepend_drive_to_path(ctx, path, NULL);
ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode); ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode);
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock); _lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &path, NULL);
int fd = get_next_fd(fat_ctx); int fd = get_next_fd(fat_ctx);
if (fd < 0) { if (fd < 0) {
ESP_LOGE(TAG, "open: no free file descriptors"); ESP_LOGE(TAG, "open: no free file descriptors");
@@ -368,9 +376,12 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st)
static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
{ {
prepend_drive_to_path(ctx, path, NULL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &path, NULL);
FILINFO info; FILINFO info;
FRESULT res = f_stat(path, &info); FRESULT res = f_stat(path, &info);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res); errno = fresult_to_errno(res);
@@ -398,8 +409,11 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
static int vfs_fat_unlink(void* ctx, const char *path) static int vfs_fat_unlink(void* ctx, const char *path)
{ {
prepend_drive_to_path(ctx, path, NULL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &path, NULL);
FRESULT res = f_unlink(path); FRESULT res = f_unlink(path);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res); errno = fresult_to_errno(res);
@@ -465,8 +479,11 @@ fail1:
static int vfs_fat_rename(void* ctx, const char *src, const char *dst) static int vfs_fat_rename(void* ctx, const char *src, const char *dst)
{ {
prepend_drive_to_path(ctx, src, dst); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &src, &dst);
FRESULT res = f_rename(src, dst); FRESULT res = f_rename(src, dst);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res); errno = fresult_to_errno(res);
@@ -477,13 +494,17 @@ static int vfs_fat_rename(void* ctx, const char *src, const char *dst)
static DIR* vfs_fat_opendir(void* ctx, const char* name) static DIR* vfs_fat_opendir(void* ctx, const char* name)
{ {
prepend_drive_to_path(ctx, name, NULL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &name, NULL);
vfs_fat_dir_t* fat_dir = calloc(1, sizeof(vfs_fat_dir_t)); vfs_fat_dir_t* fat_dir = calloc(1, sizeof(vfs_fat_dir_t));
if (!fat_dir) { if (!fat_dir) {
_lock_release(&fat_ctx->lock);
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
FRESULT res = f_opendir(&fat_dir->ffdir, name); FRESULT res = f_opendir(&fat_dir->ffdir, name);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
free(fat_dir); free(fat_dir);
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
@@ -582,8 +603,11 @@ static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset)
static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode)
{ {
(void) mode; (void) mode;
prepend_drive_to_path(ctx, name, NULL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &name, NULL);
FRESULT res = f_mkdir(name); FRESULT res = f_mkdir(name);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res); errno = fresult_to_errno(res);
@@ -594,8 +618,11 @@ 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_rmdir(void* ctx, const char* name)
{ {
prepend_drive_to_path(ctx, name, NULL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
_lock_acquire(&fat_ctx->lock);
prepend_drive_to_path(fat_ctx, &name, NULL);
FRESULT res = f_unlink(name); FRESULT res = f_unlink(name);
_lock_release(&fat_ctx->lock);
if (res != FR_OK) { if (res != FR_OK) {
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
errno = fresult_to_errno(res); errno = fresult_to_errno(res);