1 // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef __ESP_VFS_H__ 16 #define __ESP_VFS_H__ 17 18 #include <stdint.h> 19 #include <stddef.h> 20 #include <stdarg.h> 21 #include <unistd.h> 22 #include <utime.h> 23 #include "freertos/FreeRTOS.h" 24 #include "freertos/semphr.h" 25 #include "esp_err.h" 26 #include <sys/types.h> 27 #include <sys/reent.h> 28 #include <sys/stat.h> 29 #include <sys/time.h> 30 #include <sys/termios.h> 31 #include <sys/poll.h> 32 #include <sys/dirent.h> 33 #include <string.h> 34 #include "sdkconfig.h" 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 #ifndef _SYS_TYPES_FD_SET 41 #error "VFS should be used with FD_SETSIZE and FD_SET from sys/types.h" 42 #endif 43 44 /** 45 * Maximum number of (global) file descriptors. 46 */ 47 #define MAX_FDS FD_SETSIZE /* for compatibility with fd_set and select() */ 48 49 /** 50 * Maximum length of path prefix (not including zero terminator) 51 */ 52 #define ESP_VFS_PATH_MAX 15 53 54 /** 55 * Default value of flags member in esp_vfs_t structure. 56 */ 57 #define ESP_VFS_FLAG_DEFAULT 0 58 59 /** 60 * Flag which indicates that FS needs extra context pointer in syscalls. 61 */ 62 #define ESP_VFS_FLAG_CONTEXT_PTR 1 63 64 /* 65 * @brief VFS identificator used for esp_vfs_register_with_id() 66 */ 67 typedef int esp_vfs_id_t; 68 69 /** 70 * @brief VFS semaphore type for select() 71 * 72 */ 73 typedef struct 74 { 75 bool is_sem_local; /*!< type of "sem" is SemaphoreHandle_t when true, defined by socket driver otherwise */ 76 void *sem; /*!< semaphore instance */ 77 } esp_vfs_select_sem_t; 78 79 /** 80 * @brief VFS definition structure 81 * 82 * This structure should be filled with pointers to corresponding 83 * FS driver functions. 84 * 85 * VFS component will translate all FDs so that the filesystem implementation 86 * sees them starting at zero. The caller sees a global FD which is prefixed 87 * with an pre-filesystem-implementation. 88 * 89 * Some FS implementations expect some state (e.g. pointer to some structure) 90 * to be passed in as a first argument. For these implementations, 91 * populate the members of this structure which have _p suffix, set 92 * flags member to ESP_VFS_FLAG_CONTEXT_PTR and provide the context pointer 93 * to esp_vfs_register function. 94 * If the implementation doesn't use this extra argument, populate the 95 * members without _p suffix and set flags member to ESP_VFS_FLAG_DEFAULT. 96 * 97 * If the FS driver doesn't provide some of the functions, set corresponding 98 * members to NULL. 99 */ 100 typedef struct 101 { 102 int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR or ESP_VFS_FLAG_DEFAULT */ 103 union { 104 ssize_t (*write_p)(void* p, int fd, const void * data, size_t size); /*!< Write with context pointer */ 105 ssize_t (*write)(int fd, const void * data, size_t size); /*!< Write without context pointer */ 106 }; 107 union { 108 off_t (*lseek_p)(void* p, int fd, off_t size, int mode); /*!< Seek with context pointer */ 109 off_t (*lseek)(int fd, off_t size, int mode); /*!< Seek without context pointer */ 110 }; 111 union { 112 ssize_t (*read_p)(void* ctx, int fd, void * dst, size_t size); /*!< Read with context pointer */ 113 ssize_t (*read)(int fd, void * dst, size_t size); /*!< Read without context pointer */ 114 }; 115 union { 116 ssize_t (*pread_p)(void *ctx, int fd, void * dst, size_t size, off_t offset); /*!< pread with context pointer */ 117 ssize_t (*pread)(int fd, void * dst, size_t size, off_t offset); /*!< pread without context pointer */ 118 }; 119 union { 120 ssize_t (*pwrite_p)(void *ctx, int fd, const void *src, size_t size, off_t offset); /*!< pwrite with context pointer */ 121 ssize_t (*pwrite)(int fd, const void *src, size_t size, off_t offset); /*!< pwrite without context pointer */ 122 }; 123 union { 124 int (*open_p)(void* ctx, const char * path, int flags, int mode); /*!< open with context pointer */ 125 int (*open)(const char * path, int flags, int mode); /*!< open without context pointer */ 126 }; 127 union { 128 int (*close_p)(void* ctx, int fd); /*!< close with context pointer */ 129 int (*close)(int fd); /*!< close without context pointer */ 130 }; 131 union { 132 int (*fstat_p)(void* ctx, int fd, struct stat * st); /*!< fstat with context pointer */ 133 int (*fstat)(int fd, struct stat * st); /*!< fstat without context pointer */ 134 }; 135 #ifdef CONFIG_VFS_SUPPORT_DIR 136 union { 137 int (*stat_p)(void* ctx, const char * path, struct stat * st); /*!< stat with context pointer */ 138 int (*stat)(const char * path, struct stat * st); /*!< stat without context pointer */ 139 }; 140 union { 141 int (*link_p)(void* ctx, const char* n1, const char* n2); /*!< link with context pointer */ 142 int (*link)(const char* n1, const char* n2); /*!< link without context pointer */ 143 }; 144 union { 145 int (*unlink_p)(void* ctx, const char *path); /*!< unlink with context pointer */ 146 int (*unlink)(const char *path); /*!< unlink without context pointer */ 147 }; 148 union { 149 int (*rename_p)(void* ctx, const char *src, const char *dst); /*!< rename with context pointer */ 150 int (*rename)(const char *src, const char *dst); /*!< rename without context pointer */ 151 }; 152 union { 153 DIR* (*opendir_p)(void* ctx, const char* name); /*!< opendir with context pointer */ 154 DIR* (*opendir)(const char* name); /*!< opendir without context pointer */ 155 }; 156 union { 157 struct dirent* (*readdir_p)(void* ctx, DIR* pdir); /*!< readdir with context pointer */ 158 struct dirent* (*readdir)(DIR* pdir); /*!< readdir without context pointer */ 159 }; 160 union { 161 int (*readdir_r_p)(void* ctx, DIR* pdir, struct dirent* entry, struct dirent** out_dirent); /*!< readdir_r with context pointer */ 162 int (*readdir_r)(DIR* pdir, struct dirent* entry, struct dirent** out_dirent); /*!< readdir_r without context pointer */ 163 }; 164 union { 165 long (*telldir_p)(void* ctx, DIR* pdir); /*!< telldir with context pointer */ 166 long (*telldir)(DIR* pdir); /*!< telldir without context pointer */ 167 }; 168 union { 169 void (*seekdir_p)(void* ctx, DIR* pdir, long offset); /*!< seekdir with context pointer */ 170 void (*seekdir)(DIR* pdir, long offset); /*!< seekdir without context pointer */ 171 }; 172 union { 173 int (*closedir_p)(void* ctx, DIR* pdir); /*!< closedir with context pointer */ 174 int (*closedir)(DIR* pdir); /*!< closedir without context pointer */ 175 }; 176 union { 177 int (*mkdir_p)(void* ctx, const char* name, mode_t mode); /*!< mkdir with context pointer */ 178 int (*mkdir)(const char* name, mode_t mode); /*!< mkdir without context pointer */ 179 }; 180 union { 181 int (*rmdir_p)(void* ctx, const char* name); /*!< rmdir with context pointer */ 182 int (*rmdir)(const char* name); /*!< rmdir without context pointer */ 183 }; 184 #endif // CONFIG_VFS_SUPPORT_DIR 185 union { 186 int (*fcntl_p)(void* ctx, int fd, int cmd, int arg); /*!< fcntl with context pointer */ 187 int (*fcntl)(int fd, int cmd, int arg); /*!< fcntl without context pointer */ 188 }; 189 union { 190 int (*ioctl_p)(void* ctx, int fd, int cmd, va_list args); /*!< ioctl with context pointer */ 191 int (*ioctl)(int fd, int cmd, va_list args); /*!< ioctl without context pointer */ 192 }; 193 union { 194 int (*fsync_p)(void* ctx, int fd); /*!< fsync with context pointer */ 195 int (*fsync)(int fd); /*!< fsync without context pointer */ 196 }; 197 #ifdef CONFIG_VFS_SUPPORT_DIR 198 union { 199 int (*access_p)(void* ctx, const char *path, int amode); /*!< access with context pointer */ 200 int (*access)(const char *path, int amode); /*!< access without context pointer */ 201 }; 202 union { 203 int (*truncate_p)(void* ctx, const char *path, off_t length); /*!< truncate with context pointer */ 204 int (*truncate)(const char *path, off_t length); /*!< truncate without context pointer */ 205 }; 206 union { 207 int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times); /*!< utime with context pointer */ 208 int (*utime)(const char *path, const struct utimbuf *times); /*!< utime without context pointer */ 209 }; 210 #endif // CONFIG_VFS_SUPPORT_DIR 211 #ifdef CONFIG_VFS_SUPPORT_TERMIOS 212 union { 213 int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p); /*!< tcsetattr with context pointer */ 214 int (*tcsetattr)(int fd, int optional_actions, const struct termios *p); /*!< tcsetattr without context pointer */ 215 }; 216 union { 217 int (*tcgetattr_p)(void *ctx, int fd, struct termios *p); /*!< tcgetattr with context pointer */ 218 int (*tcgetattr)(int fd, struct termios *p); /*!< tcgetattr without context pointer */ 219 }; 220 union { 221 int (*tcdrain_p)(void *ctx, int fd); /*!< tcdrain with context pointer */ 222 int (*tcdrain)(int fd); /*!< tcdrain without context pointer */ 223 }; 224 union { 225 int (*tcflush_p)(void *ctx, int fd, int select); /*!< tcflush with context pointer */ 226 int (*tcflush)(int fd, int select); /*!< tcflush without context pointer */ 227 }; 228 union { 229 int (*tcflow_p)(void *ctx, int fd, int action); /*!< tcflow with context pointer */ 230 int (*tcflow)(int fd, int action); /*!< tcflow without context pointer */ 231 }; 232 union { 233 pid_t (*tcgetsid_p)(void *ctx, int fd); /*!< tcgetsid with context pointer */ 234 pid_t (*tcgetsid)(int fd); /*!< tcgetsid without context pointer */ 235 }; 236 union { 237 int (*tcsendbreak_p)(void *ctx, int fd, int duration); /*!< tcsendbreak with context pointer */ 238 int (*tcsendbreak)(int fd, int duration); /*!< tcsendbreak without context pointer */ 239 }; 240 #endif // CONFIG_VFS_SUPPORT_TERMIOS 241 #ifdef CONFIG_VFS_SUPPORT_SELECT 242 /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ 243 esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); 244 /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */ 245 int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); 246 /** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */ 247 void (*stop_socket_select)(void *sem); 248 /** stop_socket_select which can be called from ISR; set only for the socket driver */ 249 void (*stop_socket_select_isr)(void *sem, BaseType_t *woken); 250 /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ 251 void* (*get_socket_select_semaphore)(void); 252 /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ 253 esp_err_t (*end_select)(void *end_select_args); 254 #endif // CONFIG_VFS_SUPPORT_SELECT 255 } esp_vfs_t; 256 257 258 /** 259 * Register a virtual filesystem for given path prefix. 260 * 261 * @param base_path file path prefix associated with the filesystem. 262 * Must be a zero-terminated C string, may be empty. 263 * If not empty, must be up to ESP_VFS_PATH_MAX 264 * characters long, and at least 2 characters long. 265 * Name must start with a "/" and must not end with "/". 266 * For example, "/data" or "/dev/spi" are valid. 267 * These VFSes would then be called to handle file paths such as 268 * "/data/myfile.txt" or "/dev/spi/0". 269 * In the special case of an empty base_path, a "fallback" 270 * VFS is registered. Such VFS will handle paths which are not 271 * matched by any other registered VFS. 272 * @param vfs Pointer to esp_vfs_t, a structure which maps syscalls to 273 * the filesystem driver functions. VFS component doesn't 274 * assume ownership of this pointer. 275 * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer 276 * which should be passed to VFS functions. Otherwise, NULL. 277 * 278 * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are 279 * registered. 280 */ 281 esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ctx); 282 283 284 /** 285 * Special case function for registering a VFS that uses a method other than 286 * open() to open new file descriptors from the interval <min_fd; max_fd). 287 * 288 * This is a special-purpose function intended for registering LWIP sockets to VFS. 289 * 290 * @param vfs Pointer to esp_vfs_t. Meaning is the same as for esp_vfs_register(). 291 * @param ctx Pointer to context structure. Meaning is the same as for esp_vfs_register(). 292 * @param min_fd The smallest file descriptor this VFS will use. 293 * @param max_fd Upper boundary for file descriptors this VFS will use (the biggest file descriptor plus one). 294 * 295 * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are 296 * registered, ESP_ERR_INVALID_ARG if the file descriptor boundaries 297 * are incorrect. 298 */ 299 esp_err_t esp_vfs_register_fd_range(const esp_vfs_t *vfs, void *ctx, int min_fd, int max_fd); 300 301 /** 302 * Special case function for registering a VFS that uses a method other than 303 * open() to open new file descriptors. In comparison with 304 * esp_vfs_register_fd_range, this function doesn't pre-registers an interval 305 * of file descriptors. File descriptors can be registered later, by using 306 * esp_vfs_register_fd. 307 * 308 * @param vfs Pointer to esp_vfs_t. Meaning is the same as for esp_vfs_register(). 309 * @param ctx Pointer to context structure. Meaning is the same as for esp_vfs_register(). 310 * @param vfs_id Here will be written the VFS ID which can be passed to 311 * esp_vfs_register_fd for registering file descriptors. 312 * 313 * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are 314 * registered, ESP_ERR_INVALID_ARG if the file descriptor boundaries 315 * are incorrect. 316 */ 317 esp_err_t esp_vfs_register_with_id(const esp_vfs_t *vfs, void *ctx, esp_vfs_id_t *vfs_id); 318 319 /** 320 * Unregister a virtual filesystem for given path prefix 321 * 322 * @param base_path file prefix previously used in esp_vfs_register call 323 * @return ESP_OK if successful, ESP_ERR_INVALID_STATE if VFS for given prefix 324 * hasn't been registered 325 */ 326 esp_err_t esp_vfs_unregister(const char* base_path); 327 328 /** 329 * Special function for registering another file descriptor for a VFS registered 330 * by esp_vfs_register_with_id. 331 * 332 * @param vfs_id VFS identificator returned by esp_vfs_register_with_id. 333 * @param fd The registered file descriptor will be written to this address. 334 * 335 * @return ESP_OK if the registration is successful, 336 * ESP_ERR_NO_MEM if too many file descriptors are registered, 337 * ESP_ERR_INVALID_ARG if the arguments are incorrect. 338 */ 339 esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd); 340 341 /** 342 * Special function for unregistering a file descriptor belonging to a VFS 343 * registered by esp_vfs_register_with_id. 344 * 345 * @param vfs_id VFS identificator returned by esp_vfs_register_with_id. 346 * @param fd File descriptor which should be unregistered. 347 * 348 * @return ESP_OK if the registration is successful, 349 * ESP_ERR_INVALID_ARG if the arguments are incorrect. 350 */ 351 esp_err_t esp_vfs_unregister_fd(esp_vfs_id_t vfs_id, int fd); 352 353 /** 354 * These functions are to be used in newlib syscall table. They will be called by 355 * newlib when it needs to use any of the syscalls. 356 */ 357 /**@{*/ 358 ssize_t esp_vfs_write(struct _reent *r, int fd, const void * data, size_t size); 359 off_t esp_vfs_lseek(struct _reent *r, int fd, off_t size, int mode); 360 ssize_t esp_vfs_read(struct _reent *r, int fd, void * dst, size_t size); 361 int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode); 362 int esp_vfs_close(struct _reent *r, int fd); 363 int esp_vfs_fstat(struct _reent *r, int fd, struct stat * st); 364 int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st); 365 int esp_vfs_link(struct _reent *r, const char* n1, const char* n2); 366 int esp_vfs_unlink(struct _reent *r, const char *path); 367 int esp_vfs_rename(struct _reent *r, const char *src, const char *dst); 368 int esp_vfs_utime(const char *path, const struct utimbuf *times); 369 /**@}*/ 370 371 /** 372 * @brief Synchronous I/O multiplexing which implements the functionality of POSIX select() for VFS 373 * @param nfds Specifies the range of descriptors which should be checked. 374 * The first nfds descriptors will be checked in each set. 375 * @param readfds If not NULL, then points to a descriptor set that on input 376 * specifies which descriptors should be checked for being 377 * ready to read, and on output indicates which descriptors 378 * are ready to read. 379 * @param writefds If not NULL, then points to a descriptor set that on input 380 * specifies which descriptors should be checked for being 381 * ready to write, and on output indicates which descriptors 382 * are ready to write. 383 * @param errorfds If not NULL, then points to a descriptor set that on input 384 * specifies which descriptors should be checked for error 385 * conditions, and on output indicates which descriptors 386 * have error conditions. 387 * @param timeout If not NULL, then points to timeval structure which 388 * specifies the time period after which the functions should 389 * time-out and return. If it is NULL, then the function will 390 * not time-out. 391 * 392 * @return The number of descriptors set in the descriptor sets, or -1 393 * when an error (specified by errno) have occurred. 394 */ 395 int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); 396 397 /** 398 * @brief Notification from a VFS driver about a read/write/error condition 399 * 400 * This function is called when the VFS driver detects a read/write/error 401 * condition as it was requested by the previous call to start_select. 402 * 403 * @param sem semaphore structure which was passed to the driver by the start_select call 404 */ 405 void esp_vfs_select_triggered(esp_vfs_select_sem_t sem); 406 407 /** 408 * @brief Notification from a VFS driver about a read/write/error condition (ISR version) 409 * 410 * This function is called when the VFS driver detects a read/write/error 411 * condition as it was requested by the previous call to start_select. 412 * 413 * @param sem semaphore structure which was passed to the driver by the start_select call 414 * @param woken is set to pdTRUE if the function wakes up a task with higher priority 415 */ 416 void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken); 417 418 /** 419 * 420 * @brief Implements the VFS layer of POSIX pread() 421 * 422 * @param fd File descriptor used for read 423 * @param dst Pointer to the buffer where the output will be written 424 * @param size Number of bytes to be read 425 * @param offset Starting offset of the read 426 * 427 * @return A positive return value indicates the number of bytes read. -1 is return on failure and errno is 428 * set accordingly. 429 */ 430 ssize_t esp_vfs_pread(int fd, void *dst, size_t size, off_t offset); 431 432 /** 433 * 434 * @brief Implements the VFS layer of POSIX pwrite() 435 * 436 * @param fd File descriptor used for write 437 * @param src Pointer to the buffer from where the output will be read 438 * @param size Number of bytes to write 439 * @param offset Starting offset of the write 440 * 441 * @return A positive return value indicates the number of bytes written. -1 is return on failure and errno is 442 * set accordingly. 443 */ 444 ssize_t esp_vfs_pwrite(int fd, const void *src, size_t size, off_t offset); 445 446 #ifdef __cplusplus 447 } // extern "C" 448 #endif 449 450 #endif //__ESP_VFS_H__ 451