feat(vfs): add linux support to vfs

This commit is contained in:
sonika.rathi
2024-09-04 12:41:13 +02:00
parent 70b28a8d8a
commit 24e42cc4a6
21 changed files with 830 additions and 22 deletions
+4 -2
View File
@@ -2,17 +2,19 @@ idf_build_get_property(target IDF_TARGET)
set(srcs "commands.c"
"esp_console_common.c"
"esp_console_repl_internal.c"
"split_argv.c"
"linenoise/linenoise.c")
set(requires vfs)
if(${target} STREQUAL "linux")
list(APPEND srcs "esp_console_repl_linux.c")
list(APPEND srcs "esp_console_repl_linux.c" "esp_console_repl_internal.c")
else()
list(APPEND srcs "esp_console_repl_chip.c")
list(APPEND requires esp_stdio)
if(CONFIG_VFS_SUPPORT_SELECT)
list(APPEND srcs "esp_console_repl_internal.c")
endif()
endif()
set(argtable_srcs argtable3/arg_cmd.c
+1 -1
View File
@@ -106,7 +106,7 @@ esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_co
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
#if CONFIG_VFS_SUPPORT_SELECT
#if CONFIG_VFS_SUPPORT_SELECT || CONFIG_IDF_TARGET_LINUX
ret = esp_console_internal_set_event_fd(repl_com);
if (ret != ESP_OK) {
goto _exit;
@@ -16,8 +16,6 @@
#include "esp_vfs_eventfd.h"
#if CONFIG_VFS_SUPPORT_SELECT
static const char *TAG = "console.repl.internal";
static int s_interrupt_reading_fd = -1;
@@ -38,7 +36,7 @@ static ssize_t read_bytes(int fd, void *buf, size_t max_bytes)
return -1;
}
if (FD_ISSET(s_interrupt_reading_fd, &read_fds)) {
if (s_interrupt_reading_fd != -1 && FD_ISSET(s_interrupt_reading_fd, &read_fds)) {
/* read termination request happened, return */
int buf[sizeof(s_interrupt_reading_signal)];
nread = read(s_interrupt_reading_fd, buf, sizeof(s_interrupt_reading_signal));
@@ -147,7 +145,6 @@ esp_err_t esp_console_common_deinit(esp_console_repl_com_t *repl_com)
return ESP_OK;
}
#endif // CONFIG_VFS_SUPPORT_SELECT
/* DO NOT move this function out of this file. All other definitions in this
* file are strong definition of weak functions.
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -74,6 +74,12 @@ static esp_err_t esp_console_repl_linux_delete(esp_console_repl_t *repl)
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
ret = esp_console_common_deinit(&linux_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
esp_console_deinit();
free(linux_repl);
@@ -1 +1,2 @@
CONFIG_IDF_TARGET="linux"
CONFIG_VFS_SUPPORT_IO=n
@@ -1,4 +1,5 @@
CONFIG_IDF_TARGET="linux"
CONFIG_VFS_SUPPORT_IO=n
# enable sorted commands in the help command
CONFIG_CONSOLE_SORTED_HELP=y
@@ -0,0 +1 @@
CONFIG_VFS_SUPPORT_IO=n
+16 -2
View File
@@ -2,8 +2,22 @@ idf_build_get_property(target IDF_TARGET)
# On Linux, we only support a few features, hence this simple component registration
if(${target} STREQUAL "linux")
idf_component_register(SRCS "vfs_eventfd_linux.c"
INCLUDE_DIRS "include")
list(APPEND inc include)
if(CONFIG_VFS_SUPPORT_IO)
list(APPEND inc linux_include)
list(APPEND priv_inc private_include)
list(APPEND srcs "vfs_linux.c" "vfs.c")
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
list(APPEND srcs "vfs_eventfd_linux.c")
endif()
idf_component_register(SRCS ${srcs}
LDFRAGMENTS "linker.lf"
INCLUDE_DIRS ${inc}
PRIV_INCLUDE_DIRS ${priv_inc})
return()
endif()
+8
View File
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
# This test app doesn't require FreeRTOS, using mock instead
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
project(vfs_linux_test)
@@ -0,0 +1,10 @@
set(src "test_vfs.c" "test_vfs_linux_dev.c")
idf_component_register(SRCS ${src}
INCLUDE_DIRS .
PRIV_REQUIRES vfs unity
WHOLE_ARCHIVE
)
# dlsym is used to dynamically link native Linux platform functions during test execution
target_link_libraries(${COMPONENT_LIB} PRIVATE dl)
+265
View File
@@ -0,0 +1,265 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include "esp_vfs.h"
#include "test_vfs_linux_dev.h"
#include "unity.h"
#include "unity_fixture.h"
TEST_GROUP(vfs_linux);
TEST_SETUP(vfs_linux)
{
}
TEST_TEAR_DOWN(vfs_linux)
{
}
static void test_create_file_with_text(const char* name, const char* text)
{
int fd = -1;
fd = open(name, O_CREAT|O_RDWR, 0777);
TEST_ASSERT_NOT_EQUAL(-1, fd);
ssize_t sz = write(fd, text, strlen(text));
TEST_ASSERT_EQUAL(strlen(text), sz);
TEST_ASSERT_EQUAL(0, close(fd));
}
TEST(vfs_linux,test_linux_vfs_open)
{
linux_vfs_dev_register();
const char *test_str = "Espressif";
const char *filename = "/linux/test.txt";
test_create_file_with_text(filename, test_str);
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
int len = strlen(test_str);
char buf[10];
TEST_ASSERT_EQUAL(len, read(fd, buf, len));
TEST_ASSERT_EQUAL(0, strncmp(test_str, buf, len));
close(fd);
unlink(filename);
printf("Inside %s\n",__func__);
linux_vfs_dev_unregister();
}
static void test_lseek(void)
{
const char *test_str = "0123456789\n";
const char *filename = "/linux/lseek.txt";
test_create_file_with_text(filename, test_str);
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
off_t off = lseek(fd, 6, SEEK_CUR);
TEST_ASSERT_EQUAL(6, off);
off = lseek(fd, 3, SEEK_SET);
TEST_ASSERT_EQUAL(3, off);
off = lseek(fd, -9, SEEK_END);
TEST_ASSERT_EQUAL(2, off);
close(fd);
unlink(filename);
}
TEST(vfs_linux, test_lseek_via_vfs)
{
printf("Inside %s\n",__func__);
linux_vfs_dev_register();
printf("Inside %s\n",__func__);
test_lseek();
linux_vfs_dev_unregister();
}
static void test_pread_pwrite(void)
{
const char *test_str = "0123456789";
const char *filename = "/linux/pread_pwrite.txt";
test_create_file_with_text(filename, test_str);
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
// Test pwrite
const char *write_str = "ABCD";
ssize_t written = pwrite(fd, write_str, strlen(write_str), 2);
TEST_ASSERT_EQUAL(strlen(write_str), written);
// Test pread
char read_buf[10] = {0};
ssize_t bytes_read = pread(fd, read_buf, 4, 2);
TEST_ASSERT_EQUAL(4, bytes_read);
TEST_ASSERT_EQUAL(0, strncmp(write_str, read_buf, 4));
close(fd);
unlink(filename);
}
TEST(vfs_linux, test_pread_pwrite_via_vfs)
{
linux_vfs_dev_register();
test_pread_pwrite();
linux_vfs_dev_unregister();
}
static void test_unlink(void)
{
const char *filename = "/linux/unlink.txt";
test_create_file_with_text(filename, "test");
// Test that file exists
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
close(fd);
// Test unlink
TEST_ASSERT_EQUAL(0, unlink(filename));
// Test that file no longer exists
fd = open(filename, O_RDWR);
TEST_ASSERT_EQUAL(-1, fd);
TEST_ASSERT_EQUAL(ENOENT, errno);
}
TEST(vfs_linux, test_unlink_via_vfs)
{
linux_vfs_dev_register();
test_unlink();
linux_vfs_dev_unregister();
}
static void test_fstat(void)
{
const char *filename = "/linux/fstat.txt";
test_create_file_with_text(filename, "test");
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
struct stat st;
TEST_ASSERT_EQUAL(0, fstat(fd, &st));
TEST_ASSERT_TRUE(S_ISREG(st.st_mode)); // Check if it's a regular file
TEST_ASSERT_EQUAL(4, st.st_size); // Check file size
close(fd);
unlink(filename);
}
TEST(vfs_linux, test_fstat_via_vfs)
{
linux_vfs_dev_register();
test_fstat();
linux_vfs_dev_unregister();
}
static void test_fcntl(void)
{
const char *filename = "/linux/fcntl.txt";
test_create_file_with_text(filename, "test");
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
// Test F_GETFL
int flags = fcntl(fd, F_GETFL);
TEST_ASSERT_NOT_EQUAL(-1, flags);
TEST_ASSERT_EQUAL(O_RDWR, (flags & O_RDWR)); // Check if file is opened in read-write mode
close(fd);
unlink(filename);
}
TEST(vfs_linux, test_fcntl_via_vfs)
{
linux_vfs_dev_register();
test_fcntl();
linux_vfs_dev_unregister();
}
static void test_ftruncate(void)
{
const char *test_str = "0123456789\n";
const char *filename = "/linux/ftruncate.txt";
test_create_file_with_text(filename, test_str);
int fd = open(filename, O_RDWR);
TEST_ASSERT_NOT_EQUAL(-1, fd);
// Test truncating to a smaller size
const char truncated_1[] = "01234";
off_t truncated_len = strlen(truncated_1);
TEST_ASSERT_EQUAL(0, ftruncate(fd, truncated_len));
// Verify the file size after truncation
struct stat st;
TEST_ASSERT_EQUAL(0, fstat(fd, &st));
TEST_ASSERT_EQUAL(truncated_len, st.st_size);
// Read back the truncated content
char buf[32] = {0};
TEST_ASSERT_EQUAL(truncated_len, read(fd, buf, sizeof(buf)));
TEST_ASSERT_EQUAL(0, strncmp(truncated_1, buf, truncated_len));
// Test truncating to a larger size
off_t new_size = truncated_len + 5;
TEST_ASSERT_EQUAL(0, ftruncate(fd, new_size));
TEST_ASSERT_EQUAL(0, fstat(fd, &st));
TEST_ASSERT_EQUAL(new_size, st.st_size);
// Test truncating to zero
TEST_ASSERT_EQUAL(0, ftruncate(fd, 0));
TEST_ASSERT_EQUAL(0, fstat(fd, &st));
TEST_ASSERT_EQUAL(0, st.st_size);
// Test invalid length
TEST_ASSERT_EQUAL(-1, ftruncate(fd, -1));
TEST_ASSERT_EQUAL(EINVAL, errno);
close(fd);
unlink(filename);
}
TEST(vfs_linux, test_ftruncate_via_vfs)
{
linux_vfs_dev_register();
test_ftruncate();
linux_vfs_dev_unregister();
}
TEST_GROUP_RUNNER(vfs_linux)
{
RUN_TEST_CASE(vfs_linux, test_linux_vfs_open);
RUN_TEST_CASE(vfs_linux, test_lseek_via_vfs);
RUN_TEST_CASE(vfs_linux, test_pread_pwrite_via_vfs);
RUN_TEST_CASE(vfs_linux, test_unlink_via_vfs);
RUN_TEST_CASE(vfs_linux, test_fstat_via_vfs);
RUN_TEST_CASE(vfs_linux, test_fcntl_via_vfs);
RUN_TEST_CASE(vfs_linux, test_ftruncate_via_vfs);
}
static void run_all_tests(void)
{
RUN_TEST_GROUP(vfs_linux);
}
int main(int argc, char **argv)
{
UNITY_MAIN_FUNC(run_all_tests);
return 0;
}
@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include "esp_vfs.h"
#include "sdkconfig.h"
#define NONE -1
typedef int (*open_func_t)(const char * path, int flags, ...);
typedef int (*close_func_t)(int s);
typedef ssize_t (*write_func_t)(int fd, const void * data, size_t size);
typedef ssize_t (*read_func_t)(int fd, void* data, size_t size);
typedef ssize_t (*pread_func_t)(int fd, void *dst, size_t size, off_t offset);
typedef ssize_t (*pwrite_func_t)(int fd, const void *src, size_t size, off_t offset);
typedef off_t (*lseek_func_t)(int fd, off_t size, int mode);
typedef int (*fstat_func_t)(int fd, struct stat *st);
typedef int (*fcntl_func_t)(int fd, int cmd, int arg);
typedef int (*fsync_func_t)(int fd);
typedef int (*ioctl_func_t)(int fd, int cmd, va_list args);
typedef int (*unlink_func_t)(const char *path);
typedef int (*ftruncate_func_t)(int fd, off_t length);
static open_func_t __real_open = NULL;
static close_func_t __real_close = NULL;
static write_func_t __real_write = NULL;
static read_func_t __real_read = NULL;
static pread_func_t __real_pread = NULL;
static pwrite_func_t __real_pwrite = NULL;
static lseek_func_t __real_lseek = NULL;
static fstat_func_t __real_fstat = NULL;
static fcntl_func_t __real_fcntl = NULL;
static fsync_func_t __real_fsync = NULL;
static ioctl_func_t __real_ioctl = NULL;
static unlink_func_t __real_unlink = NULL;
static ftruncate_func_t __real_ftruncate = NULL;
void __attribute__((constructor)) init_real_funcs(void)
{
__real_open = (open_func_t) dlsym(RTLD_NEXT, "open");
__real_close = (close_func_t) dlsym(RTLD_NEXT, "close");
__real_write = (write_func_t) dlsym(RTLD_NEXT, "write");
__real_read = (read_func_t) dlsym(RTLD_NEXT, "read");
__real_pread = (pread_func_t) dlsym(RTLD_NEXT, "pread");
__real_pwrite = (pwrite_func_t) dlsym(RTLD_NEXT, "pwrite");
__real_lseek = (lseek_func_t) dlsym(RTLD_NEXT, "lseek");
__real_fstat = (fstat_func_t) dlsym(RTLD_NEXT, "fstat");
__real_fcntl = (fcntl_func_t) dlsym(RTLD_NEXT, "fcntl");
__real_fsync = (fsync_func_t) dlsym(RTLD_NEXT, "fsync");
__real_ioctl = (ioctl_func_t) dlsym(RTLD_NEXT, "ioctl");
__real_unlink = (unlink_func_t) dlsym(RTLD_NEXT, "unlink");
__real_ftruncate = (ftruncate_func_t) dlsym(RTLD_NEXT, "ftruncate");
}
static int linux_open(const char *path, int flags, int mode)
{
return __real_open(path+1, flags, mode);
}
static ssize_t linux_write(int fd, const void * data, size_t size)
{
return __real_write(fd, data, size);
}
static ssize_t linux_read(int fd, void* data, size_t size)
{
return __real_read(fd, data, size);
}
static int linux_close(int fd)
{
return __real_close(fd);
}
static ssize_t linux_pread(int fd, void *dst, size_t size, off_t offset)
{
return __real_pread(fd, dst, size, offset);
}
static ssize_t linux_pwrite(int fd, const void *src, size_t size, off_t offset)
{
return __real_pwrite(fd, src, size, offset);
}
static off_t linux_lseek(int fd, off_t size, int mode)
{
return __real_lseek(fd, size, mode);
}
static int linux_fstat(int fd, struct stat *st)
{
return __real_fstat(fd, st);
}
static int linux_fcntl(int fd, int cmd, int arg)
{
return __real_fcntl(fd, cmd, arg);
}
static int linux_fsync(int fd)
{
return __real_fsync(fd);
}
static int linux_ioctl(int fd, int request, va_list args)
{
return __real_ioctl(fd, request, args);
}
static int linux_unlink(const char *path)
{
return __real_unlink(path+1);
}
static int linux_ftruncate(int fd, off_t length)
{
return __real_ftruncate(fd, length);
}
static const esp_vfs_t linux_vfs = {
.flags = ESP_VFS_FLAG_DEFAULT,
.write = &linux_write,
.open = &linux_open,
.close = &linux_close,
.read = &linux_read,
.pread = &linux_pread,
.pwrite = &linux_pwrite,
.lseek = &linux_lseek,
.fstat = &linux_fstat,
.fcntl = &linux_fcntl,
.fsync = &linux_fsync,
.ioctl = &linux_ioctl,
.unlink = &linux_unlink,
.ftruncate = &linux_ftruncate,
};
void linux_vfs_dev_register(void)
{
ESP_ERROR_CHECK(esp_vfs_register("/linux", &linux_vfs, NULL));
}
void linux_vfs_dev_unregister(void)
{
ESP_ERROR_CHECK(esp_vfs_unregister("/linux"));
}
@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void linux_vfs_dev_register(void);
void linux_vfs_dev_unregister(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,5 @@
CONFIG_IDF_TARGET="linux"
CONFIG_IDF_TARGET_LINUX=y
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
CONFIG_UNITY_ENABLE_FIXTURE=y
+22 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -31,9 +31,11 @@
extern "C" {
#endif
#ifndef CONFIG_IDF_TARGET_LINUX
#ifndef _SYS_TYPES_FD_SET
#error "VFS should be used with FD_SETSIZE and FD_SET from sys/types.h"
#endif
#endif
/**
* Maximum number of (global) file descriptors.
@@ -385,6 +387,25 @@ int esp_vfs_link(struct _reent *r, const char* n1, const char* n2);
int esp_vfs_unlink(struct _reent *r, const char *path);
int esp_vfs_rename(struct _reent *r, const char *src, const char *dst);
int esp_vfs_utime(const char *path, const struct utimbuf *times);
int esp_vfs_fsync(int fd);
int esp_vfs_fcntl_r(struct _reent *r, int fd, int cmd, int arg);
int esp_vfs_ioctl(int fd, int cmd, ...);
/* Directory related functions */
int esp_vfs_stat(struct _reent *r, const char *path, struct stat *st);
int esp_vfs_truncate(const char *path, off_t length);
int esp_vfs_ftruncate(int fd, off_t length);
int esp_vfs_access(const char *path, int amode);
int esp_vfs_utime(const char *path, const struct utimbuf *times);
int esp_vfs_rmdir(const char* name);
int esp_vfs_mkdir(const char* name, mode_t mode);
DIR* esp_vfs_opendir(const char* name);
int esp_vfs_closedir(DIR* pdir);
int esp_vfs_readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
struct dirent* esp_vfs_readdir(DIR* pdir);
long esp_vfs_telldir(DIR* pdir);
void esp_vfs_seekdir(DIR* pdir, long loc);
void esp_vfs_rewinddir(DIR* pdir);
/**@}*/
/**
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -27,9 +27,11 @@
extern "C" {
#endif
#ifndef CONFIG_IDF_TARGET_LINUX
#ifndef _SYS_TYPES_FD_SET
#error "VFS should be used with FD_SETSIZE and FD_SET from sys/types.h"
#endif
#endif
/*
* @brief VFS identificator used for esp_vfs_register_with_id()
+64
View File
@@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
/**
* This header file provides POSIX-compatible definitions of directory access data types.
* The standard dirent.h cannot be used directly because we have a custom version defined in newlib component,
* which is used by VFS. Accessing the VFS index (definition of struct DIR) requires this custom dirent.h.
* This file is a copy of dirent.h from newlib.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Opaque directory structure
*/
typedef struct {
uint16_t dd_vfs_idx; /*!< VFS index, not to be used by applications */
uint16_t dd_rsv; /*!< field reserved for future extension */
/* remaining fields are defined by VFS implementation */
} DIR;
/**
* @brief Directory entry structure
*/
struct dirent {
ino_t d_ino; /*!< file number */
uint8_t d_type; /*!< not defined in POSIX, but present in BSD and Linux */
#define DT_UNKNOWN 0
#define DT_REG 1
#define DT_DIR 2
#if __BSD_VISIBLE
#define MAXNAMLEN 255
char d_name[MAXNAMLEN + 1]; /*!< zero-terminated file name */
#else
char d_name[256];
#endif
};
DIR* opendir(const char* name);
struct dirent* readdir(DIR* pdir);
long telldir(DIR* pdir);
void seekdir(DIR* pdir, long loc);
void rewinddir(DIR* pdir);
int closedir(DIR* pdir);
int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
int scandir(const char *dirname, struct dirent ***out_dirlist,
int (*select_func)(const struct dirent *),
int (*cmp_func)(const struct dirent **, const struct dirent **));
int alphasort(const struct dirent **d1, const struct dirent **d2);
#ifdef __cplusplus
}
#endif
+31
View File
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_PLATFORM_ERRNO_H_
#define _ESP_PLATFORM_ERRNO_H_
#include_next "errno.h"
//
// Possibly define some missing errors
//
#ifndef ESHUTDOWN
#define ESHUTDOWN 110 /* Cannot send after transport endpoint shutdown */
#endif
#ifndef EAI_SOCKTYPE
#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
#endif
#ifndef EAI_AGAIN
#define EAI_AGAIN 2 /* temporary failure in name resolution */
#endif
#ifndef EAI_BADFLAGS
#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
#endif
#endif // _ESP_PLATFORM_ERRNO_H_
+16
View File
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
// reent struct is not used for Linux platform. It's defined in Newlib.
// To make it compatible with vfs.c, following dummy struct and macros are defined.
struct _reent {
int i;
};
#define __errno_r(r) r->i
#define __getreent() NULL
+14 -10
View File
@@ -6,21 +6,15 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/reent.h>
#include <sys/unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include <dirent.h>
#include "inttypes_ext.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_vfs.h"
#include "esp_vfs_private.h"
#include "include/esp_vfs.h"
#include "sdkconfig.h"
// Warn about using deprecated option
#ifdef CONFIG_LWIP_USE_ONLY_LWIP_SELECT
@@ -47,7 +41,11 @@ static const char *TAG = "vfs";
#define LEN_PATH_PREFIX_IGNORED SIZE_MAX /* special length value for VFS which is never recognised by open() */
#define FD_TABLE_ENTRY_UNUSED (fd_table_t) { .permanent = false, .has_pending_close = false, .has_pending_select = false, .vfs_index = -1, .local_fd = -1 }
#ifdef CONFIG_IDF_TARGET_LINUX
typedef uint16_t local_fd_t;
#else
typedef uint8_t local_fd_t;
#endif
_Static_assert((1 << (sizeof(local_fd_t)*8)) >= MAX_FDS, "file descriptor type too small");
typedef int8_t vfs_index_t;
@@ -547,7 +545,7 @@ esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ct
esp_err_t esp_vfs_register_fd_range(const esp_vfs_t *vfs, void *ctx, int min_fd, int max_fd)
{
if (min_fd < 0 || max_fd < 0 || min_fd > MAX_FDS || max_fd > MAX_FDS || min_fd > max_fd) {
ESP_LOGD(TAG, "Invalid arguments: esp_vfs_register_fd_range(0x%x, 0x%x, %d, %d)", (int) vfs, (int) ctx, min_fd, max_fd);
ESP_LOGD(TAG, "Invalid arguments: esp_vfs_register_fd_range(0x%p, 0x%p, %d, %d)", vfs, ctx, min_fd, max_fd);
return ESP_ERR_INVALID_ARG;
}
@@ -623,7 +621,9 @@ esp_err_t esp_vfs_unregister_with_id(esp_vfs_id_t vfs_id)
}
#ifndef CONFIG_IDF_TARGET_LINUX
esp_err_t esp_vfs_unregister_fs_with_id(esp_vfs_id_t vfs_id) __attribute__((alias("esp_vfs_unregister_with_id")));
#endif
esp_err_t esp_vfs_unregister(const char* base_path)
{
@@ -641,7 +641,9 @@ esp_err_t esp_vfs_unregister(const char* base_path)
return ESP_ERR_INVALID_STATE;
}
#ifndef CONFIG_IDF_TARGET_LINUX
esp_err_t esp_vfs_unregister_fs(const char* base_path) __attribute__((alias("esp_vfs_unregister")));
#endif
esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd)
{
@@ -730,7 +732,7 @@ void esp_vfs_dump_registered_paths(FILE *fp)
for (size_t i = 0; i < VFS_MAX_COUNT; ++i) {
fprintf(
fp,
"%d:%s -> %p\n",
"%" PRIuSIZE ": %s -> %p\n",
i,
s_vfs[i] ? s_vfs[i]->path_prefix : "NULL",
s_vfs[i] ? s_vfs[i]->vfs : NULL
@@ -1587,7 +1589,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds
// call start_select for all non-socket VFSs with has at least one FD set in readfds, writefds, or errorfds
// note: it can point to socket VFS but item->isset will be false for that
ESP_LOGD(TAG, "calling start_select for VFS ID %d with the following local FDs", i);
ESP_LOGD(TAG, "calling start_select for VFS ID % " PRIuSIZE " with the following local FDs", i);
esp_vfs_log_fd_set("readfds", &item->readfds);
esp_vfs_log_fd_set("writefds", &item->writefds);
esp_vfs_log_fd_set("errorfds", &item->errorfds);
@@ -1833,6 +1835,7 @@ int tcsendbreak(int fd, int duration)
#endif // CONFIG_VFS_SUPPORT_TERMIOS
#ifndef CONFIG_IDF_TARGET_LINUX
/* Create aliases for libc syscalls
These functions are also available in ROM as stubs which use the syscall table, but linking them
@@ -1905,6 +1908,7 @@ void seekdir(DIR* pdir, long loc)
void rewinddir(DIR* pdir)
__attribute__((alias("esp_vfs_rewinddir")));
#endif // CONFIG_VFS_SUPPORT_DIR
#endif //CONFIG_IDF_TARGET_LINUX
void vfs_include_syscalls_impl(void)
{
+189
View File
@@ -0,0 +1,189 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Linux target VFS syscall wrappers
*
* This file provides POSIX syscall wrappers that redirect to ESP-IDF VFS functions
* when building for Linux target.
*/
#include <stdlib.h>
#include <string.h>
#include "esp_vfs.h"
int open(const char * path, int flags, ...)
{
struct _reent r;
va_list list;
va_start(list, flags);
int mode = va_arg(list, int);
va_end(list);
return esp_vfs_open(&r, path, flags, mode);
}
int close(int fd)
{
struct _reent r;
return esp_vfs_close(&r, fd);
}
ssize_t read(int fd, void * dst, size_t size)
{
struct _reent r;
return esp_vfs_read(&r, fd, dst, size);
}
ssize_t write(int fd, const void * data, size_t size)
{
struct _reent r;
return esp_vfs_write(&r, fd, data, size);
}
off_t lseek(int fd, off_t size, int mode)
{
struct _reent r;
return esp_vfs_lseek(&r, fd, size, mode);
}
ssize_t pread(int fd, void *dst, size_t size, off_t offset)
{
return esp_vfs_pread(fd,dst, size, offset);
}
ssize_t pwrite(int fd, const void *src, size_t size, off_t offset)
{
return esp_vfs_pwrite(fd, src,size, offset);
}
int fstat(int fd, struct stat *st)
{
struct _reent r;
return esp_vfs_fstat(&r, fd, st);
}
int fcntl(int fd, int cmd, ...)
{
struct _reent r;
va_list list;
va_start(list, cmd);
int args = va_arg(list, int);
va_end(list);
return esp_vfs_fcntl_r(&r, fd, cmd, args);
}
int ioctl(int fd, unsigned long cmd, ...)
{
va_list args;
va_start(args, cmd);
int ret = esp_vfs_ioctl(fd, cmd, args);
va_end(args);
return ret;
}
int fsync(int fd)
{
return esp_vfs_fsync(fd);
}
#ifdef CONFIG_VFS_SUPPORT_SELECT
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
{
return esp_vfs_select(nfds, readfds, writefds, errorfds, timeout);
}
#endif // CONFIG_VFS_SUPPORT_SELECT
#ifdef CONFIG_VFS_SUPPORT_DIR
int stat(const char * path, struct stat * st)
{
struct _reent r;
return esp_vfs_stat(&r, path, st);
}
int link(const char* n1, const char* n2)
{
struct _reent r;
return esp_vfs_link(&r, n1, n2);
}
int unlink(const char *path)
{
struct _reent r;
return esp_vfs_unlink(&r, path);
}
int rename(const char *src, const char *dst)
{
struct _reent r;
return esp_vfs_rename(&r, src, dst);
}
int truncate(const char *path, off_t length)
{
return esp_vfs_truncate(path, length);
}
int ftruncate(int fd, off_t length)
{
return esp_vfs_ftruncate(fd, length);
}
int access(const char *path, int amode)
{
return esp_vfs_access(path, amode);
}
int utime(const char *path, const struct utimbuf *times)
{
return esp_vfs_utime(path, times);
}
int rmdir(const char* name)
{
return esp_vfs_rmdir(name);
}
int mkdir(const char* name, mode_t mode)
{
return esp_vfs_mkdir(name, mode);
}
DIR* opendir(const char* name)
{
return esp_vfs_opendir(name);
}
int closedir(DIR* pdir)
{
return esp_vfs_closedir(pdir);
}
int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent)
{
return esp_vfs_readdir_r(pdir, entry, out_dirent);
}
struct dirent* readdir(DIR* pdir)
{
return esp_vfs_readdir(pdir);
}
long telldir(DIR* pdir)
{
return esp_vfs_telldir(pdir);
}
void seekdir(DIR* pdir, long loc)
{
return esp_vfs_seekdir(pdir, loc);
}
void rewinddir(DIR* pdir)
{
return esp_vfs_rewinddir(pdir);
}
#endif // CONFIG_VFS_SUPPORT_DIR