XFusion API v1.3.0
载入中...
搜索中...
未找到
xf_vfs.c
浏览该文件的文档.
1
9/*
10 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 */
14
27/* ==================== [Includes] ========================================== */
28
29#include "xf_vfs.h"
30#include "xf_vfs_private.h"
31
32/* ==================== [Defines] =========================================== */
33
34#define FD_TABLE_ENTRY_UNUSED (fd_table_t) { .permanent = false, .has_pending_close = false, .has_pending_select = false, .vfs_index = -1, .local_fd = -1 }
35
36#if !defined(STATIC_ASSERT)
37# define STATIC_ASSERT(EXPR, ...) extern char (*_do_assert(void)) [sizeof(char[1 - 2*!(EXPR)])]
38#endif
39
40#define _lock_acquire(lock) xf_lock_lock(lock)
41#define _lock_release(lock) xf_lock_unlock(lock)
42
43#if !defined(xf_strncpy)
44# define xf_strncpy(dst, src, len) strncpy((dst), (src), (len))
45#endif
46
47/* ==================== [Typedefs] ========================================== */
48
49#if ((1 << (1 /* byte */ * 8)) >= XF_VFS_FDS_MAX)
50# define _LOCAL_FD_T_ uint8_t
51#else
52# define _LOCAL_FD_T_ uint16_t
53#endif
54
56STATIC_ASSERT((1 << (sizeof(local_fd_t) * 8)) >= XF_VFS_FDS_MAX, "file descriptor type too small");
57
58typedef int8_t vfs_index_t;
59STATIC_ASSERT((1 << (sizeof(vfs_index_t) * 8)) >= XF_VFS_MAX_COUNT, "VFS index type too small");
60STATIC_ASSERT(((vfs_index_t) -1) < 0, "vfs_index_t must be a signed type");
61
70
71typedef struct {
72 bool isset; // none or at least one bit is set in the following 3 fd sets
77
78typedef struct {
79#if XF_VFS_SUPPORT_DIR_IS_ENABLE
81#endif
82#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
84#endif
86
87/* ==================== [Static Prototypes] ================================= */
88
90static void xf_vfs_free_fs_ops(xf_vfs_fs_ops_t *vfs);
91static void xf_vfs_free_entry(xf_vfs_entry_t *entry);
92static xf_vfs_fs_ops_t *xf_minify_vfs(const xf_vfs_t *const vfs, vfs_component_proxy_t proxy);
95static xf_err_t xf_vfs_make_fs_ops(const xf_vfs_t *vfs, xf_vfs_fs_ops_t **min);
97 const char *base_path, size_t len, const xf_vfs_fs_ops_t *vfs, int flags, void *ctx, int *vfs_index);
98static inline bool fd_valid(int fd);
99static const xf_vfs_entry_t *get_vfs_for_fd(int fd);
100static inline int get_local_fd(const xf_vfs_entry_t *vfs, int fd);
101static const char *translate_path(const xf_vfs_entry_t *vfs, const char *src_path);
102
103/* ==================== [Static Variables] ================================== */
104
105static const char *const TAG = "xf_vfs";
106
108static size_t s_vfs_count = 0;
109
112
113/* ==================== [Macros] ============================================ */
114
115/* ==================== [Global Functions] ================================== */
116
117xf_err_t xf_vfs_register_fs(const char *base_path, const xf_vfs_fs_ops_t *vfs, int flags, void *ctx)
118{
119 if (s_fd_table_lock == NULL) {
121 }
122
123 if (vfs == NULL) {
124 XF_LOGE(TAG, "VFS is NULL");
125 return XF_ERR_INVALID_ARG;
126 }
127
128 if ((flags & XF_VFS_FLAG_STATIC)) {
129 return xf_vfs_register_fs_common(base_path, xf_strlen(base_path), vfs, flags, ctx, NULL);
130 }
131
133 if (_vfs == NULL) {
134 return XF_ERR_NO_MEM;
135 }
136
137 xf_err_t ret = xf_vfs_register_fs_common(base_path, xf_strlen(base_path), _vfs, flags, ctx, NULL);
138 if (ret != XF_OK) {
139 xf_vfs_free_fs_ops(_vfs);
140 return ret;
141 }
142
143 return XF_OK;
144}
145
146xf_err_t xf_vfs_register_common(const char *base_path, size_t len, const xf_vfs_t *vfs, void *ctx, int *vfs_index)
147{
148 if (s_fd_table_lock == NULL) {
150 }
151
152 if (vfs == NULL) {
153 XF_LOGE(TAG, "VFS is NULL");
154 return XF_ERR_INVALID_ARG;
155 }
156
157 if (vfs->flags & XF_VFS_FLAG_STATIC) {
158 XF_LOGE(TAG, "XF_VFS_FLAG_STATIC is not supported for xf_vfs_t, use xf_vfs_register_fs instead");
159 return XF_ERR_INVALID_ARG;
160 }
161
162 xf_vfs_fs_ops_t *_vfs = NULL;
163 xf_err_t ret = xf_vfs_make_fs_ops(vfs, &_vfs);
164 if (ret != XF_OK) {
165 return ret;
166 }
167
168 ret = xf_vfs_register_fs_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index);
169 if (ret != XF_OK) {
170 xf_vfs_free_fs_ops(_vfs);
171 return ret;
172 }
173
174 return XF_OK;
175}
176
177xf_err_t xf_vfs_register(const char *base_path, const xf_vfs_t *vfs, void *ctx)
178{
179 return xf_vfs_register_common(base_path, xf_strlen(base_path), vfs, ctx, NULL);
180}
181
182xf_err_t xf_vfs_register_fd_range(const xf_vfs_t *vfs, void *ctx, int min_fd, int max_fd)
183{
184 if (min_fd < 0 || max_fd < 0 || min_fd > XF_VFS_FDS_MAX || max_fd > XF_VFS_FDS_MAX || min_fd > max_fd) {
185 XF_LOGD(TAG, "Invalid arguments: xf_vfs_register_fd_range(0x%x, 0x%x, %d, %d)", (int)(uintptr_t)vfs,
186 (int)(uintptr_t)ctx, min_fd, max_fd);
187 return XF_ERR_INVALID_ARG;
188 }
189
190 int index = 0;
192
193 if (ret == XF_OK) {
195 for (int i = min_fd; i < max_fd; ++i) {
196 if (s_fd_table[i].vfs_index != -1) {
197 xf_free(s_vfs[index]);
198 s_vfs[index] = NULL;
199 for (int j = min_fd; j < i; ++j) {
200 if (s_fd_table[j].vfs_index == index) {
202 }
203 }
205 XF_LOGD(TAG, "xf_vfs_register_fd_range cannot set fd %d (used by other VFS)", i);
206 return XF_ERR_INVALID_ARG;
207 }
208 s_fd_table[i].permanent = true;
209 s_fd_table[i].vfs_index = index;
210 s_fd_table[i].local_fd = i;
211 }
213
214 XF_LOGW(TAG, "xf_vfs_register_fd_range is successful for range <%d; %d) and VFS ID %d", min_fd, max_fd, index);
215 }
216
217 return ret;
218}
219
221{
222 if (vfs_id == NULL) {
223 return XF_ERR_INVALID_ARG;
224 }
225
226 *vfs_id = -1;
227 return xf_vfs_register_fs_common("", XF_VFS_PATH_PREFIX_LEN_IGNORED, vfs, flags, ctx, vfs_id);
228}
229
231{
232 if (vfs_id == NULL) {
233 return XF_ERR_INVALID_ARG;
234 }
235
236 *vfs_id = -1;
238}
239
241{
242 if (vfs_id < 0 || vfs_id >= XF_VFS_MAX_COUNT || s_vfs[vfs_id] == NULL) {
243 return XF_ERR_INVALID_ARG;
244 }
245 xf_vfs_entry_t *vfs = s_vfs[vfs_id];
247 s_vfs[vfs_id] = NULL;
248
250 // Delete all references from the FD lookup-table
251 for (int j = 0; j < XF_VFS_MAX_COUNT; ++j) {
252 if (s_fd_table[j].vfs_index == vfs_id) {
254 }
255 }
257
258 return XF_OK;
259
260}
261
266
267xf_err_t xf_vfs_unregister(const char *base_path)
268{
269 const size_t base_path_len = xf_strlen(base_path);
270 for (size_t i = 0; i < s_vfs_count; ++i) {
271 xf_vfs_entry_t *vfs = s_vfs[i];
272 if (vfs == NULL) {
273 continue;
274 }
275 if (base_path_len == vfs->path_prefix_len &&
276 xf_memcmp(base_path, vfs->path_prefix, vfs->path_prefix_len) == 0) {
278 }
279 }
281}
282
283xf_err_t xf_vfs_unregister_fs(const char *base_path)
284{
285 return xf_vfs_unregister(base_path);
286}
287
289{
290 return xf_vfs_register_fd_with_local_fd(vfs_id, -1, true, fd);
291}
292
293xf_err_t xf_vfs_register_fd_with_local_fd(xf_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd)
294{
295 if (vfs_id < 0 || vfs_id >= s_vfs_count || fd == NULL) {
296 XF_LOGD(TAG, "Invalid arguments for xf_vfs_register_fd_with_local_fd(%d, %d, %d, 0x%p)",
297 vfs_id, local_fd, permanent, fd);
298 return XF_ERR_INVALID_ARG;
299 }
300
303 for (int i = 0; i < XF_VFS_FDS_MAX; ++i) {
304 if (s_fd_table[i].vfs_index == -1) {
305 s_fd_table[i].permanent = permanent;
306 s_fd_table[i].vfs_index = vfs_id;
307 if (local_fd >= 0) {
308 s_fd_table[i].local_fd = local_fd;
309 } else {
310 s_fd_table[i].local_fd = i;
311 }
312 *fd = i;
313 ret = XF_OK;
314 break;
315 }
316 }
318
319 XF_LOGD(TAG, "xf_vfs_register_fd_with_local_fd(%d, %d, %d, 0x%p) finished with %s",
320 vfs_id, local_fd, permanent, fd, xf_err_to_name(ret));
321
322 return ret;
323}
324
326{
328
329 if (vfs_id < 0 || vfs_id >= s_vfs_count || fd < 0 || fd >= XF_VFS_FDS_MAX) {
330 XF_LOGD(TAG, "Invalid arguments for xf_vfs_unregister_fd(%d, %d)", vfs_id, fd);
331 return ret;
332 }
333
335 fd_table_t *item = s_fd_table + fd;
336 if (item->permanent == true && item->vfs_index == vfs_id && item->local_fd == fd) {
337 *item = FD_TABLE_ENTRY_UNUSED;
338 ret = XF_OK;
339 }
341
342 XF_LOGD(TAG, "xf_vfs_unregister_fd(%d, %d) finished with %s", vfs_id, fd, xf_err_to_name(ret));
343
344 return ret;
345}
346
348{
349 const xf_vfs_entry_t *vfs;
350 xf_log_printf("------------------------------------------------------\n");
351 xf_log_printf("<VFS Path Prefix>-<FD seen by App>-<FD seen by driver>\n");
352 xf_log_printf("------------------------------------------------------\n");
354 for (int index = 0; index < XF_VFS_FDS_MAX; index++) {
355 if (s_fd_table[index].vfs_index != -1) {
356 vfs = s_vfs[s_fd_table[index].vfs_index];
357 if (xf_strcmp(vfs->path_prefix, "")) {
358 xf_log_printf("(%s) - 0x%x - 0x%x\n", vfs->path_prefix, index, s_fd_table[index].local_fd);
359 } else {
360 xf_log_printf("(socket) - 0x%x - 0x%x\n", index, s_fd_table[index].local_fd);
361 }
362 }
363 }
365}
366
368{
369 xf_log_printf("------------------------------------------------------\n");
370 xf_log_printf("<index>:<VFS Path Prefix> -> <VFS entry ptr>\n");
371 xf_log_printf("------------------------------------------------------\n");
372 for (int i = 0; i < XF_VFS_MAX_COUNT; ++i) {
374 "%d:%s -> %p\n",
375 (int)i,
376 s_vfs[i] ? s_vfs[i]->path_prefix : "NULL",
377 s_vfs[i] ? s_vfs[i]->vfs : NULL
378 );
379 }
380}
381
382/*
383 * Set XF_VFS_FLAG_READONLY_FS read-only flag for a registered virtual filesystem
384 * for given path prefix. Should be only called from the xf_vfs_*filesystem* register
385 * or helper mount functions where vfs_t is not available to set the read-only
386 * flag directly (e.g. xf_vfs_fat_spiflash_mount_rw_wl).
387 */
388xf_err_t xf_vfs_set_readonly_flag(const char *base_path)
389{
390 const size_t base_path_len = xf_strlen(base_path);
391 for (size_t i = 0; i < s_vfs_count; ++i) {
392 xf_vfs_entry_t *vfs = s_vfs[i];
393 if (vfs == NULL) {
394 continue;
395 }
396 if (base_path_len == vfs->path_prefix_len &&
397 xf_memcmp(base_path, vfs->path_prefix, vfs->path_prefix_len) == 0) {
399 return XF_OK;
400 }
401 }
403}
404
406{
407 if (index < 0 || index >= s_vfs_count) {
408 return NULL;
409 } else {
410 return s_vfs[index];
411 }
412}
413
415{
416 const xf_vfs_entry_t *best_match = NULL;
417 xf_vfs_ssize_t best_match_prefix_len = -1;
418 size_t len = xf_strlen(path);
419 for (size_t i = 0; i < s_vfs_count; ++i) {
420 const xf_vfs_entry_t *vfs = s_vfs[i];
421 if (vfs == NULL || vfs->path_prefix_len == XF_VFS_PATH_PREFIX_LEN_IGNORED) {
422 continue;
423 }
424 // match path prefix
425 if (len < vfs->path_prefix_len ||
426 xf_memcmp(path, vfs->path_prefix, vfs->path_prefix_len) != 0) {
427 continue;
428 }
429 // this is the default VFS and we don't have a better match yet.
430 if (vfs->path_prefix_len == 0 && !best_match) {
431 best_match = vfs;
432 continue;
433 }
434 // if path is not equal to the prefix, expect to see a path separator
435 // i.e. don't match "/data" prefix for "/data1/foo.txt" path
436 if (len > vfs->path_prefix_len &&
437 path[vfs->path_prefix_len] != '/') {
438 continue;
439 }
440 // Out of all matching path prefixes, select the longest one;
441 // i.e. if "/dev" and "/dev/uart" both match, for "/dev/uart/1" path,
442 // choose "/dev/uart",
443 // This causes all s_vfs_count VFS entries to be scanned when opening
444 // a file by name. This can be optimized by introducing a table for
445 // FS search order, sorted so that longer prefixes are checked first.
446 if (best_match_prefix_len < (xf_vfs_ssize_t) vfs->path_prefix_len) {
447 best_match_prefix_len = (xf_vfs_ssize_t) vfs->path_prefix_len;
448 best_match = vfs;
449 }
450 }
451 return best_match;
452}
453
454/*
455 * Using huge multi-line macros is never nice, but in this case
456 * the only alternative is to repeat this chunk of code (with different function names)
457 * for each syscall being implemented. Given that this define is contained within a single
458 * file, this looks like a good tradeoff.
459 *
460 * First we check if syscall is implemented by VFS (corresponding member is not NULL),
461 * then call the right flavor of the method (e.g. open or open_p) depending on
462 * XF_VFS_FLAG_CONTEXT_PTR flag. If XF_VFS_FLAG_CONTEXT_PTR is set, context is passed
463 * in as first argument and _p variant is used for the call.
464 * It is enough to check just one of them for NULL, as both variants are part of a union.
465 */
466#define CHECK_AND_CALL(ret, r, pvfs, func, ...) \
467 if (pvfs->vfs->func == NULL) { \
468 errno = ENOSYS; \
469 return -1; \
470 } \
471 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
472 ret = (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \
473 } else { \
474 ret = (*pvfs->vfs->func)(__VA_ARGS__); \
475 }
476
477#define CHECK_AND_CALL_SUBCOMPONENT(ret, r, pvfs, component, func, ...) \
478 if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \
479 errno = ENOSYS; \
480 return -1; \
481 } \
482 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
483 ret = (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \
484 } else { \
485 ret = (*pvfs->vfs->component->func)(__VA_ARGS__); \
486 }
487
488#define CHECK_AND_CALLV(r, pvfs, func, ...) \
489 if (pvfs->vfs->func == NULL) { \
490 errno = ENOSYS; \
491 return; \
492 } \
493 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
494 (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \
495 } else { \
496 (*pvfs->vfs->func)(__VA_ARGS__); \
497 }
498
499#define CHECK_AND_CALL_SUBCOMPONENTV(r, pvfs, component, func, ...) \
500 if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \
501 errno = ENOSYS; \
502 return; \
503 } \
504 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
505 (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \
506 } else { \
507 (*pvfs->vfs->component->func)(__VA_ARGS__); \
508 }
509
510#define CHECK_AND_CALLP(ret, r, pvfs, func, ...) \
511 if (pvfs->vfs->func == NULL) { \
512 errno = ENOSYS; \
513 return NULL; \
514 } \
515 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
516 ret = (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \
517 } else { \
518 ret = (*pvfs->vfs->func)(__VA_ARGS__); \
519 }
520
521#define CHECK_AND_CALL_SUBCOMPONENTP(ret, r, pvfs, component, func, ...) \
522 if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \
523 errno = ENOSYS; \
524 return NULL; \
525 } \
526 if (pvfs->flags & XF_VFS_FLAG_CONTEXT_PTR) { \
527 ret = (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \
528 } else { \
529 ret = (*pvfs->vfs->component->func)(__VA_ARGS__); \
530 }
531
532#define CHECK_VFS_READONLY_FLAG(flags) \
533 if (flags & XF_VFS_FLAG_READONLY_FS) { \
534 errno = EROFS; \
535 return -1; \
536 }
537
538int xf_vfs_open(const char *path, int flags, int mode)
539{
540 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
541 if (vfs == NULL) {
542 errno = ENOENT;
543 return -1;
544 }
545
546 int acc_mode = flags & XF_VFS_O_ACCMODE;
547 int ro_filesystem = vfs->flags & XF_VFS_FLAG_READONLY_FS;
548 if (acc_mode != XF_VFS_O_RDONLY && ro_filesystem) {
549 errno = EROFS;
550 return -1;
551 }
552
553 const char *path_within_vfs = translate_path(vfs, path);
554 int fd_within_vfs;
555 CHECK_AND_CALL(fd_within_vfs, r, vfs, open, path_within_vfs, flags, mode);
556 if (fd_within_vfs >= 0) {
558 for (int i = 0; i < XF_VFS_FDS_MAX; ++i) {
559 if (s_fd_table[i].vfs_index == -1) {
560 s_fd_table[i].permanent = false;
561 s_fd_table[i].vfs_index = vfs->offset;
562 s_fd_table[i].local_fd = fd_within_vfs;
564 return i;
565 }
566 }
568 int ret;
569 CHECK_AND_CALL(ret, r, vfs, close, fd_within_vfs);
570 (void) ret; // remove "set but not used" warning
571 errno = ENOMEM;
572 return -1;
573 }
574 return -1;
575}
576
577xf_vfs_ssize_t xf_vfs_write(int fd, const void *data, size_t size)
578{
579 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
580 const int local_fd = get_local_fd(vfs, fd);
581 if (vfs == NULL || local_fd < 0) {
582 errno = EBADF;
583 return -1;
584 }
585 xf_vfs_ssize_t ret;
586 CHECK_AND_CALL(ret, r, vfs, write, local_fd, data, size);
587 return ret;
588}
589
591{
592 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
593 const int local_fd = get_local_fd(vfs, fd);
594 if (vfs == NULL || local_fd < 0) {
595 errno = EBADF;
596 return -1;
597 }
598 xf_vfs_off_t ret;
599 CHECK_AND_CALL(ret, r, vfs, lseek, local_fd, size, mode);
600 return ret;
601}
602
603xf_vfs_ssize_t xf_vfs_read(int fd, void *dst, size_t size)
604{
605 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
606 const int local_fd = get_local_fd(vfs, fd);
607 if (vfs == NULL || local_fd < 0) {
608 errno = EBADF;
609 return -1;
610 }
611 xf_vfs_ssize_t ret;
612 CHECK_AND_CALL(ret, r, vfs, read, local_fd, dst, size);
613 return ret;
614}
615
616xf_vfs_ssize_t xf_vfs_pread(int fd, void *dst, size_t size, xf_vfs_off_t offset)
617{
618 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
619 const int local_fd = get_local_fd(vfs, fd);
620 if (vfs == NULL || local_fd < 0) {
621 errno = EBADF;
622 return -1;
623 }
624 xf_vfs_ssize_t ret;
625 CHECK_AND_CALL(ret, r, vfs, pread, local_fd, dst, size, offset);
626 return ret;
627}
628
629xf_vfs_ssize_t xf_vfs_pwrite(int fd, const void *src, size_t size, xf_vfs_off_t offset)
630{
631 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
632 const int local_fd = get_local_fd(vfs, fd);
633 if (vfs == NULL || local_fd < 0) {
634 errno = EBADF;
635 return -1;
636 }
637 xf_vfs_ssize_t ret;
638 CHECK_AND_CALL(ret, r, vfs, pwrite, local_fd, src, size, offset);
639 return ret;
640}
641
642int xf_vfs_close(int fd)
643{
644 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
645 const int local_fd = get_local_fd(vfs, fd);
646 if (vfs == NULL || local_fd < 0) {
647 errno = EBADF;
648 return -1;
649 }
650 int ret;
651 CHECK_AND_CALL(ret, r, vfs, close, local_fd);
652
654 if (!s_fd_table[fd].permanent) {
655 if (s_fd_table[fd].has_pending_select) {
656 s_fd_table[fd].has_pending_close = true;
657 } else {
659 }
660 }
662 return ret;
663}
664
666{
667 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
668 const int local_fd = get_local_fd(vfs, fd);
669 if (vfs == NULL || local_fd < 0) {
670 errno = EBADF;
671 return -1;
672 }
673 int ret;
674 CHECK_AND_CALL(ret, r, vfs, fstat, local_fd, st);
675 return ret;
676}
677
678int xf_vfs_fcntl_r(int fd, int cmd, int arg)
679{
680 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
681 const int local_fd = get_local_fd(vfs, fd);
682 if (vfs == NULL || local_fd < 0) {
683 errno = EBADF;
684 return -1;
685 }
686 int ret;
687 CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, arg);
688 return ret;
689}
690
691int xf_vfs_ioctl(int fd, int cmd, ...)
692{
693 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
694 const int local_fd = get_local_fd(vfs, fd);
695 if (vfs == NULL || local_fd < 0) {
696 errno = EBADF;
697 return -1;
698 }
699 int ret;
700 va_list args;
701 va_start(args, cmd);
702 CHECK_AND_CALL(ret, r, vfs, ioctl, local_fd, cmd, args);
703 va_end(args);
704 return ret;
705}
706
707int xf_vfs_fsync(int fd)
708{
709 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
710 const int local_fd = get_local_fd(vfs, fd);
711 if (vfs == NULL || local_fd < 0) {
712 errno = EBADF;
713 return -1;
714 }
715 int ret;
716 CHECK_AND_CALL(ret, r, vfs, fsync, local_fd);
717 return ret;
718}
719
720#if XF_VFS_SUPPORT_DIR_IS_ENABLE
721
722int xf_vfs_stat(const char *path, xf_vfs_stat_t *st)
723{
724 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
725 if (vfs == NULL) {
726 errno = ENOENT;
727 return -1;
728 }
729 const char *path_within_vfs = translate_path(vfs, path);
730 int ret;
731 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, stat, path_within_vfs, st);
732 return ret;
733}
734
735int xf_vfs_utime(const char *path, const xf_vfs_utimbuf_t *times)
736{
737 int ret;
738 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
739 if (vfs == NULL) {
740 errno = ENOENT;
741 return -1;
742 }
743 const char *path_within_vfs = translate_path(vfs, path);
744 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, utime, path_within_vfs, times);
745 return ret;
746}
747
748int xf_vfs_link(const char *n1, const char *n2)
749{
751 if (vfs == NULL) {
752 errno = ENOENT;
753 return -1;
754 }
755 const xf_vfs_entry_t *vfs2 = xf_vfs_get_vfs_for_path(n2);
756 if (vfs != vfs2) {
757 errno = EXDEV;
758 return -1;
759 }
760
762
763 const char *path1_within_vfs = translate_path(vfs, n1);
764 const char *path2_within_vfs = translate_path(vfs, n2);
765 int ret;
766 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, link, path1_within_vfs, path2_within_vfs);
767 return ret;
768}
769
770int xf_vfs_unlink(const char *path)
771{
772 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
773 if (vfs == NULL) {
774 errno = ENOENT;
775 return -1;
776 }
777
779
780 const char *path_within_vfs = translate_path(vfs, path);
781 int ret;
782 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, unlink, path_within_vfs);
783 return ret;
784}
785
786int xf_vfs_rename(const char *src, const char *dst)
787{
788 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(src);
789 if (vfs == NULL) {
790 errno = ENOENT;
791 return -1;
792 }
793
795
796 const xf_vfs_entry_t *vfs_dst = xf_vfs_get_vfs_for_path(dst);
797 if (vfs != vfs_dst) {
798 errno = EXDEV;
799 return -1;
800 }
801
803
804 const char *src_within_vfs = translate_path(vfs, src);
805 const char *dst_within_vfs = translate_path(vfs, dst);
806 int ret;
807 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, rename, src_within_vfs, dst_within_vfs);
808 return ret;
809}
810
811xf_vfs_dir_t *xf_vfs_opendir(const char *name)
812{
813 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(name);
814 if (vfs == NULL) {
815 errno = ENOENT;
816 return NULL;
817 }
818 const char *path_within_vfs = translate_path(vfs, name);
819 xf_vfs_dir_t *ret;
820 CHECK_AND_CALL_SUBCOMPONENTP(ret, r, vfs, dir, opendir, path_within_vfs);
821 if (ret != NULL) {
822 ret->dd_vfs_idx = vfs->offset;
823 }
824 return ret;
825}
826
828{
830 if (vfs == NULL) {
831 errno = EBADF;
832 return NULL;
833 }
834 xf_vfs_dirent_t *ret;
835 CHECK_AND_CALL_SUBCOMPONENTP(ret, r, vfs, dir, readdir, pdir);
836 return ret;
837}
838
840{
842 if (vfs == NULL) {
843 errno = EBADF;
844 return -1;
845 }
846 int ret;
847 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, readdir_r, pdir, entry, out_dirent);
848 return ret;
849}
850
852{
854 if (vfs == NULL) {
855 errno = EBADF;
856 return -1;
857 }
858 long ret;
859 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, telldir, pdir);
860 return ret;
861}
862
863void xf_vfs_seekdir(xf_vfs_dir_t *pdir, long loc)
864{
866 if (vfs == NULL) {
867 errno = EBADF;
868 return;
869 }
870 CHECK_AND_CALL_SUBCOMPONENTV(r, vfs, dir, seekdir, pdir, loc);
871}
872
874{
875 xf_vfs_seekdir(pdir, 0);
876}
877
879{
881 if (vfs == NULL) {
882 errno = EBADF;
883 return -1;
884 }
885 int ret;
886 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, closedir, pdir);
887 return ret;
888}
889
890int xf_vfs_mkdir(const char *name, xf_vfs_mode_t mode)
891{
892 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(name);
893 if (vfs == NULL) {
894 errno = ENOENT;
895 return -1;
896 }
897
899
900 const char *path_within_vfs = translate_path(vfs, name);
901 int ret;
902 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, mkdir, path_within_vfs, mode);
903 return ret;
904}
905
906int xf_vfs_rmdir(const char *name)
907{
908 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(name);
909 if (vfs == NULL) {
910 errno = ENOENT;
911 return -1;
912 }
913
915
916 const char *path_within_vfs = translate_path(vfs, name);
917 int ret;
918 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, rmdir, path_within_vfs);
919 return ret;
920}
921
922int xf_vfs_access(const char *path, int amode)
923{
924 int ret;
925 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
926 if (vfs == NULL) {
927 errno = ENOENT;
928 return -1;
929 }
930 const char *path_within_vfs = translate_path(vfs, path);
931 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, access, path_within_vfs, amode);
932 return ret;
933}
934
935int xf_vfs_truncate(const char *path, xf_vfs_off_t length)
936{
937 int ret;
938 const xf_vfs_entry_t *vfs = xf_vfs_get_vfs_for_path(path);
939 if (vfs == NULL) {
940 errno = ENOENT;
941 return -1;
942 }
943
945
946 const char *path_within_vfs = translate_path(vfs, path);
947 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, truncate, path_within_vfs, length);
948 return ret;
949}
950
952{
953 const xf_vfs_entry_t *vfs = get_vfs_for_fd(fd);
954 int local_fd = get_local_fd(vfs, fd);
955 if (vfs == NULL || local_fd < 0) {
956 errno = EBADF;
957 return -1;
958 }
959
961
962 int ret;
963 CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, ftruncate, local_fd, length);
964 return ret;
965}
966
967#endif // CONFIG_XF_VFS_SUPPORT_DIR
968
969#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
970
971static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args)
972{
973 for (int i = 0; i < end_index; ++i) {
975 const fds_triple_t *item = &vfs_fds_triple[i];
976 if (vfs != NULL
977 && vfs->vfs->select != NULL
978 && vfs->vfs->select->end_select != NULL
979 && item->isset
980 ) {
981 xf_err_t err = vfs->vfs->select->end_select(driver_args[i]);
982 if (err != XF_OK) {
983 XF_LOGD(TAG, "end_select failed: %s", xf_err_to_name(err));
984 }
985 }
986 }
987}
988
989static inline bool xf_vfs_safe_fd_isset(int fd, const xf_fd_set *fds)
990{
991 return fds && XF_FD_ISSET(fd, fds);
992}
993
994static int set_global_fd_sets(const fds_triple_t *vfs_fds_triple, int size, xf_fd_set *readfds, xf_fd_set *writefds,
995 xf_fd_set *errorfds)
996{
997 int ret = 0;
998
999 for (int i = 0; i < size; ++i) {
1000 const fds_triple_t *item = &vfs_fds_triple[i];
1001 if (item->isset) {
1002 for (int fd = 0; fd < XF_VFS_FDS_MAX; ++fd) {
1003 if (s_fd_table[fd].vfs_index == i) {
1004 const int local_fd = s_fd_table[fd].local_fd; // single read -> no locking is required
1005 if (readfds && xf_vfs_safe_fd_isset(local_fd, &item->readfds)) {
1006 XF_LOGD(TAG, "FD %d in readfds was set from VFS ID %d", fd, i);
1007 XF_FD_SET(fd, readfds);
1008 ++ret;
1009 }
1010 if (writefds && xf_vfs_safe_fd_isset(local_fd, &item->writefds)) {
1011 XF_LOGD(TAG, "FD %d in writefds was set from VFS ID %d", fd, i);
1012 XF_FD_SET(fd, writefds);
1013 ++ret;
1014 }
1015 if (errorfds && xf_vfs_safe_fd_isset(local_fd, &item->errorfds)) {
1016 XF_LOGD(TAG, "FD %d in errorfds was set from VFS ID %d", fd, i);
1017 XF_FD_SET(fd, errorfds);
1018 ++ret;
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025 return ret;
1026}
1027
1028static void xf_vfs_log_fd_set(const char *fds_name, const xf_fd_set *fds)
1029{
1030 if (fds_name && fds) {
1031 XF_LOGD(TAG, "FDs in %s =", fds_name);
1032 for (int i = 0; i < XF_VFS_FDS_MAX; ++i) {
1033 if (xf_vfs_safe_fd_isset(i, fds)) {
1034 XF_LOGD(TAG, "%d", i);
1035 }
1036 }
1037 }
1038}
1039
1040int xf_vfs_select(int nfds, xf_fd_set *readfds, xf_fd_set *writefds, xf_fd_set *errorfds, xf_vfs_timeval_t *timeout)
1041{
1042 // NOTE: Please see the "Synchronous input/output multiplexing" section of the ESP-IDF Programming Guide
1043 // (API Reference -> Storage -> Virtual Filesystem) for a general overview of the implementation of VFS select().
1044 int ret = 0;
1045
1046 XF_LOGD(TAG, "xf_vfs_select starts with nfds = %d", nfds);
1047 if (timeout) {
1048 XF_LOGD(TAG, "timeout is %lds + %ldus", (long)timeout->tv_sec, timeout->tv_usec);
1049 }
1050 xf_vfs_log_fd_set("readfds", readfds);
1051 xf_vfs_log_fd_set("writefds", writefds);
1052 xf_vfs_log_fd_set("errorfds", errorfds);
1053
1054 if (nfds > XF_VFS_FDS_MAX || nfds < 0) {
1055 XF_LOGD(TAG, "incorrect nfds");
1056 errno = EINVAL;
1057 return -1;
1058 }
1059
1060 // Capture s_vfs_count to a local variable in case a new driver is registered or removed during this actual select()
1061 // call. s_vfs_count cannot be protected with a mutex during a select() call (which can be one without a timeout)
1062 // because that could block the registration of new driver.
1063 const size_t vfs_count = s_vfs_count;
1064 fds_triple_t *vfs_fds_triple;
1065 vfs_fds_triple = xf_malloc(vfs_count * sizeof(fds_triple_t));
1066 if (vfs_fds_triple == NULL) {
1067 errno = ENOMEM;
1068 XF_LOGD(TAG, "calloc is unsuccessful");
1069 return -1;
1070 }
1071 xf_memset(vfs_fds_triple, 0, vfs_count * sizeof(fds_triple_t));
1072
1073 xf_vfs_select_sem_t sel_sem = {
1074 .is_sem_local = false,
1075 .sem = NULL,
1076 };
1077
1078 int (*socket_select)(int, xf_fd_set *, xf_fd_set *, xf_fd_set *, xf_vfs_timeval_t *) = NULL;
1079 for (int fd = 0; fd < nfds; ++fd) {
1081 const bool is_socket_fd = s_fd_table[fd].permanent;
1082 const int vfs_index = s_fd_table[fd].vfs_index;
1083 const int local_fd = s_fd_table[fd].local_fd;
1084 if (xf_vfs_safe_fd_isset(fd, errorfds)) {
1085 s_fd_table[fd].has_pending_select = true;
1086 }
1088
1089 if (vfs_index < 0) {
1090 continue;
1091 }
1092
1093 if (is_socket_fd) {
1094 if (!socket_select) {
1095 // no socket_select found yet so take a look
1096 if (xf_vfs_safe_fd_isset(fd, readfds) ||
1097 xf_vfs_safe_fd_isset(fd, writefds) ||
1098 xf_vfs_safe_fd_isset(fd, errorfds)) {
1099 const xf_vfs_entry_t *vfs = s_vfs[vfs_index];
1100 socket_select = vfs->vfs->select->socket_select;
1101 sel_sem.sem = vfs->vfs->select->get_socket_select_semaphore();
1102 }
1103 }
1104 continue;
1105 }
1106
1107 fds_triple_t *item = &vfs_fds_triple[vfs_index]; // FD sets for VFS which belongs to fd
1108 if (xf_vfs_safe_fd_isset(fd, readfds)) {
1109 item->isset = true;
1110 XF_FD_SET(local_fd, &item->readfds);
1111 XF_FD_CLR(fd, readfds);
1112 XF_LOGD(TAG, "removing %d from readfds and adding as local FD %d to xf_fd_set of VFS ID %d", fd, local_fd, vfs_index);
1113 }
1114 if (xf_vfs_safe_fd_isset(fd, writefds)) {
1115 item->isset = true;
1116 XF_FD_SET(local_fd, &item->writefds);
1117 XF_FD_CLR(fd, writefds);
1118 XF_LOGD(TAG, "removing %d from writefds and adding as local FD %d to xf_fd_set of VFS ID %d", fd, local_fd, vfs_index);
1119 }
1120 if (xf_vfs_safe_fd_isset(fd, errorfds)) {
1121 item->isset = true;
1122 XF_FD_SET(local_fd, &item->errorfds);
1123 XF_FD_CLR(fd, errorfds);
1124 XF_LOGD(TAG, "removing %d from errorfds and adding as local FD %d to xf_fd_set of VFS ID %d", fd, local_fd, vfs_index);
1125 }
1126 }
1127
1128 // all non-socket VFSs have their FD sets in vfs_fds_triple
1129 // the global readfds, writefds and errorfds contain only socket FDs (if
1130 // there any)
1131
1132 if (!socket_select) {
1133 // There is no socket VFS registered or select() wasn't called for
1134 // any socket. Therefore, we will use our own signalization.
1135 sel_sem.is_sem_local = true;
1136 xf_osal_semaphore_attr_t sem_attr = {
1137 .name = "sem",
1138 };
1139 sel_sem.sem = (void *)xf_osal_semaphore_create(1, 1, &sem_attr);
1140 if (sel_sem.sem == NULL) {
1141 xf_free(vfs_fds_triple);
1142 errno = ENOMEM;
1143 XF_LOGD(TAG, "cannot create select semaphore");
1144 return -1;
1145 }
1146 }
1147
1148 void **driver_args = xf_malloc(vfs_count * sizeof(void *));
1149
1150 if (driver_args == NULL) {
1151 xf_free(vfs_fds_triple);
1152 errno = ENOMEM;
1153 XF_LOGD(TAG, "calloc is unsuccessful for driver args");
1154 return -1;
1155 }
1156 xf_memset(driver_args, 0, vfs_count * sizeof(void *));
1157
1158 for (size_t i = 0; i < vfs_count; ++i) {
1160 fds_triple_t *item = &vfs_fds_triple[i];
1161
1162 if (vfs == NULL || vfs->vfs->select == NULL || vfs->vfs->select->start_select == NULL) {
1163 XF_LOGD(TAG, "start_select function callback for this vfs (s_vfs[%d]) is not defined", vfs->offset);
1164 continue;
1165 }
1166
1167 if (!item->isset) {
1168 continue;
1169 }
1170
1171 // call start_select for all non-socket VFSs with has at least one FD set in readfds, writefds, or errorfds
1172 // note: it can point to socket VFS but item->isset will be false for that
1173 XF_LOGD(TAG, "calling start_select for VFS ID %d with the following local FDs", i);
1174 xf_vfs_log_fd_set("readfds", &item->readfds);
1175 xf_vfs_log_fd_set("writefds", &item->writefds);
1176 xf_vfs_log_fd_set("errorfds", &item->errorfds);
1177 xf_err_t err = vfs->vfs->select->start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem,
1178 driver_args + i);
1179
1180 if (err != XF_OK) {
1181 if (err != XF_ERR_NOT_SUPPORTED) {
1182 call_end_selects(i, vfs_fds_triple, driver_args);
1183 }
1184 (void) set_global_fd_sets(vfs_fds_triple, vfs_count, readfds, writefds, errorfds);
1185 if (sel_sem.is_sem_local && sel_sem.sem) {
1187 sel_sem.sem = NULL;
1188 }
1189 xf_free(vfs_fds_triple);
1190 xf_free(driver_args);
1191 errno = EINTR;
1192 XF_LOGD(TAG, "start_select failed: %s", xf_err_to_name(err));
1193 return -1;
1194 }
1195 }
1196
1197 if (socket_select) {
1198 XF_LOGD(TAG, "calling socket_select with the following FDs");
1199 xf_vfs_log_fd_set("readfds", readfds);
1200 xf_vfs_log_fd_set("writefds", writefds);
1201 xf_vfs_log_fd_set("errorfds", errorfds);
1202 ret = socket_select(nfds, readfds, writefds, errorfds, timeout);
1203 XF_LOGD(TAG, "socket_select returned %d and the FDs are the following", ret);
1204 xf_vfs_log_fd_set("readfds", readfds);
1205 xf_vfs_log_fd_set("writefds", writefds);
1206 xf_vfs_log_fd_set("errorfds", errorfds);
1207 } else {
1208 if (readfds) {
1209 XF_FD_ZERO(readfds);
1210 }
1211 if (writefds) {
1212 XF_FD_ZERO(writefds);
1213 }
1214 if (errorfds) {
1215 XF_FD_ZERO(errorfds);
1216 }
1217
1218 uint32_t ticks_to_wait = XF_OSAL_WAIT_FOREVER;
1219 if (timeout) {
1220 uint32_t timeout_ms = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
1221 /* Round up the number of ticks.
1222 * Not only we need to round up the number of ticks, but we also need to add 1.
1223 * Indeed, `select` function shall wait for AT LEAST timeout, but on FreeRTOS,
1224 * if we specify a timeout of 1 tick to `xSemaphoreTake`, it will take AT MOST
1225 * 1 tick before triggering a timeout. Thus, we need to pass 2 ticks as a timeout
1226 * to `xSemaphoreTake`. */
1227 // ticks_to_wait = ((timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS) + 1;
1228 ticks_to_wait = xf_osal_kernel_ms_to_ticks(timeout_ms) + 1;
1229 XF_LOGD(TAG, "timeout is %" PRIu32 "ms", timeout_ms);
1230 }
1231 XF_LOGD(TAG, "waiting without calling socket_select");
1232 xf_osal_semaphore_acquire(sel_sem.sem, ticks_to_wait);
1233 }
1234
1235 call_end_selects(vfs_count, vfs_fds_triple, driver_args); // for VFSs for start_select was called before
1236
1237 if (ret >= 0) {
1238 ret += set_global_fd_sets(vfs_fds_triple, vfs_count, readfds, writefds, errorfds);
1239 }
1240 if (sel_sem.sem) { // Cleanup the select semaphore
1241 if (sel_sem.is_sem_local) {
1243 } else if (socket_select) {
1244 // SemaphoreHandle_t *s = sel_sem.sem;
1245 // /* Select might have been triggered from both lwip and vfs fds at the same time, and
1246 // * we have to make sure that the lwip semaphore is cleared when we exit select().
1247 // * It is safe, as the semaphore belongs to the calling thread. */
1248 // xSemaphoreTake(*s, 0);
1249 xf_osal_semaphore_acquire(sel_sem.sem, 0);
1250 }
1251 sel_sem.sem = NULL;
1252 }
1254 for (int fd = 0; fd < nfds; ++fd) {
1255 if (s_fd_table[fd].has_pending_close) {
1257 }
1258 }
1260 xf_free(vfs_fds_triple);
1261 xf_free(driver_args);
1262
1263 XF_LOGD(TAG, "xf_vfs_select returns %d", ret);
1264 xf_vfs_log_fd_set("readfds", readfds);
1265 xf_vfs_log_fd_set("writefds", writefds);
1266 xf_vfs_log_fd_set("errorfds", errorfds);
1267 return ret;
1268}
1269
1271{
1272 if (sem.is_sem_local) {
1274 } else {
1275 // Another way would be to go through s_fd_table and find the VFS
1276 // which has a permanent FD. But in order to avoid to lock
1277 // s_fd_table_lock we go through the VFS table.
1278 for (int i = 0; i < s_vfs_count; ++i) {
1279 // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't
1280 // matter here stop_socket_select() will be called for only valid VFS drivers.
1281 const xf_vfs_entry_t *vfs = s_vfs[i];
1282 if (vfs != NULL
1283 && vfs->vfs->select != NULL
1284 && vfs->vfs->select->stop_socket_select != NULL
1285 ) {
1286 vfs->vfs->select->stop_socket_select(sem.sem);
1287 break;
1288 }
1289 }
1290 }
1291}
1292
1294{
1295 if (sem.is_sem_local) {
1296 // xSemaphoreGiveFromISR(sem.sem, woken);
1297 /* TODO 未处理 woken */
1299 } else {
1300 // Another way would be to go through s_fd_table and find the VFS
1301 // which has a permanent FD. But in order to avoid to lock
1302 // s_fd_table_lock we go through the VFS table.
1303 for (int i = 0; i < s_vfs_count; ++i) {
1304 // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't
1305 // matter here stop_socket_select() will be called for only valid VFS drivers.
1306 const xf_vfs_entry_t *vfs = s_vfs[i];
1307 if (vfs != NULL
1308 && vfs->vfs->select != NULL
1309 && vfs->vfs->select->stop_socket_select_isr != NULL
1310 ) {
1311 // Note: If the UART ISR resides in IRAM, the function referenced by stop_socket_select_isr should also be placed in IRAM.
1312 vfs->vfs->select->stop_socket_select_isr(sem.sem, woken);
1313 break;
1314 }
1315 }
1316 }
1317}
1318
1319#endif // XF_VFS_SUPPORT_SELECT_IS_ENABLE
1320
1321/* ==================== [Static Functions] ================================== */
1322
1324{
1325 for (xf_vfs_ssize_t i = 0; i < XF_VFS_MAX_COUNT; i++) {
1326 if (s_vfs[i] == NULL) {
1327 return i;
1328 }
1329 }
1330 return -1;
1331}
1332
1334{
1335// We can afford to cast away the const qualifier here, because we know that we allocated the struct and therefore its safe
1336
1337#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1338 xf_free((void *)vfs->dir);
1339#endif
1340
1341#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1342 xf_free((void *)vfs->select);
1343#endif
1344
1345 xf_free(vfs);
1346}
1347
1349{
1350 if (entry == NULL) { // Necessary because of the following flags check
1351 return;
1352 }
1353
1354 if (!(entry->flags & XF_VFS_FLAG_STATIC)) {
1355 xf_vfs_free_fs_ops((xf_vfs_fs_ops_t *)entry->vfs); // const cast, but we know it's not static from the flag
1356 }
1357
1358 xf_free(entry);
1359}
1360
1362{
1363 XF_CHECK(vfs == NULL, NULL, TAG, "vfs is NULL");
1364#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1365 // If the dir functions are not implemented, we don't need to convert them
1366 if (proxy.dir != NULL) {
1367 xf_vfs_dir_ops_t tmp = {
1368 .stat = vfs->stat,
1369 .link = vfs->link,
1370 .unlink = vfs->unlink,
1371 .rename = vfs->rename,
1372 .opendir = vfs->opendir,
1373 .readdir = vfs->readdir,
1374 .readdir_r = vfs->readdir_r,
1375 .telldir = vfs->telldir,
1376 .seekdir = vfs->seekdir,
1377 .closedir = vfs->closedir,
1378 .mkdir = vfs->mkdir,
1379 .rmdir = vfs->rmdir,
1380 .access = vfs->access,
1381 .truncate = vfs->truncate,
1382 .ftruncate = vfs->ftruncate,
1383 .utime = vfs->utime,
1384 };
1385
1386 xf_memcpy(proxy.dir, &tmp, sizeof(xf_vfs_dir_ops_t));
1387 }
1388#endif // CONFIG_XF_VFS_SUPPORT_DIR
1389
1390#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1391 // If the select functions are not implemented, we don't need to convert them
1392 if (proxy.select != NULL) {
1393 xf_vfs_select_ops_t tmp = {
1394 .start_select = vfs->start_select,
1395 .socket_select = vfs->socket_select,
1396 .stop_socket_select = vfs->stop_socket_select,
1397 .stop_socket_select_isr = vfs->stop_socket_select_isr,
1398 .get_socket_select_semaphore = vfs->get_socket_select_semaphore,
1399 .end_select = vfs->end_select,
1400 };
1401
1402 xf_memcpy(proxy.select, &tmp, sizeof(xf_vfs_select_ops_t));
1403 }
1404#endif // XF_VFS_SUPPORT_SELECT_IS_ENABLE
1405
1406 xf_vfs_fs_ops_t tmp = {
1407 .write = vfs->write,
1408 .lseek = vfs->lseek,
1409 .read = vfs->read,
1410 .pread = vfs->pread,
1411 .pwrite = vfs->pwrite,
1412 .open = vfs->open,
1413 .close = vfs->close,
1414 .fstat = vfs->fstat,
1415 .fcntl = vfs->fcntl,
1416 .ioctl = vfs->ioctl,
1417 .fsync = vfs->fsync,
1418#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1419 .dir = proxy.dir,
1420#endif
1421#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1422 .select = proxy.select,
1423#endif
1424 };
1425
1427 if (out == NULL) {
1428 return NULL;
1429 }
1430
1431 // Doing this is the only way to correctly initialize const members of a struct according to C standard
1432 xf_memcpy(out, &tmp, sizeof(xf_vfs_fs_ops_t));
1433
1434 return out;
1435}
1436
1438{
1439#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1440 xf_free(proxy->dir);
1441#endif
1442#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1443 xf_free(proxy->select);
1444#endif
1445}
1446
1448{
1449 vfs_component_proxy_t proxy = {};
1450
1451#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1452 if (orig->dir != NULL) {
1453 proxy.dir = (xf_vfs_dir_ops_t *) xf_malloc(sizeof(xf_vfs_dir_ops_t));
1454 if (proxy.dir == NULL) {
1455 goto fail;
1456 }
1457 xf_memcpy(proxy.dir, orig->dir, sizeof(xf_vfs_dir_ops_t));
1458 }
1459#endif
1460
1461#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1462 if (orig->select != NULL) {
1464 if (proxy.select == NULL) {
1465 goto fail;
1466 }
1467 xf_memcpy(proxy.select, orig->select, sizeof(xf_vfs_select_ops_t));
1468 }
1469#endif
1470
1471 // This tediousness is required because of const members
1472 xf_vfs_fs_ops_t tmp = {
1473 .write = orig->write,
1474 .lseek = orig->lseek,
1475 .read = orig->read,
1476 .pread = orig->pread,
1477 .pwrite = orig->pwrite,
1478 .open = orig->open,
1479 .close = orig->close,
1480 .fstat = orig->fstat,
1481 .fcntl = orig->fcntl,
1482 .ioctl = orig->ioctl,
1483 .fsync = orig->fsync,
1484#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1485 .dir = proxy.dir,
1486#endif
1487#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1488 .select = proxy.select,
1489#endif
1490 };
1491
1493 if (out == NULL) {
1494 goto fail;
1495 }
1496
1497 xf_memcpy(out, &tmp, sizeof(xf_vfs_fs_ops_t));
1498
1499 return out;
1500
1501fail:
1502 free_proxy_members(&proxy);
1503 return NULL;
1504}
1505
1507{
1508 if (vfs == NULL) {
1509 XF_LOGE(TAG, "Cannot minify NULL VFS");
1510 return XF_ERR_INVALID_ARG;
1511 }
1512
1513 if (min == NULL) {
1514 XF_LOGE(TAG, "Cannot minify VFS to NULL");
1515 return XF_ERR_INVALID_ARG;
1516 }
1517
1518 vfs_component_proxy_t proxy = {};
1519
1520#if XF_VFS_SUPPORT_DIR_IS_ENABLE
1521 const bool skip_dir =
1522 vfs->stat == NULL &&
1523 vfs->link == NULL &&
1524 vfs->unlink == NULL &&
1525 vfs->rename == NULL &&
1526 vfs->opendir == NULL &&
1527 vfs->readdir == NULL &&
1528 vfs->readdir_r == NULL &&
1529 vfs->telldir == NULL &&
1530 vfs->seekdir == NULL &&
1531 vfs->closedir == NULL &&
1532 vfs->mkdir == NULL &&
1533 vfs->rmdir == NULL &&
1534 vfs->access == NULL &&
1535 vfs->truncate == NULL &&
1536 vfs->ftruncate == NULL &&
1537 vfs->utime == NULL;
1538
1539 if (!skip_dir) {
1540 proxy.dir = (xf_vfs_dir_ops_t *) xf_malloc(sizeof(xf_vfs_dir_ops_t));
1541 if (proxy.dir == NULL) {
1542 goto fail;
1543 }
1544 }
1545#endif
1546
1547#if XF_VFS_SUPPORT_SELECT_IS_ENABLE
1548 const bool skip_select =
1549 vfs->start_select == NULL &&
1550 vfs->socket_select == NULL &&
1551 vfs->stop_socket_select == NULL &&
1552 vfs->stop_socket_select_isr == NULL &&
1553 vfs->get_socket_select_semaphore == NULL &&
1554 vfs->end_select == NULL;
1555
1556 if (!skip_select) {
1558 if (proxy.select == NULL) {
1559 goto fail;
1560 }
1561 }
1562#endif
1563
1564 xf_vfs_fs_ops_t *main = xf_minify_vfs(vfs, proxy);
1565 if (main == NULL) {
1566 goto fail;
1567 }
1568
1569 *min = main;
1570 return XF_OK;
1571
1572fail:
1573
1574 free_proxy_members(&proxy);
1575 return XF_ERR_NO_MEM;
1576}
1577
1578static xf_err_t xf_vfs_register_fs_common(const char *base_path, size_t len, const xf_vfs_fs_ops_t *vfs, int flags,
1579 void *ctx, int *vfs_index)
1580{
1581 if (vfs == NULL) {
1582 XF_LOGE(TAG, "VFS is NULL");
1583 return XF_ERR_INVALID_ARG;
1584 }
1585
1586 if (len != XF_VFS_PATH_PREFIX_LEN_IGNORED) {
1587 /* empty prefix is allowed, "/" is not allowed */
1588 if ((len == 1) || (len > XF_VFS_PATH_MAX)) {
1589 return XF_ERR_INVALID_ARG;
1590 }
1591 /* prefix has to start with "/" and not end with "/" */
1592 if (len >= 2 && ((base_path[0] != '/') || (base_path[len - 1] == '/'))) {
1593 return XF_ERR_INVALID_ARG;
1594 }
1595 }
1596
1598 if (index < 0) {
1599 return XF_ERR_NO_MEM;
1600 }
1601
1602 if (s_vfs[index] != NULL) {
1603 return XF_ERR_INVALID_STATE;
1604 }
1605
1606 if (index == s_vfs_count) {
1607 s_vfs_count++;
1608 }
1609
1611 if (entry == NULL) {
1612 return XF_ERR_NO_MEM;
1613 }
1614
1615 s_vfs[index] = entry;
1616 if (len != XF_VFS_PATH_PREFIX_LEN_IGNORED) {
1617 xf_strncpy(entry->path_prefix, base_path, sizeof(entry->path_prefix)); // we have already verified argument length
1618 } else {
1619 xf_memset(entry->path_prefix, 0, sizeof(entry->path_prefix));
1620 }
1621 entry->path_prefix_len = len;
1622 entry->vfs = vfs;
1623 entry->ctx = ctx;
1624 entry->offset = index;
1625 entry->flags = flags;
1626
1627 if (vfs_index) {
1628 *vfs_index = index;
1629 }
1630
1631 return XF_OK;
1632}
1633
1634static inline bool fd_valid(int fd)
1635{
1636 return (fd < XF_VFS_FDS_MAX) && (fd >= 0);
1637}
1638
1639static const xf_vfs_entry_t *get_vfs_for_fd(int fd)
1640{
1641 const xf_vfs_entry_t *vfs = NULL;
1642 if (fd_valid(fd)) {
1643 const int index = s_fd_table[fd].vfs_index; // single read -> no locking is required
1644 vfs = xf_vfs_get_vfs_for_index(index);
1645 }
1646 return vfs;
1647}
1648
1649static inline int get_local_fd(const xf_vfs_entry_t *vfs, int fd)
1650{
1651 int local_fd = -1;
1652
1653 if (vfs && fd_valid(fd)) {
1654 local_fd = s_fd_table[fd].local_fd; // single read -> no locking is required
1655 }
1656
1657 return local_fd;
1658}
1659
1660static const char *translate_path(const xf_vfs_entry_t *vfs, const char *src_path)
1661{
1662 int cmp_res = xf_strncmp(src_path, vfs->path_prefix, vfs->path_prefix_len);
1663 XF_CHECK(cmp_res != 0, NULL, TAG, "path prefix does not match");
1664 if (xf_strlen(src_path) == vfs->path_prefix_len) {
1665 // special case when src_path matches the path prefix exactly
1666 return "/";
1667 }
1668 return src_path + vfs->path_prefix_len;
1669}
uint32_t xf_osal_kernel_ms_to_ticks(uint32_t ms)
将 ms 数转为滴答数.
xf_osal_semaphore_t xf_osal_semaphore_create(uint32_t max_count, uint32_t initial_count, const xf_osal_semaphore_attr_t *attr)
创建并初始化信号量对象。
xf_err_t xf_osal_semaphore_release(xf_osal_semaphore_t semaphore)
释放信号量令牌直至初始最大计数。
xf_err_t xf_osal_semaphore_delete(xf_osal_semaphore_t semaphore)
删除信号量对象。
xf_err_t xf_osal_semaphore_acquire(xf_osal_semaphore_t semaphore, uint32_t timeout)
获取信号量令牌,如果没有可用令牌则超时。
#define XF_OSAL_WAIT_FOREVER
Definition xf_osal_def.h:30
#define XF_CHECK(condition, retval, tag, format,...)
xfusion 检查宏(条件 成立 时则输出日志后返回)。
Definition xf_check.h:112
int32_t xf_err_t
整形错误类型。 错误码具体值见 xf_err_code_t.
Definition xf_err.h:69
const char * xf_err_to_name(xf_err_t code)
返回 xf_err_code_t 错误代码对应的错误信息字符串。
@ XF_ERR_INVALID_ARG
Definition xf_err.h:46
@ XF_ERR_NOT_SUPPORTED
Definition xf_err.h:51
@ XF_OK
Definition xf_err.h:43
@ XF_ERR_INVALID_STATE
Definition xf_err.h:47
@ XF_ERR_NO_MEM
Definition xf_err.h:45
xf_err_t xf_lock_init(xf_lock_t *p_lock)
初始化锁.
Definition xf_lock.c:48
void * xf_lock_t
lock 句柄.
#define xf_malloc(x)
Definition xf_stdlib.h:38
#define xf_free(x)
Definition xf_stdlib.h:39
#define xf_strcmp(dest, src)
Definition xf_string.h:46
#define xf_strlen(str)
Definition xf_string.h:48
#define xf_strncmp(dest, src, n)
Definition xf_string.h:47
#define xf_memset(ptr, value, size)
Definition xf_string.h:42
#define xf_memcmp(dest, src, n)
Definition xf_string.h:45
#define xf_memcpy(dest, src, n)
Definition xf_string.h:44
void xf_vfs_dump_registered_paths(void)
Dump all registered FSs to the provided FILE*
Definition xf_vfs.c:367
int xf_vfs_unlink(const char *path)
Definition xf_vfs.c:770
int xf_vfs_mkdir(const char *name, xf_vfs_mode_t mode)
Definition xf_vfs.c:890
xf_err_t xf_vfs_register_fd(xf_vfs_id_t vfs_id, int *fd)
Definition xf_vfs.c:288
long xf_vfs_telldir(xf_vfs_dir_t *pdir)
Definition xf_vfs.c:851
int xf_vfs_fsync(int fd)
Definition xf_vfs.c:707
xf_err_t xf_vfs_unregister_with_id(xf_vfs_id_t vfs_id)
Definition xf_vfs.c:240
xf_vfs_dir_t * xf_vfs_opendir(const char *name)
Definition xf_vfs.c:811
xf_err_t xf_vfs_register(const char *base_path, const xf_vfs_t *vfs, void *ctx)
Definition xf_vfs.c:177
int xf_vfs_ioctl(int fd, int cmd,...)
Definition xf_vfs.c:691
int xf_vfs_close(int fd)
Definition xf_vfs.c:642
int xf_vfs_access(const char *path, int amode)
Definition xf_vfs.c:922
xf_vfs_dirent_t * xf_vfs_readdir(xf_vfs_dir_t *pdir)
Definition xf_vfs.c:827
int xf_vfs_ftruncate(int fd, xf_vfs_off_t length)
Definition xf_vfs.c:951
int xf_vfs_closedir(xf_vfs_dir_t *pdir)
Definition xf_vfs.c:878
int xf_vfs_readdir_r(xf_vfs_dir_t *pdir, xf_vfs_dirent_t *entry, xf_vfs_dirent_t **out_dirent)
Definition xf_vfs.c:839
int xf_vfs_fstat(int fd, xf_vfs_stat_t *st)
Definition xf_vfs.c:665
void xf_vfs_dump_fds(void)
Dump the existing VFS FDs data to FILE* fp
Definition xf_vfs.c:347
int xf_vfs_id_t
xf_err_t xf_vfs_unregister(const char *base_path)
Definition xf_vfs.c:267
xf_err_t xf_vfs_unregister_fs(const char *base_path)
Definition xf_vfs.c:283
void xf_vfs_select_triggered_isr(xf_vfs_select_sem_t sem, int *woken)
Notification from a VFS driver about a read/write/error condition (ISR version)
Definition xf_vfs.c:1293
xf_err_t xf_vfs_register_fs_with_id(const xf_vfs_fs_ops_t *vfs, int flags, void *ctx, xf_vfs_id_t *vfs_id)
Definition xf_vfs.c:220
#define XF_VFS_PATH_PREFIX_LEN_IGNORED
xf_err_t xf_vfs_register_with_id(const xf_vfs_t *vfs, void *ctx, xf_vfs_id_t *vfs_id)
Definition xf_vfs.c:230
xf_err_t xf_vfs_register_fd_with_local_fd(xf_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd)
Definition xf_vfs.c:293
#define XF_VFS_FLAG_READONLY_FS
xf_vfs_ssize_t xf_vfs_pread(int fd, void *dst, size_t size, xf_vfs_off_t offset)
Implements the VFS layer of POSIX pread()
Definition xf_vfs.c:616
xf_vfs_ssize_t xf_vfs_pwrite(int fd, const void *src, size_t size, xf_vfs_off_t offset)
Implements the VFS layer of POSIX pwrite()
Definition xf_vfs.c:629
xf_err_t xf_vfs_unregister_fs_with_id(xf_vfs_id_t vfs_id)
Definition xf_vfs.c:262
xf_err_t xf_vfs_register_fd_range(const xf_vfs_t *vfs, void *ctx, int min_fd, int max_fd)
Definition xf_vfs.c:182
int xf_vfs_open(const char *path, int flags, int mode)
Definition xf_vfs.c:538
int xf_vfs_rename(const char *src, const char *dst)
Definition xf_vfs.c:786
int xf_vfs_rmdir(const char *name)
Definition xf_vfs.c:906
int xf_vfs_link(const char *n1, const char *n2)
Definition xf_vfs.c:748
void xf_vfs_select_triggered(xf_vfs_select_sem_t sem)
Notification from a VFS driver about a read/write/error condition
Definition xf_vfs.c:1270
xf_err_t xf_vfs_unregister_fd(xf_vfs_id_t vfs_id, int fd)
Definition xf_vfs.c:325
int xf_vfs_truncate(const char *path, xf_vfs_off_t length)
Definition xf_vfs.c:935
int xf_vfs_utime(const char *path, const xf_vfs_utimbuf_t *times)
Definition xf_vfs.c:735
int xf_vfs_fcntl_r(int fd, int cmd, int arg)
Definition xf_vfs.c:678
xf_err_t xf_vfs_register_fs(const char *base_path, const xf_vfs_fs_ops_t *vfs, int flags, void *ctx)
Definition xf_vfs.c:117
void xf_vfs_seekdir(xf_vfs_dir_t *pdir, long loc)
Definition xf_vfs.c:863
xf_vfs_ssize_t xf_vfs_read(int fd, void *dst, size_t size)
Definition xf_vfs.c:603
void xf_vfs_rewinddir(xf_vfs_dir_t *pdir)
Definition xf_vfs.c:873
xf_vfs_off_t xf_vfs_lseek(int fd, xf_vfs_off_t size, int mode)
Definition xf_vfs.c:590
int xf_vfs_select(int nfds, xf_fd_set *readfds, xf_fd_set *writefds, xf_fd_set *errorfds, xf_vfs_timeval_t *timeout)
Synchronous I/O multiplexing which implements the functionality of POSIX select() for VFS
Definition xf_vfs.c:1040
#define XF_VFS_FLAG_STATIC
xf_vfs_ssize_t xf_vfs_write(int fd, const void *data, size_t size)
Definition xf_vfs.c:577
static xf_osal_semaphore_t sem
Definition xf_main.c:35
信号量的属性结构。
void * ctx
const xf_vfs_fs_ops_t * vfs
int flags
size_t path_prefix_len
char path_prefix[XF_VFS_PATH_MAX]
int offset
vfs_index_t vfs_index
Definition xf_vfs.c:67
bool permanent
Definition xf_vfs.c:63
bool has_pending_close
Definition xf_vfs.c:64
local_fd_t local_fd
Definition xf_vfs.c:68
bool has_pending_select
Definition xf_vfs.c:65
uint8_t _reserved
Definition xf_vfs.c:66
bool isset
Definition xf_vfs.c:72
xf_fd_set writefds
Definition xf_vfs.c:74
xf_fd_set errorfds
Definition xf_vfs.c:75
xf_fd_set readfds
Definition xf_vfs.c:73
xf_vfs_dir_ops_t * dir
Definition xf_vfs.c:80
xf_vfs_select_ops_t * select
Definition xf_vfs.c:83
Struct containing function pointers to directory related functionality.
Definition xf_vfs_ops.h:90
const xf_vfs_stat_op_t stat
Definition xf_vfs_ops.h:93
Opaque directory structure
Directory entry structure
Main struct of the minified vfs API, containing basic function pointers as well as pointers to the ot...
Definition xf_vfs_ops.h:188
const xf_vfs_ioctl_op_t ioctl
Definition xf_vfs_ops.h:227
const xf_vfs_pread_op_t pread
Definition xf_vfs_ops.h:203
const xf_vfs_select_ops_t *const select
Definition xf_vfs_ops.h:239
const xf_vfs_dir_ops_t *const dir
Definition xf_vfs_ops.h:235
const xf_vfs_pwrite_op_t pwrite
Definition xf_vfs_ops.h:207
const xf_vfs_read_op_t read
Definition xf_vfs_ops.h:199
const xf_vfs_write_op_t write
Definition xf_vfs_ops.h:191
const xf_vfs_fcntl_op_t fcntl
Definition xf_vfs_ops.h:223
const xf_vfs_fstat_op_t fstat
Definition xf_vfs_ops.h:219
const xf_vfs_fsync_op_t fsync
Definition xf_vfs_ops.h:231
const xf_vfs_lseek_op_t lseek
Definition xf_vfs_ops.h:195
const xf_vfs_close_op_t close
Definition xf_vfs_ops.h:215
const xf_vfs_open_op_t open
Definition xf_vfs_ops.h:211
Struct containing function pointers to select related functionality.
const xf_vfs_get_socket_select_semaphore_op_t get_socket_select_semaphore
const xf_vfs_end_select_op_t end_select
const xf_vfs_stop_socket_select_op_t stop_socket_select
const xf_vfs_stop_socket_select_isr_op_t stop_socket_select_isr
const xf_vfs_socket_select_op_t socket_select
const xf_vfs_start_select_op_t start_select
VFS semaphore type for select()
VFS definition structure
xf_err_t(* start_select)(int nfds, xf_fd_set *readfds, xf_fd_set *writefds, xf_fd_set *exceptfds, xf_vfs_select_sem_t sem, void **end_select_args)
xf_vfs_dirent_t *(* readdir)(xf_vfs_dir_t *pdir)
xf_vfs_ssize_t(* pwrite)(int fd, const void *src, size_t size, xf_vfs_off_t offset)
void(* stop_socket_select)(void *sem)
int(* truncate)(const char *path, xf_vfs_off_t length)
int(* stat)(const char *path, xf_vfs_stat_t *st)
int(* access)(const char *path, int amode)
void(* seekdir)(xf_vfs_dir_t *pdir, long offset)
int(* fsync)(int fd)
xf_vfs_ssize_t(* write)(int fd, const void *data, size_t size)
int(* rename)(const char *src, const char *dst)
void *(* get_socket_select_semaphore)(void)
int(* close)(int fd)
int(* rmdir)(const char *name)
int(* utime)(const char *path, const xf_vfs_utimbuf_t *times)
xf_err_t(* end_select)(void *end_select_args)
xf_vfs_ssize_t(* read)(int fd, void *dst, size_t size)
xf_vfs_dir_t *(* opendir)(const char *name)
int(* fcntl)(int fd, int cmd, int arg)
int(* readdir_r)(xf_vfs_dir_t *pdir, xf_vfs_dirent_t *entry, xf_vfs_dirent_t **out_dirent)
xf_vfs_off_t(* lseek)(int fd, xf_vfs_off_t size, int mode)
xf_vfs_ssize_t(* pread)(int fd, void *dst, size_t size, xf_vfs_off_t offset)
int(* link)(const char *n1, const char *n2)
void(* stop_socket_select_isr)(void *sem, int *woken)
int(* socket_select)(int nfds, xf_fd_set *readfds, xf_fd_set *writefds, xf_fd_set *errorfds, xf_vfs_timeval_t *timeout)
int(* fstat)(int fd, xf_vfs_stat_t *st)
long(* telldir)(xf_vfs_dir_t *pdir)
int(* ftruncate)(int fd, xf_vfs_off_t length)
int(* closedir)(xf_vfs_dir_t *pdir)
int(* open)(const char *path, int flags, int mode)
int(* ioctl)(int fd, int cmd, va_list args)
int(* unlink)(const char *path)
int(* mkdir)(const char *name, xf_vfs_mode_t mode)
xf_vfs_suseconds_t tv_usec
xf_vfs_time_t tv_sec
aos_utimbuf 结构描述了文件系统 inode 的 最后访问时间和最后修改时间。
static ex_scan_ctx_t ctx
Definition xf_main.c:69
int ioctl(int fd, unsigned long request,...)
size_t read(int fd, void *buf, size_t count)
int close(int fd)
size_t write(int fd, const void *buf, size_t count)
int open(const char *pathname, int flags)
int main(void)
Definition main.c:28
#define XF_LOGE(tag, format,...)
#define XF_LOGW(tag, format,...)
#define XF_LOGD(tag, format,...)
#define xf_log_printf(format,...)
_LOCAL_FD_T_ local_fd_t
Definition xf_vfs.c:55
static bool fd_valid(int fd)
Definition xf_vfs.c:1634
static void xf_vfs_free_entry(xf_vfs_entry_t *entry)
Definition xf_vfs.c:1348
static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args)
Definition xf_vfs.c:971
#define _lock_release(lock)
Definition xf_vfs.c:41
static size_t s_vfs_count
Definition xf_vfs.c:108
#define CHECK_AND_CALL(ret, r, pvfs, func,...)
Definition xf_vfs.c:466
const xf_vfs_entry_t * xf_vfs_get_vfs_for_index(int index)
Definition xf_vfs.c:405
static const char * translate_path(const xf_vfs_entry_t *vfs, const char *src_path)
Definition xf_vfs.c:1660
static void xf_vfs_log_fd_set(const char *fds_name, const xf_fd_set *fds)
Definition xf_vfs.c:1028
static int get_local_fd(const xf_vfs_entry_t *vfs, int fd)
Definition xf_vfs.c:1649
static xf_err_t xf_vfs_make_fs_ops(const xf_vfs_t *vfs, xf_vfs_fs_ops_t **min)
Definition xf_vfs.c:1506
static int set_global_fd_sets(const fds_triple_t *vfs_fds_triple, int size, xf_fd_set *readfds, xf_fd_set *writefds, xf_fd_set *errorfds)
Definition xf_vfs.c:994
static const char *const TAG
Definition xf_vfs.c:105
static void xf_vfs_free_fs_ops(xf_vfs_fs_ops_t *vfs)
Definition xf_vfs.c:1333
static xf_vfs_fs_ops_t * xf_vfs_duplicate_fs_ops(const xf_vfs_fs_ops_t *orig)
Definition xf_vfs.c:1447
int8_t vfs_index_t
Definition xf_vfs.c:58
#define CHECK_VFS_READONLY_FLAG(flags)
Definition xf_vfs.c:532
xf_err_t xf_vfs_register_common(const char *base_path, size_t len, const xf_vfs_t *vfs, void *ctx, int *vfs_index)
Definition xf_vfs.c:146
static const xf_vfs_entry_t * get_vfs_for_fd(int fd)
Definition xf_vfs.c:1639
static xf_lock_t s_fd_table_lock
Definition xf_vfs.c:111
static xf_err_t xf_vfs_register_fs_common(const char *base_path, size_t len, const xf_vfs_fs_ops_t *vfs, int flags, void *ctx, int *vfs_index)
Definition xf_vfs.c:1578
#define CHECK_AND_CALL_SUBCOMPONENTV(r, pvfs, component, func,...)
Definition xf_vfs.c:499
#define CHECK_AND_CALL_SUBCOMPONENTP(ret, r, pvfs, component, func,...)
Definition xf_vfs.c:521
static fd_table_t s_fd_table[XF_VFS_FDS_MAX]
Definition xf_vfs.c:110
static xf_vfs_ssize_t xf_get_free_index(void)
Definition xf_vfs.c:1323
static bool xf_vfs_safe_fd_isset(int fd, const xf_fd_set *fds)
Definition xf_vfs.c:989
#define STATIC_ASSERT(EXPR,...)
Definition xf_vfs.c:37
#define CHECK_AND_CALL_SUBCOMPONENT(ret, r, pvfs, component, func,...)
Definition xf_vfs.c:477
static xf_vfs_fs_ops_t * xf_minify_vfs(const xf_vfs_t *const vfs, vfs_component_proxy_t proxy)
Definition xf_vfs.c:1361
const xf_vfs_entry_t * xf_vfs_get_vfs_for_path(const char *path)
Definition xf_vfs.c:414
#define FD_TABLE_ENTRY_UNUSED
Definition xf_vfs.c:34
#define xf_strncpy(dst, src, len)
Definition xf_vfs.c:44
static void free_proxy_members(vfs_component_proxy_t *proxy)
Definition xf_vfs.c:1437
static xf_vfs_entry_t * s_vfs[XF_VFS_MAX_COUNT]
Definition xf_vfs.c:107
#define _LOCAL_FD_T_
Definition xf_vfs.c:50
#define _lock_acquire(lock)
Definition xf_vfs.c:40
xf_err_t xf_vfs_set_readonly_flag(const char *base_path)
Definition xf_vfs.c:388
#define XF_VFS_FDS_MAX
#define XF_VFS_MAX_COUNT
#define XF_VFS_PATH_MAX
#define XF_VFS_O_RDONLY
#define XF_VFS_O_ACCMODE
#define XF_FD_CLR(n, p)
#define XF_FD_ISSET(n, p)
#define XF_FD_SET(n, p)
#define XF_FD_ZERO(p)
unsigned long xf_vfs_mode_t
long xf_vfs_off_t
signed int xf_vfs_ssize_t