ftw.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:7k
- /*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- #define HAVE_DIRENT 1
- #define HAVE_SYMLINK 1
- #ifdef HAVE_DIRENT
- #include <dirent.h>
- #else
- #include <sys/dir.h>
- #endif
- #include <errno.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <sys/stat.h>
- #include "ftw.h"
- #if !HAS_FTW
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)ftw.c 5.3 (Berkeley) 8/5/88";
- #endif /* LIBC_SCCS and not lint */
- /* #include "../src/config.h" */
- #define NODESC -1
- #ifdef HAVE_SYMLINK
- # define ISLINK(sb) ((sb.st_mode&S_IFMT) == S_IFLNK)
- #else
- # define lstat stat
- #endif
- #define ISDIR(sb) ((sb.st_mode&S_IFMT) == S_IFDIR)
- #define ISDOT(dp)
- (dp->d_name[0] == '.' && (!dp->d_name[1] ||
- (dp->d_name[1] == '.' && !dp->d_name[2])))
- extern int errno;
- static int g_fds,
- (*g_fn) (),
- g_opts;
- static char *bp;
- #ifdef __STDC__
- int treewalk(const char *path, int (*fn) (const char *file, const struct stat *sb, int flag), int maxfds, int opts);
- #else
- int treewalk();
- #endif
- /*
- * cycle through the directories at the top of the tree, otherwise, once
- * you run out of descriptors you have to keep reusing the same one and
- * it gets *real* slow.
- */
- typedef struct d_fd {
- struct d_fd *next;
- DIR *dirp;
- off_t off;
- } FD;
- static FD *freep,
- *node;
- static int
- walk(register char *name)
- {
- #ifdef HAVE_DIRENT
- register struct dirent *dp;
- #else
- register struct direct *dp;
- #endif
- register int rval;
- struct stat sb;
- FD cur;
- char *save,
- #ifdef __STDC__
- *strcpy(char *, const char *);
- #else
- *strcpy();
- #endif
- if (!freep)
- freep = &cur;
- else
- node->next = &cur;
- node = &cur;
- cur.off = 0;
- getfd:if (!g_fds) {
- freep->off = telldir(freep->dirp);
- closedir(freep->dirp);
- freep = freep->next;
- ++g_fds;
- }
- if ( !(cur.dirp = opendir(bp)) ) {
- if (errno == EMFILE) {
- g_fds = 0;
- goto getfd;
- }
- return (errno == EACCES ? (*g_fn) (bp, &sb, FTW_DNR) : -1);
- } else
- --g_fds;
- for (; *name; ++name) ;
- *name++ = '/';
- for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
- if (ISDOT(dp))
- continue;
- (void) strcpy(name, dp->d_name);
- if (lstat(bp, &sb)) {
- rval = errno == EACCES ?
- (*g_fn) (bp, &sb, FTW_NS) : -1;
- if (rval)
- break;
- }
- #ifdef HAVE_SYMLINK
- if (ISLINK(sb) && g_opts & FTW_SYMLINK)
- if (stat(bp, &sb))
- continue;
- #endif
- if (!ISDIR(sb)) {
- rval = (*g_fn) (bp, &sb, FTW_F);
- if (rval)
- break;
- continue;
- }
- if (g_opts & FTW_DIRLAST)
- #ifdef HAVE_D_NAMLEN
- save = name + dp->d_namlen;
- #else
- save = name + strlen(dp->d_name);
- #endif
- rval = (*g_fn) (bp, &sb, FTW_D);
- if ( (rval && rval != NODESC) || (rval = walk(name)))
- break;
- if (g_opts & FTW_DIRLAST) {
- *save = ' ';
- rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
- if (rval)
- if (rval == NODESC)
- rval = 0;
- else
- break;
- }
- if (cur.off) {
- *name = ' ';
- if ( (cur.dirp = opendir(bp)) ) {
- seekdir(cur.dirp, cur.off);
- /* tricky; if we have to reset the directory pointer we know
- * it's the next one to reuse */
- freep = &cur;
- --g_fds;
- }
- /* directory moved from under us!!! */
- else {
- rval = -1;
- break;
- }
- }
- }
- closedir(cur.dirp);
- ++g_fds;
- return (rval);
- }
- static int
- chwalk(register const char *name)
- {
- #ifdef HAVE_DIRENT
- register struct dirent *dp;
- #else
- register struct direct *dp;
- #endif
- register int rval;
- struct stat sb;
- FD cur;
- char *pwd,
- *getwd(char *),
- #ifndef NO_MALLOC_PROTO
- *malloc(size_t),
- #endif
- *strcpy(char *, const char *);
- if (!freep)
- freep = &cur;
- else
- node->next = &cur;
- node = &cur;
- cur.off = 0;
- if (chdir(name))
- return (errno == EACCES ? (*g_fn) (name, &sb, FTW_DNR) : -1);
- getfd:if (!g_fds) {
- freep->off = telldir(freep->dirp);
- closedir(freep->dirp);
- freep = freep->next;
- ++g_fds;
- }
- if ( !(cur.dirp = opendir(".")) ) {
- if (errno == EMFILE) {
- g_fds = 0;
- goto getfd;
- }
- return (errno == EACCES ? (*g_fn) (".", &sb, FTW_DNR) : -1);
- } else
- --g_fds;
- for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
- if (ISDOT(dp))
- continue;
- if (lstat(dp->d_name, &sb)) {
- rval = errno == EACCES ?
- (*g_fn) (dp->d_name, &sb, FTW_NS) : -1;
- if (rval)
- break;
- }
- pwd = NULL;
- #ifdef HAVE_SYMLINK
- if (ISLINK(sb) && g_opts & FTW_SYMLINK) {
- if (stat(dp->d_name, &sb))
- continue;
- if (ISDIR(sb)) {
- /* NOSTRICT */
- if (!(pwd = malloc((u_int) MAXPATHLEN))) {
- rval = -1;
- break;
- }
- if (!getwd(pwd)) {
- rval = -1;
- break;
- }
- }
- }
- #endif
- if (!ISDIR(sb)) {
- rval = (*g_fn) (dp->d_name, &sb, FTW_F);
- if (rval)
- break;
- continue;
- }
- rval = (*g_fn) (dp->d_name, &sb, FTW_D);
- if ((rval && rval != NODESC) || (rval = chwalk(dp->d_name)))
- break;
- if (g_opts & FTW_DIRLAST) {
- rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
- if (rval)
- if (rval == NODESC)
- rval = 0;
- else
- break;
- }
- if (pwd && chdir(pwd)) {
- rval = -1;
- break;
- }
- if (cur.off) {
- if ( (cur.dirp = opendir(".")) ) {
- seekdir(cur.dirp, cur.off);
- /* tricky; if we have to reset the directory pointer we know
- * it's the next one to reuse */
- freep = &cur;
- --g_fds;
- }
- /* directory moved from under us!!! */
- else {
- rval = -1;
- break;
- }
- }
- }
- closedir(cur.dirp);
- ++g_fds;
- if (chdir(".."))
- return (-1);
- return (rval);
- }
- /* S5 compatible ftw(BA_LIB) */
- int
- ftw(const char *path, int (*fn) (const char *file, const struct stat *sb, int flag), int maxfds)
- {
- return (treewalk(path, fn, maxfds, 0));
- }
- int
- treewalk(const char *path, int (*fn) (const char *file, const struct stat *sb, int flag), int maxfds, int opts)
- {
- struct stat sb;
- int rval;
- char *pwd,
- *getwd(char *),
- #ifndef NO_MALLOC_PROTO
- *malloc(size_t),
- #endif
- *strcpy(char *, const char *);
- if (lstat(path, &sb))
- return (errno == EACCES ? (*fn) (path, &sb, FTW_NS) : -1);
- pwd = NULL;
- #ifdef HAVE_SYMLINK
- if (ISLINK(sb) && opts & FTW_SYMLINK) {
- if (stat(path, &sb))
- return (0);
- if (ISDIR(sb)) {
- /* NOSTRICT */
- if (!(pwd = malloc((u_int) MAXPATHLEN)))
- return (-1);
- if (!getwd(pwd))
- return (-1);
- }
- }
- #endif
- if (!ISDIR(sb))
- return ((*fn) (path, &sb, FTW_F));
- if (!maxfds)
- return (-1);
- g_fds = maxfds == -1 ? getdtablesize(): maxfds;
- g_fn = fn;
- g_opts = opts;
- if (!(opts & FTW_CHDIR) && !(bp = malloc((u_int) MAXPATHLEN))) {
- errno = ENOMEM;
- return (-1);
- }
- rval = (*fn) (path, &sb, FTW_D);
- if (rval == NODESC)
- rval = 0;
- else if (!rval) {
- if (opts & FTW_CHDIR)
- rval = chwalk(path);
- else
- rval = walk(strcpy(bp, path));
- if (!rval && opts & FTW_DIRLAST) {
- rval = (*fn) (path, &sb, FTW_D2);
- if (rval == NODESC)
- rval = 0;
- }
- }
- if (pwd && chdir(pwd))
- return (-1);
- return (rval);
- }
- #endif