From 6fb430f45eb6aa81f2066995442ee83cdeba203f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 3 Jan 2017 03:26:25 +0800 Subject: [PATCH] vfs: add directory APIs --- components/newlib/include/sys/dirent.h | 13 --- components/vfs/include/esp_vfs.h | 34 +++++++ components/vfs/include/sys/dirent.h | 55 ++++++++++ components/vfs/vfs.c | 135 +++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 13 deletions(-) delete mode 100644 components/newlib/include/sys/dirent.h create mode 100644 components/vfs/include/sys/dirent.h diff --git a/components/newlib/include/sys/dirent.h b/components/newlib/include/sys/dirent.h deleted file mode 100644 index a3fb5c02c..000000000 --- a/components/newlib/include/sys/dirent.h +++ /dev/null @@ -1,13 +0,0 @@ -/* includes , which is this file. On a - system which supports , this file is overridden by - dirent.h in the libc/sys/.../sys directory. On a system which does - not support , we will get this file which uses #error to force - an error. */ - -#ifdef __cplusplus -extern "C" { -#endif -#error " not supported" -#ifdef __cplusplus -} -#endif diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 5d9236b54..304750aab 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -21,6 +21,8 @@ #include #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -106,6 +108,38 @@ typedef struct 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; diff --git a/components/vfs/include/sys/dirent.h b/components/vfs/include/sys/dirent.h new file mode 100644 index 000000000..57b5be5ee --- /dev/null +++ b/components/vfs/include/sys/dirent.h @@ -0,0 +1,55 @@ +// 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 +#include + +/** + * 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); + diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index b166a427b..d80972a53 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -163,6 +163,28 @@ static const vfs_entry_t* get_vfs_for_path(const char* path) } +#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); @@ -309,3 +331,116 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) 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; +}