This is an automated email from the ASF dual-hosted git repository. yamamoto pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new b13f321 libc: Implement ftw and nftw function b13f321 is described below commit b13f3212ad3311880b0fb5b8503d91858ec99e2e Author: Xiang Xiao <xiaoxi...@xiaomi.com> AuthorDate: Tue Jul 28 16:05:02 2020 +0800 libc: Implement ftw and nftw function see the reference here: https://pubs.opengroup.org/onlinepubs/009695399/basedefs/ftw.h.html Signed-off-by: Xiang Xiao <xiaoxi...@xiaomi.com> Change-Id: I3b368106a56b0e9d4c653f3ae16304b0a9d55fbc --- include/ftw.h | 15 ++- libs/libc/dirent/Make.defs | 1 + libs/libc/dirent/lib_ftw.c | 39 ++++++ libs/libc/dirent/lib_nftw.c | 241 ++++++++++++++++++++++++++++++++++++++ libs/libc/libc.h | 4 + libs/libc/unistd/Make.defs | 2 +- libs/libc/unistd/lib_restoredir.c | 59 ++++++++++ 7 files changed, 356 insertions(+), 5 deletions(-) diff --git a/include/ftw.h b/include/ftw.h index 34fe454..d8b110a 100644 --- a/include/ftw.h +++ b/include/ftw.h @@ -58,8 +58,10 @@ #define FTW_MOUNT 2 /* The walk does not cross a mount point. */ #define FTW_DEPTH 4 /* All subdirectories are visited before the directory * itself. */ +#ifndef CONFIG_DISABLE_ENVIRON #define FTW_CHDIR 8 /* The walk changes to each directory before reading * it. */ +#endif /**************************************************************************** * Public Types @@ -67,7 +69,7 @@ /* The fourth argument of the ftw/nftw callback is a pointer to an FTW * structure. The value of base is the offset of the object's filename in - * the pathname passed as the first argument to the callbaqck. The value of + * the pathname passed as the first argument to the callback. The value of * level indicates depth relative to the root of the walk, where the root * level is 0. */ @@ -78,10 +80,15 @@ struct FTW int level; /* Depth relative to the root of the walk */ }; -/* This is the type of the ftw/nftw callback */ +/* This is the type of the ftw callback */ typedef int (*ftw_cb_t)(FAR const char *path, FAR const struct stat *buf, - int info, FAR struct FTW *pftw); + int info); + +/* This is the type of the nftw callback */ + +typedef int (*nftw_cb_t)(FAR const char *path, FAR const struct stat *buf, + int info, FAR struct FTW *pftw); /**************************************************************************** * Public Function Prototypes @@ -205,7 +212,7 @@ int ftw(FAR const char *path, ftw_cb_t fn, int fdlimit); * ****************************************************************************/ -int nftw(FAR const char *path, ftw_cb_t fn, int fdlimit, int flags); +int nftw(FAR const char *path, nftw_cb_t fn, int fdlimit, int flags); #undef EXTERN #ifdef __cplusplus diff --git a/libs/libc/dirent/Make.defs b/libs/libc/dirent/Make.defs index 60d7926..3ce3553 100644 --- a/libs/libc/dirent/Make.defs +++ b/libs/libc/dirent/Make.defs @@ -36,6 +36,7 @@ # Add the dirent C files to the build CSRCS += lib_readdirr.c lib_telldir.c lib_alphasort.c lib_scandir.c +CSRCS += lib_ftw.c lib_nftw.c # Add the dirent directory to the build diff --git a/libs/libc/dirent/lib_ftw.c b/libs/libc/dirent/lib_ftw.c new file mode 100644 index 0000000..4356c83 --- /dev/null +++ b/libs/libc/dirent/lib_ftw.c @@ -0,0 +1,39 @@ +/**************************************************************************** + * libs/libc/dirent/lib_ftw.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <ftw.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int ftw(FAR const char *path, ftw_cb_t fn, int fdlimit) +{ + /* The following cast assumes that calling a function with one + * argument more than it needs behaves as expected. This is + * actually undefined, but works on all real-world machines. + */ + + return nftw(path, (nftw_cb_t)fn, fdlimit, FTW_PHYS); +} diff --git a/libs/libc/dirent/lib_nftw.c b/libs/libc/dirent/lib_nftw.c new file mode 100644 index 0000000..34e5677 --- /dev/null +++ b/libs/libc/dirent/lib_nftw.c @@ -0,0 +1,241 @@ +/**************************************************************************** + * libs/libc/dirent/lib_nftw.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <ftw.h> +#include <dirent.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> + +#include "libc.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int +call_nftw(FAR char *path, nftw_cb_t fn, int flags, int base, + int level, FAR const struct stat *buf, int info) +{ + struct FTW ftw = + { + base, level + }; + + int r; + +#ifndef CONFIG_DISABLE_ENVIRON + if (flags & FTW_CHDIR) + { + if (base > 1) + { + path[base - 1] = '\0'; + r = chdir(path); + path[base - 1] = '/'; + } + else + { + r = chdir("/"); + } + + if (r < 0) + { + return r; + } + } +#endif + + r = fn(path, buf, info, &ftw); + +#ifndef CONFIG_DISABLE_ENVIRON + if (flags & FTW_CHDIR) + { + lib_restoredir(); + } +#endif + + return r; +} + +static int +do_nftw(FAR char *path, nftw_cb_t fn, int fdlimit, int flags, int level) +{ + FAR DIR *dir = NULL; + struct stat buf; + size_t base; + size_t j; + int info; + int r; + + j = strlen(path); + while (j > 1 && path[j - 1] == '/') + { + path[--j] = '\0'; + } + + base = j - 1; + while (base > 0 && path[base - 1] != '/') + { + --base; + } + + r = flags & FTW_PHYS ? lstat(path, &buf) : stat(path, &buf); + if (r < 0) + { + if (!(flags & FTW_PHYS) && + get_errno() == ENOENT && !lstat(path, &buf)) + { + info = FTW_SLN; + } + else if (get_errno() == EACCES) + { + info = FTW_NS; + } + else + { + return -1; + } + } + else if (S_ISDIR(buf.st_mode)) + { + if (flags & FTW_DEPTH) + { + info = FTW_DP; + } + else + { + info = FTW_D; + } + } + else if (S_ISLNK(buf.st_mode)) + { + if (flags & FTW_PHYS) + { + info = FTW_SL; + } + else + { + info = FTW_SLN; + } + } + else + { + info = FTW_F; + } + + if (info == FTW_D || info == FTW_DP) + { + dir = opendir(path); + if (dir) + { + if (fdlimit <= 0) + { + closedir(dir); + dir = NULL; + } + } + else if (get_errno() == EACCES) + { + info = FTW_DNR; + } + else + { + return -1; + } + } + + if (!(flags & FTW_DEPTH)) + { + r = call_nftw(path, fn, flags, base, level, &buf, info); + if (r) + { + return r; + } + } + + if (dir) + { + FAR struct dirent *de; + size_t l = j; + + if (path[j - 1] != '/') + { + path[j++] = '/'; + } + + while ((de = readdir(dir))) + { + if (de->d_name[0] == '.' && (!de->d_name[1] || + (de->d_name[1] == '.' && !de->d_name[2]))) + { + continue; + } + + if (strlen(de->d_name) > PATH_MAX - j) + { + set_errno(ENAMETOOLONG); + closedir(dir); + return -1; + } + + strcpy(path + j, de->d_name); + r = do_nftw(path, fn, fdlimit - 1, flags, level + 1); + if (r) + { + closedir(dir); + return r; + } + } + + path[l] = '\0'; + closedir(dir); + } + + if (flags & FTW_DEPTH) + { + r = call_nftw(path, fn, flags, base, level, &buf, info); + if (r) + { + return r; + } + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int nftw(FAR const char *path, nftw_cb_t fn, int fdlimit, int flags) +{ + char pathbuf[PATH_MAX + 1]; + + strncpy(pathbuf, path, PATH_MAX); + pathbuf[PATH_MAX] = '\0'; + + return do_nftw(pathbuf, fn, fdlimit, flags, 0); +} diff --git a/libs/libc/libc.h b/libs/libc/libc.h index 49a9b07..d8fe9c6 100644 --- a/libs/libc/libc.h +++ b/libs/libc/libc.h @@ -217,6 +217,10 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host, FAR char *buf, size_t buflen); #endif +#ifndef CONFIG_DISABLE_ENVIRON +int lib_restoredir(void); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs index 60527c3..1b9f04f 100644 --- a/libs/libc/unistd/Make.defs +++ b/libs/libc/unistd/Make.defs @@ -47,7 +47,7 @@ CSRCS += lib_setuid.c lib_setgid.c lib_getuid.c lib_getgid.c endif ifneq ($(CONFIG_DISABLE_ENVIRON),y) -CSRCS += lib_chdir.c lib_getcwd.c +CSRCS += lib_chdir.c lib_getcwd.c lib_restoredir.c endif ifeq ($(CONFIG_LIBC_EXECFUNCS),y) diff --git a/libs/libc/unistd/lib_restoredir.c b/libs/libc/unistd/lib_restoredir.c new file mode 100644 index 0000000..13fa3b6 --- /dev/null +++ b/libs/libc/unistd/lib_restoredir.c @@ -0,0 +1,59 @@ +/**************************************************************************** + * libs/libc/unistd/lib_restoredir.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "libc.h" + +#ifndef CONFIG_DISABLE_ENVIRON + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_restoredir + ****************************************************************************/ + +int lib_restoredir(void) +{ + char *oldpwd; + int ret = OK; + + oldpwd = getenv("OLDPWD"); + if (oldpwd) + { + oldpwd = strdup(oldpwd); /* kludge needed because environment is realloc'ed */ + ret = setenv("PWD", oldpwd, TRUE); + lib_free(oldpwd); + } + + return ret; +} + +#endif /* !CONFIG_DISABLE_ENVIRON */