mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
vfs: add directory APIs
This commit is contained in:
parent
3f889de5ab
commit
6fb430f45e
@ -1,13 +0,0 @@
|
|||||||
/* <dirent.h> includes <sys/dirent.h>, which is this file. On a
|
|
||||||
system which supports <dirent.h>, this file is overridden by
|
|
||||||
dirent.h in the libc/sys/.../sys directory. On a system which does
|
|
||||||
not support <dirent.h>, we will get this file which uses #error to force
|
|
||||||
an error. */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
#error "<dirent.h> not supported"
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -21,6 +21,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/reent.h>
|
#include <sys/reent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -106,6 +108,38 @@ typedef struct
|
|||||||
int (*rename_p)(void* ctx, const char *src, const char *dst);
|
int (*rename_p)(void* ctx, const char *src, const char *dst);
|
||||||
int (*rename)(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;
|
} esp_vfs_t;
|
||||||
|
|
||||||
|
|
||||||
|
55
components/vfs/include/sys/dirent.h
Normal file
55
components/vfs/include/sys/dirent.h
Normal file
@ -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 <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);
|
||||||
|
|
@ -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)
|
int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode)
|
||||||
{
|
{
|
||||||
const vfs_entry_t* vfs = get_vfs_for_path(path);
|
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);
|
CHECK_AND_CALL(ret, r, vfs, rename, src_within_vfs, dst_within_vfs);
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user