diff --git a/components/vfs/test_apps/main/CMakeLists.txt b/components/vfs/test_apps/main/CMakeLists.txt index 7ab4968a9e..e7cfc100f5 100644 --- a/components/vfs/test_apps/main/CMakeLists.txt +++ b/components/vfs/test_apps/main/CMakeLists.txt @@ -3,6 +3,7 @@ set(src "test_app_main.c" "test_vfs_access.c" "test_vfs_fd.c" "test_vfs_lwip.c" "test_vfs_open.c" "test_vfs_paths.c" "test_vfs_select.c" "test_vfs_nullfs.c" + "test_vfs_minified.c" ) idf_component_register(SRCS ${src} diff --git a/components/vfs/test_apps/main/test_vfs_minified.c b/components/vfs/test_apps/main/test_vfs_minified.c new file mode 100644 index 0000000000..f103b7b3cd --- /dev/null +++ b/components/vfs/test_apps/main/test_vfs_minified.c @@ -0,0 +1,167 @@ + +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include +#include + +#include "esp_err.h" +#include "esp_vfs_minified.h" +#include "unity.h" +#include "esp_vfs.h" + +#include "unity_test_runner.h" + +#define BUF_CAP 1024 + +typedef struct { + uint8_t data[BUF_CAP]; + size_t head; + size_t tail; +} cb_t; + +void cb_reset(cb_t* buf) { + buf->head = 0; + buf->tail = 0; +} + +size_t cb_count(const cb_t *buf) { + return buf->head - buf->tail; +} + +int cb_write(cb_t *buf, const uint8_t *data, size_t size) { + size_t count = cb_count(buf); + size_t space = BUF_CAP - count; + + size_t to_write = (size > space) ? space : size; + + size_t idx = buf->head % BUF_CAP; + size_t first_chunk = BUF_CAP - idx; + if (first_chunk > to_write) + first_chunk = to_write; + + memcpy(&buf->data[idx], data, first_chunk); + buf->head += first_chunk; + + if (first_chunk < to_write) { + size_t second_chunk = to_write - first_chunk; + memcpy(&buf->data[0], data + first_chunk, second_chunk); + buf->head += second_chunk; + } + + return (int)to_write; +} + +int cb_read(cb_t *buf, uint8_t *dest, size_t count) { + size_t available = cb_count(buf); + size_t to_read = (count > available) ? available : count; + + size_t idx = buf->tail % BUF_CAP; + size_t first_chunk = BUF_CAP - idx; + if (first_chunk > to_read) + first_chunk = to_read; + + memcpy(dest, &buf->data[idx], first_chunk); + buf->tail += first_chunk; + + if (first_chunk < to_read) { + size_t second_chunk = to_read - first_chunk; + memcpy(dest + first_chunk, &buf->data[0], second_chunk); + buf->tail += second_chunk; + } + + return (int)to_read; +} + + +int buffer_open(void *ctx, const char *path, int flags, int mode) { + return 0; +} + +int buffer_write(void *ctx, int fd, const void *data, size_t size) { + cb_t* buf = (cb_t*) ctx; + return cb_write(buf, data, size); +} + +int buffer_read(void *ctx, int fd, void *data, size_t size) { + cb_t* buf = (cb_t*) ctx; + return cb_read(buf, data, size); +} + +int buffer_close(void *ctx, int fd) { + cb_reset((cb_t*) ctx); + return 0; +} + +static esp_vfs_minified_t s_buffer_fs = { + .write_p = buffer_write, + .read_p = buffer_read, + .open_p = buffer_open, + .close_p = buffer_close, +}; + +TEST_CASE("VFS won't create a copy when ESP_FLAG_VFS_STATIC is specified", "[vfs_minified]") +{ + TEST_MESSAGE("test"); + static esp_vfs_dir_t dir = {}; + static esp_vfs_minified_t vfs = { + .dir = &dir, + }; + + cb_t *buffer = calloc(1, sizeof(cb_t)); + + esp_err_t err = ESP_OK; + err = esp_vfs_register_minified("/buffer", &s_buffer_fs, ESP_VFS_FLAG_CONTEXT_PTR | ESP_VFS_FLAG_STATIC, buffer); + TEST_ASSERT_EQUAL(ESP_OK, err); + + err = esp_vfs_register_minified("/static", &vfs, ESP_VFS_FLAG_STATIC, NULL); + TEST_ASSERT_EQUAL(ESP_OK, err); + + err = esp_vfs_register_minified("/dynamic", &vfs, ESP_VFS_FLAG_DEFAULT, NULL); + TEST_ASSERT_EQUAL(ESP_OK, err); + + FILE *buf_f = fopen("/buffer/a", "r+"); + + esp_vfs_dump_registered_paths(buf_f); + + char read_buffer[512]; + size_t bytes_read = fread(read_buffer, 1, sizeof(read_buffer) - 1, buf_f); + read_buffer[bytes_read] = '\0'; // Null-terminate the string + + // Parse the buffer to extract VFS pointers + char *line = strtok(read_buffer, "\n"); + void *static_vfs_ptr = NULL; + void *dynamic_vfs_ptr = NULL; + + while (line != NULL) { + int index; + char path_prefix[64]; + char ptr_str[32]; + TEST_MESSAGE(line); + if (sscanf(line, "%d:%63s -> %31s", &index, path_prefix, ptr_str) == 3) { + void *vfs_ptr = (void *)strtoul(ptr_str, NULL, 0); + if (strcmp(path_prefix, "/static") == 0) { + static_vfs_ptr = vfs_ptr; + } else if (strcmp(path_prefix, "/dynamic") == 0) { + dynamic_vfs_ptr = vfs_ptr; + } + } + line = strtok(NULL, "\n"); + } + + // Check that the pointer for "/static" is the same as 'vfs' and "/dynamic" is different + TEST_ASSERT_EQUAL_PTR(&vfs, static_vfs_ptr); + TEST_ASSERT_NOT_EQUAL(&vfs, dynamic_vfs_ptr); + + free(buffer); + fclose(buf_f); + + esp_vfs_unregister("/buffer"); + esp_vfs_unregister("/static"); + esp_vfs_unregister("/dynamic"); +} diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index cc2a2eab03..d01aedbcfb 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -642,7 +642,13 @@ void esp_vfs_dump_registered_paths(FILE *fp) fprintf(fp, ": -> \n"); fprintf(fp, "------------------------------------------------------\n"); for (size_t i = 0; i < VFS_MAX_COUNT; ++i) { - fprintf(fp, "%d:%s -> %p\n", i, s_vfs[i] ? s_vfs[i]->path_prefix : "NULL", s_vfs[i]); + fprintf( + fp, + "%d:%s -> %p\n", + i, + s_vfs[i] ? s_vfs[i]->path_prefix : "NULL", + s_vfs[i] ? s_vfs[i]->vfs : NULL + ); } }