This is ftw.c in view mode; [Download] [Up]
/* * 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. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)ftw.c 5.3 (Berkeley) 8/5/88"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> #include <sys/dir.h> #include <sys/stat.h> #include <errno.h> #include "ftw.h" #define NODESC -1 #define ISLINK(sb) ((sb.st_mode&S_IFMT) == S_IFLNK) #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; /* S5 compatible ftw(BA_LIB) */ ftw(path, fn, maxfds) char *path; int (*fn)(), maxfds; { return(treewalk(path, fn, maxfds, 0)); } treewalk(path, fn, maxfds, opts) char *path; int (*fn)(), maxfds, opts; { struct stat sb; int rval; char *pwd, *getwd(), *malloc(), *strcpy(); if (lstat(path, &sb)) return(errno == EACCES ? (*fn)(path, &sb, FTW_NS) : -1); pwd = NULL; 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); } } 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); } /* * 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 walk(name) register char *name; { register struct direct *dp; register int rval; struct stat sb; FD cur; char *save, *strcpy(); 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; } if (ISLINK(sb) && g_opts&FTW_SYMLINK) if (stat(bp, &sb)) continue; if (!ISDIR(sb)) { rval = (*g_fn)(bp, &sb, FTW_F); if (rval) break; continue; } if (g_opts&FTW_DIRLAST) save = name + dp->d_namlen; rval = (*g_fn)(bp, &sb, FTW_D); if (rval && rval != NODESC || (rval = walk(name))) break; if (g_opts&FTW_DIRLAST) { *save = '\0'; rval = (*g_fn)(dp->d_name, &sb, FTW_D2); if (rval) if (rval == NODESC) rval = 0; else break; } if (cur.off) { *name = NULL; 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 chwalk(name) register char *name; { register struct direct *dp; register int rval; struct stat sb; FD cur; char *pwd, *getwd(), *malloc(), *strcpy(); 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; 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; } } } 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); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.