#include <sys/types.h>
#include <sys/reent.h>
#include <sys/stat.h>
+#include <dirent.h>
+
#ifdef __cplusplus
extern "C" {
#endif
int (*rename_p)(void* ctx, const char *src, const char *dst);
int (*rename)(const char *src, const char *dst);
};
+ union {
+ DIR* (*opendir_p)(void* ctx, const char* name);
+ DIR* (*opendir)(const char* name);
+ };
+ union {
+ struct dirent* (*readdir_p)(void* ctx, DIR* pdir);
+ struct dirent* (*readdir)(DIR* pdir);
+ };
+ union {
+ int (*readdir_r_p)(void* ctx, DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
+ int (*readdir_r)(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
+ };
+ union {
+ long (*telldir_p)(void* ctx, DIR* pdir);
+ long (*telldir)(DIR* pdir);
+ };
+ union {
+ void (*seekdir_p)(void* ctx, DIR* pdir, long offset);
+ void (*seekdir)(DIR* pdir, long offset);
+ };
+ union {
+ int (*closedir_p)(void* ctx, DIR* pdir);
+ int (*closedir)(DIR* pdir);
+ };
+ union {
+ int (*mkdir_p)(void* ctx, const char* name, mode_t mode);
+ int (*mkdir)(const char* name, mode_t mode);
+ };
+ union {
+ int (*rmdir_p)(void* ctx, const char* name);
+ int (*rmdir)(const char* name);
+ };
} esp_vfs_t;
--- /dev/null
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * This header file provides POSIX-compatible definitions of directory
+ * access functions and related data types.
+ * See http://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html
+ * for reference.
+ */
+
+/**
+ * @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 {
+ int 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
+ char d_name[256]; /*!< zero-terminated file name */
+};
+
+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);
+
}
+#define CHECK_AND_CALLV(r, pvfs, func, ...) \
+ if (pvfs->vfs.func == NULL) { \
+ __errno_r(r) = ENOSYS; \
+ return; \
+ } \
+ if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \
+ (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \
+ } else { \
+ (*pvfs->vfs.func)(__VA_ARGS__);\
+ }
+
+#define CHECK_AND_CALLP(ret, r, pvfs, func, ...) \
+ if (pvfs->vfs.func == NULL) { \
+ __errno_r(r) = ENOSYS; \
+ return NULL; \
+ } \
+ if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \
+ ret = (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \
+ } else { \
+ ret = (*pvfs->vfs.func)(__VA_ARGS__);\
+ }
+
int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode)
{
const vfs_entry_t* vfs = get_vfs_for_path(path);
CHECK_AND_CALL(ret, r, vfs, rename, src_within_vfs, dst_within_vfs);
return ret;
}
+
+DIR* opendir(const char* name)
+{
+ const vfs_entry_t* vfs = get_vfs_for_path(name);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ __errno_r(r) = ENOENT;
+ return NULL;
+ }
+ const char* path_within_vfs = translate_path(vfs, name);
+ DIR* ret;
+ CHECK_AND_CALLP(ret, r, vfs, opendir, path_within_vfs);
+ if (ret != NULL) {
+ ret->dd_vfs_idx = vfs->offset << VFS_INDEX_S;
+ }
+ return ret;
+}
+
+struct dirent* readdir(DIR* pdir)
+{
+ const vfs_entry_t* vfs = get_vfs_for_fd(pdir->dd_vfs_idx);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ __errno_r(r) = EBADF;
+ return NULL;
+ }
+ struct dirent* ret;
+ CHECK_AND_CALLP(ret, r, vfs, readdir, pdir);
+ return ret;
+}
+
+int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent)
+{
+ const vfs_entry_t* vfs = get_vfs_for_fd(pdir->dd_vfs_idx);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ int ret;
+ CHECK_AND_CALL(ret, r, vfs, readdir_r, pdir, entry, out_dirent);
+ return ret;
+}
+
+long telldir(DIR* pdir)
+{
+ const vfs_entry_t* vfs = get_vfs_for_fd(pdir->dd_vfs_idx);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ long ret;
+ CHECK_AND_CALL(ret, r, vfs, telldir, pdir);
+ return ret;
+}
+
+void seekdir(DIR* pdir, long loc)
+{
+ const vfs_entry_t* vfs = get_vfs_for_fd(pdir->dd_vfs_idx);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ errno = EBADF;
+ return;
+ }
+ CHECK_AND_CALLV(r, vfs, seekdir, pdir, loc);
+}
+
+void rewinddir(DIR* pdir)
+{
+ seekdir(pdir, 0);
+}
+
+int closedir(DIR* pdir)
+{
+ const vfs_entry_t* vfs = get_vfs_for_fd(pdir->dd_vfs_idx);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ int ret;
+ CHECK_AND_CALL(ret, r, vfs, closedir, pdir);
+ return ret;
+}
+
+int mkdir(const char* name, mode_t mode)
+{
+ const vfs_entry_t* vfs = get_vfs_for_path(name);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ __errno_r(r) = ENOENT;
+ return -1;
+ }
+ const char* path_within_vfs = translate_path(vfs, name);
+ int ret;
+ CHECK_AND_CALL(ret, r, vfs, mkdir, path_within_vfs, mode);
+ return ret;
+}
+
+int rmdir(const char* name)
+{
+ const vfs_entry_t* vfs = get_vfs_for_path(name);
+ struct _reent* r = __getreent();
+ if (vfs == NULL) {
+ __errno_r(r) = ENOENT;
+ return -1;
+ }
+ const char* path_within_vfs = translate_path(vfs, name);
+ int ret;
+ CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs);
+ return ret;
+}