142273Sbostic /*- 242273Sbostic * Copyright (c) 1990 The Regents of the University of California. 339800Sbostic * All rights reserved. 439800Sbostic * 542273Sbostic * %sccs.include.redist.c% 639800Sbostic */ 739800Sbostic 839800Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*47194Sbostic static char sccsid[] = "@(#)fts.c 5.14 (Berkeley) 03/10/91"; 1039800Sbostic #endif /* LIBC_SCCS and not lint */ 1139800Sbostic 12*47194Sbostic #include <sys/cdefs.h> 1339800Sbostic #include <sys/param.h> 1439800Sbostic #include <sys/stat.h> 1542299Sbostic #include <fcntl.h> 1639800Sbostic #include <dirent.h> 1739800Sbostic #include <errno.h> 18*47194Sbostic #include "fts.h" 19*47194Sbostic #include <stdlib.h> 2042273Sbostic #include <string.h> 2147155Sbostic #include <unistd.h> 2239800Sbostic 23*47194Sbostic static FTSENT *fts_alloc(), *fts_build(), *fts_sort(); 24*47194Sbostic static void fts_lfree(); 25*47194Sbostic static int fts_load(); 2647155Sbostic static u_short fts_stat(); 2747155Sbostic static char *fts_path(); 2839800Sbostic 2945600Sbostic #define ISSET(opt) (sp->fts_options & opt) 3045600Sbostic #define SET(opt) (sp->fts_options |= opt) 3139800Sbostic 3245600Sbostic #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) 3345600Sbostic #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 3439800Sbostic 3542299Sbostic /* fts_build flags */ 3645600Sbostic #define BCHILD 1 /* from fts_children */ 3745600Sbostic #define BREAD 2 /* from fts_read */ 3842299Sbostic 3945600Sbostic /* fts_level values */ 40*47194Sbostic #define ROOTLEVEL 0 4145600Sbostic #define ROOTPARENTLEVEL -1 4239800Sbostic 4339800Sbostic FTS * 4445600Sbostic fts_open(argv, options, compar) 4547155Sbostic char * const *argv; 4639800Sbostic register int options; 47*47194Sbostic int (*compar)(); 4839800Sbostic { 4939800Sbostic register FTS *sp; 5039800Sbostic register FTSENT *p, *root; 5139800Sbostic register int nitems, maxlen; 5239800Sbostic FTSENT *parent, *tmp; 53*47194Sbostic int len; 5439800Sbostic 5545600Sbostic /* Allocate/initialize the stream */ 5645600Sbostic if (!(sp = (FTS *)malloc((u_int)sizeof(FTS)))) 5739800Sbostic return(NULL); 5839800Sbostic bzero(sp, sizeof(FTS)); 5942273Sbostic sp->fts_compar = compar; 6042273Sbostic sp->fts_options = options; 6139800Sbostic 6245600Sbostic /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 6345600Sbostic if (ISSET(FTS_LOGICAL)) 6445600Sbostic SET(FTS_NOCHDIR); 6545600Sbostic 6645600Sbostic /* Allocate/initialize root's parent. */ 6745600Sbostic if (!(parent = fts_alloc(sp, "", 0))) 6839800Sbostic goto mem1; 6942273Sbostic parent->fts_level = ROOTPARENTLEVEL; 7039800Sbostic 7145600Sbostic /* Allocate/initialize root(s). */ 7243070Sbostic maxlen = -1; 7343070Sbostic for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { 74*47194Sbostic if (!(len = strlen(*argv))) { 75*47194Sbostic errno = ENOENT; 7643070Sbostic goto mem2; 77*47194Sbostic } 78*47194Sbostic if (maxlen < len) 79*47194Sbostic maxlen = len; 80*47194Sbostic p = fts_alloc(sp, *argv, len); 8143070Sbostic /* 8245600Sbostic * If comparison routine supplied, traverse in sorted 8343070Sbostic * order; otherwise traverse in the order specified. 8443070Sbostic */ 8543070Sbostic if (compar) { 8643070Sbostic p->fts_link = root; 8743070Sbostic root = p; 8843070Sbostic p->fts_accpath = p->fts_name; 8943075Sbostic if (!(options & FTS_NOSTAT)) 9045600Sbostic p->fts_info = fts_stat(sp, p, 0); 9143070Sbostic } else { 9243070Sbostic p->fts_link = NULL; 9343070Sbostic if (!root) 9443070Sbostic tmp = root = p; 9543070Sbostic else { 9643070Sbostic tmp->fts_link = p; 9743070Sbostic tmp = p; 9839800Sbostic } 9939800Sbostic } 10043070Sbostic p->fts_level = ROOTLEVEL; 10143070Sbostic p->fts_parent = parent; 10239800Sbostic } 10343070Sbostic if (compar && nitems > 1) 10445600Sbostic root = fts_sort(sp, root, nitems); 10539800Sbostic 10642281Sbostic /* 10745600Sbostic * Allocate a dummy pointer and make fts_read think that we've just 10842281Sbostic * finished the node before the root(s); set p->fts_info to FTS_NS 10942281Sbostic * so that everything about the "current" node is ignored. 11042281Sbostic */ 11145600Sbostic if (!(sp->fts_cur = fts_alloc(sp, "", 0))) 11242281Sbostic goto mem2; 11342281Sbostic sp->fts_cur->fts_link = root; 11442281Sbostic sp->fts_cur->fts_info = FTS_NS; 11542281Sbostic 11645600Sbostic /* Start out with at least 1K+ of path space. */ 11745600Sbostic if (!fts_path(sp, MAX(maxlen, MAXPATHLEN))) 11842281Sbostic goto mem3; 11939800Sbostic 12039800Sbostic /* 12145600Sbostic * If using chdir(2), grab a file descriptor pointing to dot to insure 12242299Sbostic * that we can get back here; this could be avoided for some paths, 12342299Sbostic * but almost certainly not worth the effort. Slashes, symbolic links, 12442299Sbostic * and ".." are all fairly nasty problems. Note, if we can't get the 12542299Sbostic * descriptor we run anyway, just more slowly. 12639800Sbostic */ 127*47194Sbostic if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) 12845600Sbostic SET(FTS_NOCHDIR); 12939800Sbostic 13039800Sbostic return(sp); 13139800Sbostic 132*47194Sbostic mem3: free(sp->fts_cur); 13339800Sbostic mem2: fts_lfree(root); 134*47194Sbostic free(parent); 135*47194Sbostic mem1: free(sp); 13639800Sbostic return(NULL); 13739800Sbostic } 13839800Sbostic 139*47194Sbostic static 14045600Sbostic fts_load(sp, p) 14145600Sbostic FTS *sp; 14239800Sbostic register FTSENT *p; 14339800Sbostic { 144*47194Sbostic static int need_to_cd; 14539800Sbostic register int len; 14639800Sbostic register char *cp; 14739800Sbostic 14839800Sbostic /* 149*47194Sbostic * If changing the root level node, load the stream structure for the 150*47194Sbostic * next traversal; set the fts_accpath field specially so the chdir 151*47194Sbostic * gets done to the right place and the user can access the first node. 15239800Sbostic */ 15342273Sbostic len = p->fts_pathlen = p->fts_namelen; 15445600Sbostic bcopy(p->fts_name, sp->fts_path, len + 1); 15542273Sbostic if ((cp = rindex(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 15639800Sbostic len = strlen(++cp); 15742273Sbostic bcopy(cp, p->fts_name, len + 1); 15842273Sbostic p->fts_namelen = len; 15939800Sbostic } 16045600Sbostic p->fts_accpath = p->fts_path = sp->fts_path; 161*47194Sbostic 162*47194Sbostic sp->rdev = p->fts_statb.st_dev; 163*47194Sbostic 164*47194Sbostic /* 165*47194Sbostic * If not the first time, and it's not an absolute pathname, get back 166*47194Sbostic * to starting directory. If that fails, we're dead. 167*47194Sbostic */ 168*47194Sbostic if (need_to_cd && p->fts_path[0] != '/' && FCHDIR(sp, sp->fts_rfd)) 169*47194Sbostic return(0); 170*47194Sbostic need_to_cd = 1; 171*47194Sbostic 172*47194Sbostic /* 173*47194Sbostic * Special case error condition -- if we can't find the root of the 174*47194Sbostic * traversal, make sure the user notices the error. 175*47194Sbostic */ 176*47194Sbostic if ((p->fts_info = fts_stat(sp, p, 0)) == FTS_NS) 177*47194Sbostic p->fts_info = FTS_ERR; 178*47194Sbostic return(1); 17939800Sbostic } 18039800Sbostic 18145600Sbostic fts_close(sp) 18239800Sbostic FTS *sp; 18339800Sbostic { 18439800Sbostic register FTSENT *freep, *p; 18539800Sbostic int saved_errno; 18639800Sbostic 18742281Sbostic if (sp->fts_cur) { 18842281Sbostic /* 18945600Sbostic * This still works if we haven't read anything -- the dummy 19042281Sbostic * structure points to the root list, so we step through to 19142281Sbostic * the end of the root list which has a valid parent pointer. 19242281Sbostic */ 19342281Sbostic for (p = sp->fts_cur; p->fts_level > ROOTPARENTLEVEL;) { 19442281Sbostic freep = p; 19542281Sbostic p = p->fts_link ? p->fts_link : p->fts_parent; 196*47194Sbostic free(freep); 19739800Sbostic } 198*47194Sbostic free(p); 19942281Sbostic } 20039800Sbostic 20145600Sbostic /* Free up child linked list, sort array, path buffer. */ 20242273Sbostic if (sp->fts_child) 20342273Sbostic fts_lfree(sp->fts_child); 20442273Sbostic if (sp->fts_array) 205*47194Sbostic free(sp->fts_array); 206*47194Sbostic free(sp->fts_path); 20739800Sbostic 208*47194Sbostic /* Return to original directory, save errno if necessary. */ 20945600Sbostic if (!ISSET(FTS_NOCHDIR)) { 210*47194Sbostic saved_errno = fchdir(sp->fts_rfd) ? errno : 0; 211*47194Sbostic (void)close(sp->fts_rfd); 21239800Sbostic } 21339800Sbostic 21445600Sbostic /* Free up the stream pointer. */ 215*47194Sbostic free(sp); 21639800Sbostic 21745600Sbostic /* Set errno and return. */ 21845600Sbostic if (!ISSET(FTS_NOCHDIR) && saved_errno) { 21939800Sbostic errno = saved_errno; 22039800Sbostic return(-1); 22139800Sbostic } 22239800Sbostic return(0); 22339800Sbostic } 22439800Sbostic 225*47194Sbostic /* 226*47194Sbostic * Special case a root of "/" so that slashes aren't appended causing 227*47194Sbostic * paths to be written as "//foo". 228*47194Sbostic */ 229*47194Sbostic #define NAPPEND(p) \ 230*47194Sbostic (p->fts_level == ROOTLEVEL && p->fts_pathlen == 1 && \ 231*47194Sbostic p->fts_path[0] == '/' ? 0 : p->fts_pathlen) 232*47194Sbostic 23339800Sbostic FTSENT * 23445600Sbostic fts_read(sp) 23539800Sbostic register FTS *sp; 23639800Sbostic { 23742299Sbostic register FTSENT *p, *tmp; 23839800Sbostic register int instr; 239*47194Sbostic register char *t; 24039800Sbostic 24145600Sbostic /* If finished or unrecoverable error, return NULL. */ 242*47194Sbostic if (!sp->fts_cur || ISSET(FTS_STOP)) 24339800Sbostic return(NULL); 24439800Sbostic 24545600Sbostic /* Set current node pointer. */ 24642273Sbostic p = sp->fts_cur; 24739800Sbostic 24845600Sbostic /* Save and zero out user instructions. */ 24942273Sbostic instr = p->fts_instr; 250*47194Sbostic p->fts_instr = FTS_NOINSTR; 25139800Sbostic 25245600Sbostic /* If used fts_link pointer for cycle detection, restore it. */ 25342273Sbostic if (sp->fts_savelink) { 25442273Sbostic p->fts_link = sp->fts_savelink; 25542273Sbostic sp->fts_savelink = NULL; 25639800Sbostic } 25739800Sbostic 258*47194Sbostic /* Any type of file may be re-visited; re-stat and re-turn. */ 25939800Sbostic if (instr == FTS_AGAIN) { 26045600Sbostic p->fts_info = fts_stat(sp, p, 0); 26139800Sbostic return(p); 26239800Sbostic } 26339800Sbostic 264*47194Sbostic /* 265*47194Sbostic * Following a symlink -- SLNONE test allows application to see 266*47194Sbostic * SLNONE and recover. 267*47194Sbostic */ 268*47194Sbostic if (instr == FTS_FOLLOW && 269*47194Sbostic (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 27045600Sbostic p->fts_info = fts_stat(sp, p, 1); 27142299Sbostic return(p); 27242299Sbostic } 27342299Sbostic 27445600Sbostic /* Directory in pre-order. */ 27542299Sbostic if (p->fts_info == FTS_D) { 27645600Sbostic /* If skipped or crossed mount point, do post-order visit. */ 277*47194Sbostic if (instr == FTS_SKIP || 278*47194Sbostic ISSET(FTS_XDEV) && p->fts_statb.st_dev != sp->rdev) { 27942273Sbostic if (sp->fts_child) { 28042273Sbostic fts_lfree(sp->fts_child); 28142273Sbostic sp->fts_child = NULL; 28239800Sbostic } 28342301Sbostic p->fts_info = FTS_DP; 28442301Sbostic return(p); 28542299Sbostic } 28642299Sbostic 287*47194Sbostic /* 288*47194Sbostic * Cd to the subdirectory, reading it if haven't already. If 289*47194Sbostic * the read fails for any reason, or the directory is empty, 290*47194Sbostic * the fts_info field of the current node is set by fts_build. 291*47194Sbostic * If have already read and fail to chdir, do some quick 292*47194Sbostic * whacking to make the names come out right, and set the 293*47194Sbostic * parent state so the application will eventually get an 294*47194Sbostic * error condition. 295*47194Sbostic */ 296*47194Sbostic if (sp->fts_child) { 29742299Sbostic if (CHDIR(sp, p->fts_accpath)) { 298*47194Sbostic p->fts_parent->fts_cderr = errno; 299*47194Sbostic for (p = sp->fts_child; p; p = p->fts_link) 300*47194Sbostic p->fts_accpath = 301*47194Sbostic p->fts_parent->fts_accpath; 30242299Sbostic } 303*47194Sbostic } else if (!(sp->fts_child = fts_build(sp, BREAD))) 304*47194Sbostic return(ISSET(FTS_STOP) ? NULL : p); 305*47194Sbostic p = sp->fts_child; 30642299Sbostic sp->fts_child = NULL; 307*47194Sbostic goto name; 30839800Sbostic } 30939800Sbostic 31045600Sbostic /* Move to next node on this level. */ 31142299Sbostic next: tmp = p; 31242299Sbostic if (p = p->fts_link) { 313*47194Sbostic free(tmp); 314*47194Sbostic 315*47194Sbostic /* If reached the top, load the paths for the next root. */ 31642273Sbostic if (p->fts_level == ROOTLEVEL) { 317*47194Sbostic if (!fts_load(sp, p)) { 318*47194Sbostic SET(FTS_STOP); 319*47194Sbostic return(NULL); 32042299Sbostic } 321*47194Sbostic return(sp->fts_cur = p); 322*47194Sbostic } 32342299Sbostic 324*47194Sbostic /* User may have called fts_set on the node. */ 325*47194Sbostic if (p->fts_instr == FTS_SKIP) 326*47194Sbostic goto next; 327*47194Sbostic if (p->fts_instr == FTS_FOLLOW) { 328*47194Sbostic p->fts_info = fts_stat(sp, p, 1); 329*47194Sbostic p->fts_instr = FTS_NOINSTR; 330*47194Sbostic } 33142299Sbostic 332*47194Sbostic name: t = sp->fts_path + NAPPEND(p->fts_parent); 333*47194Sbostic *t++ = '/'; 334*47194Sbostic bcopy(p->fts_name, t, p->fts_namelen + 1); 33542273Sbostic return(sp->fts_cur = p); 33639800Sbostic } 33739800Sbostic 33845600Sbostic /* Move to parent. */ 33942299Sbostic p = tmp->fts_parent; 340*47194Sbostic free(tmp); 34142299Sbostic 34242273Sbostic if (p->fts_level == ROOTPARENTLEVEL) { 34339800Sbostic /* 34445600Sbostic * Done; free everything up and set errno to 0 so the user 34539800Sbostic * can distinguish between error and EOF. 34639800Sbostic */ 347*47194Sbostic free(p); 34839800Sbostic errno = 0; 34942273Sbostic return(sp->fts_cur = NULL); 35039800Sbostic } 35139800Sbostic 35242273Sbostic sp->fts_path[p->fts_pathlen] = '\0'; 353*47194Sbostic 354*47194Sbostic /* 355*47194Sbostic * If had a chdir error, set the info field to reflect this, and 356*47194Sbostic * restore errno. The error indicator has to be reset to 0 so that 357*47194Sbostic * if the user does an FTS_AGAIN, it all works. Can't cd up on 358*47194Sbostic * the post-order visit to the root node, otherwise will be in the 359*47194Sbostic * wrong directory. 360*47194Sbostic */ 361*47194Sbostic if (p->fts_cderr) { 362*47194Sbostic errno = p->fts_cderr; 363*47194Sbostic p->fts_cderr = 0; 36442273Sbostic p->fts_info = FTS_ERR; 365*47194Sbostic } else { 366*47194Sbostic if (p->fts_level != ROOTLEVEL && CHDIR(sp, "..")) { 367*47194Sbostic SET(FTS_STOP); 368*47194Sbostic return(NULL); 369*47194Sbostic } 37042273Sbostic p->fts_info = FTS_DP; 371*47194Sbostic } 37242273Sbostic return(sp->fts_cur = p); 37339800Sbostic } 37439800Sbostic 37539800Sbostic /* 37645600Sbostic * fts_set takes the stream as an argument although it's not used in this 37739800Sbostic * implementation; it would be necessary if anyone wanted to add global 37845600Sbostic * semantics to fts using fts_set. An error return is allowed for similar 37945600Sbostic * reasons. 38039800Sbostic */ 38139800Sbostic /* ARGSUSED */ 38245600Sbostic fts_set(sp, p, instr) 38339800Sbostic FTS *sp; 38439800Sbostic FTSENT *p; 38539800Sbostic int instr; 38639800Sbostic { 38742273Sbostic p->fts_instr = instr; 38839800Sbostic return(0); 38939800Sbostic } 39039800Sbostic 39139800Sbostic FTSENT * 39245600Sbostic fts_children(sp) 39339800Sbostic register FTS *sp; 39439800Sbostic { 39542299Sbostic register FTSENT *p; 39642299Sbostic int fd; 39742299Sbostic 39845600Sbostic /* Set current node pointer. */ 39945600Sbostic p = sp->fts_cur; 40045600Sbostic 40139800Sbostic /* 40245600Sbostic * Set errno to 0 so that user can tell the difference between an 403*47194Sbostic * error and a directory without entries. If not a directory being 404*47194Sbostic * visited in *pre-order*, or we've already had fatal errors, return 405*47194Sbostic * immediately. 40639800Sbostic */ 40739800Sbostic errno = 0; 408*47194Sbostic if (ISSET(FTS_STOP) || p->fts_info != FTS_D && p->fts_info != FTS_DNR) 40939800Sbostic return(NULL); 41045600Sbostic 41145600Sbostic /* Free up any previous child list. */ 41242273Sbostic if (sp->fts_child) 41342273Sbostic fts_lfree(sp->fts_child); 41442299Sbostic 41542299Sbostic /* 41645600Sbostic * If using chdir on a relative path and called BEFORE fts_read does 417*47194Sbostic * its chdir to the root of a traversal, we can lose -- we need to 418*47194Sbostic * chdir into the subdirectory, and we don't know where the current 419*47194Sbostic * directory is, so we can't get back so that the upcoming chdir by 420*47194Sbostic * fts_read will work. 42142299Sbostic */ 42242299Sbostic if (p->fts_level != ROOTLEVEL || p->fts_accpath[0] == '/' || 42345600Sbostic ISSET(FTS_NOCHDIR)) 42442299Sbostic return(sp->fts_child = fts_build(sp, BCHILD)); 42542299Sbostic 42642299Sbostic if ((fd = open(".", O_RDONLY, 0)) < 0) 42742299Sbostic return(NULL); 42842299Sbostic sp->fts_child = fts_build(sp, BCHILD); 42942299Sbostic if (fchdir(fd)) 43042299Sbostic return(NULL); 43142299Sbostic (void)close(fd); 43242299Sbostic return(sp->fts_child); 43339800Sbostic } 43439800Sbostic 435*47194Sbostic /* 436*47194Sbostic * This is the tricky part -- do not casually change *anything* in here. The 437*47194Sbostic * idea is to build the linked list of entries that are used by fts_children 438*47194Sbostic * and fts_read. There are lots of special cases. 439*47194Sbostic * 440*47194Sbostic * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 441*47194Sbostic * set and it's a physical walk (so that symbolic links can't be directories), 442*47194Sbostic * we assume that the number of subdirectories in a node is equal to the number 443*47194Sbostic * of links to the parent. This allows stat calls to be skipped in any leaf 444*47194Sbostic * directories and for any nodes after the directories in the parent node have 445*47194Sbostic * been found. This empirically cuts the stat calls by about 2/3. 446*47194Sbostic */ 44739800Sbostic #define ISDOT(a) (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2])) 44839800Sbostic 44947155Sbostic static FTSENT * 45042299Sbostic fts_build(sp, type) 45139800Sbostic register FTS *sp; 45242299Sbostic int type; 45339800Sbostic { 45439800Sbostic register struct dirent *dp; 45539800Sbostic register FTSENT *p, *head; 45639800Sbostic register int nitems; 457*47194Sbostic FTSENT *cur; 45839800Sbostic DIR *dirp; 459*47194Sbostic int cderr, descend, len, level, maxlen, nlinks, saved_errno; 46039800Sbostic char *cp; 46139800Sbostic 46245600Sbostic /* Set current node pointer. */ 463*47194Sbostic cur = sp->fts_cur; 46445600Sbostic 465*47194Sbostic /* 466*47194Sbostic * Open the directory for reading. If this fails, we're done. 467*47194Sbostic * If being called from fts_read, set the fts_info field. 468*47194Sbostic */ 469*47194Sbostic if (!(dirp = opendir(cur->fts_accpath))) { 470*47194Sbostic if (type == BREAD) 471*47194Sbostic cur->fts_info = FTS_DNR; 47239800Sbostic return(NULL); 47339800Sbostic } 47439800Sbostic 47539800Sbostic /* 476*47194Sbostic * Nlinks is the number of possible entries of type directory in the 477*47194Sbostic * directory if we're cheating on stat calls, 0 if we're not doing 478*47194Sbostic * any stat calls at all, -1 if we're doing stats on everything. 47939800Sbostic */ 48042273Sbostic nlinks = 48145600Sbostic ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL) ? 482*47194Sbostic cur->fts_statb.st_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2) : -1; 48339800Sbostic 484*47194Sbostic /* 485*47194Sbostic * If we're going to need to stat anything or we want to descend 486*47194Sbostic * and stay in the directory, chdir. If this fails we keep going. 487*47194Sbostic * We won't be able to stat anything, but we can still return the 488*47194Sbostic * names themselves. Note, that since fts_read won't be able to 489*47194Sbostic * chdir into the directory, it will have to return different path 490*47194Sbostic * names than before, i.e. "a/b" instead of "b". Since the node 491*47194Sbostic * has already been visited in pre-order, have to wait until the 492*47194Sbostic * post-order visit to return the error. This is all fairly nasty. 493*47194Sbostic * If a program needed sorted entries or stat information, they had 494*47194Sbostic * better be checking FTS_NS on the returned nodes. 495*47194Sbostic */ 49645600Sbostic if (nlinks || type == BREAD) 497*47194Sbostic if (FCHDIR(sp, dirfd(dirp))) { 498*47194Sbostic if (type == BREAD) 499*47194Sbostic cur->fts_cderr = errno; 500*47194Sbostic descend = nlinks = 0; 501*47194Sbostic cderr = 1; 502*47194Sbostic } else { 50345600Sbostic descend = 1; 504*47194Sbostic cderr = 0; 50539962Sbostic } 506*47194Sbostic else 507*47194Sbostic descend = 0; 50839962Sbostic 509*47194Sbostic /* 510*47194Sbostic * Figure out the max file name length that can be stored in the 511*47194Sbostic * current path -- the inner loop allocates more path as necessary. 512*47194Sbostic * We really wouldn't have to do the maxlen calculations here, we 513*47194Sbostic * could do them in fts_read before returning the path, but it's a 514*47194Sbostic * lot easier here since the length is part of the dirent structure. 515*47194Sbostic * 516*47194Sbostic * If not changing directories set a pointer so that we can just 517*47194Sbostic * append each new name into the path. 518*47194Sbostic */ 519*47194Sbostic maxlen = sp->fts_pathlen - cur->fts_pathlen - 1; 520*47194Sbostic len = NAPPEND(cur); 521*47194Sbostic if (ISSET(FTS_NOCHDIR)) { 522*47194Sbostic cp = sp->fts_path + len; 523*47194Sbostic *cp++ = '/'; 524*47194Sbostic } 52540939Sbostic 526*47194Sbostic level = cur->fts_level + 1; 52740939Sbostic 528*47194Sbostic /* Read the directory, attaching each entry to the `link' pointer. */ 52939800Sbostic for (head = NULL, nitems = 0; dp = readdir(dirp);) { 530*47194Sbostic if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 53139800Sbostic continue; 53239800Sbostic 533*47194Sbostic if (!(p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen))) 53439800Sbostic goto mem1; 53539800Sbostic if (dp->d_namlen > maxlen) { 53645600Sbostic if (!fts_path(sp, (int)dp->d_namlen)) { 537*47194Sbostic /* 538*47194Sbostic * No more memory for path or structures. Save 539*47194Sbostic * errno, free up the current structure and the 540*47194Sbostic * structures already allocated. 541*47194Sbostic */ 542*47194Sbostic mem1: saved_errno = errno; 543*47194Sbostic if (p) 544*47194Sbostic free(p); 545*47194Sbostic fts_lfree(head); 546*47194Sbostic (void)closedir(dirp); 54739800Sbostic errno = saved_errno; 548*47194Sbostic cur->fts_info = FTS_ERR; 549*47194Sbostic SET(FTS_STOP); 55039800Sbostic return(NULL); 55139800Sbostic } 55242273Sbostic maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1; 55339800Sbostic } 55439800Sbostic 55542273Sbostic p->fts_pathlen = len + dp->d_namlen + 1; 55642273Sbostic p->fts_parent = sp->fts_cur; 55742273Sbostic p->fts_level = level; 55839800Sbostic 55939800Sbostic if (nlinks) { 560*47194Sbostic /* Build a file name for fts_stat to stat. */ 561*47194Sbostic if (ISSET(FTS_NOCHDIR)) { 562*47194Sbostic p->fts_accpath = p->fts_path; 56342273Sbostic bcopy(p->fts_name, cp, p->fts_namelen + 1); 564*47194Sbostic } else 565*47194Sbostic p->fts_accpath = p->fts_name; 56645600Sbostic p->fts_info = fts_stat(sp, p, 0); 567*47194Sbostic if (nlinks > 0 && p->fts_info == FTS_D) 56839800Sbostic --nlinks; 569*47194Sbostic } else if (cderr) { 570*47194Sbostic p->fts_info = ISSET(FTS_NOSTAT) ? FTS_NSOK : FTS_NS; 571*47194Sbostic p->fts_accpath = cur->fts_accpath; 572*47194Sbostic } else { 573*47194Sbostic p->fts_accpath = 574*47194Sbostic ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 575*47194Sbostic p->fts_info = FTS_NSOK; 576*47194Sbostic } 57739800Sbostic 57842273Sbostic p->fts_link = head; 57939800Sbostic head = p; 58039800Sbostic ++nitems; 58139800Sbostic } 58239800Sbostic (void)closedir(dirp); 58339800Sbostic 584*47194Sbostic /* 585*47194Sbostic * If not changing directories, reset the path back to original 586*47194Sbostic * state. 587*47194Sbostic */ 588*47194Sbostic if (ISSET(FTS_NOCHDIR)) { 589*47194Sbostic if (cp - 1 > sp->fts_path) 590*47194Sbostic --cp; 591*47194Sbostic *cp = '\0'; 592*47194Sbostic } 59342299Sbostic 59442299Sbostic /* 595*47194Sbostic * If descended after called from fts_children or called from 596*47194Sbostic * fts_read and didn't find anything, get back. If can't get 597*47194Sbostic * back, we're done. 59842299Sbostic */ 59942299Sbostic if (descend && (!nitems || type == BCHILD) && CHDIR(sp, "..")) { 600*47194Sbostic cur->fts_info = FTS_ERR; 601*47194Sbostic SET(FTS_STOP); 60239962Sbostic return(NULL); 60339962Sbostic } 60439962Sbostic 605*47194Sbostic /* If we didn't find anything, just do the post-order visit */ 60639800Sbostic if (!nitems) { 60742299Sbostic if (type == BREAD) 608*47194Sbostic cur->fts_info = FTS_DP; 60939800Sbostic return(NULL); 61039800Sbostic } 61139800Sbostic 612*47194Sbostic /* Sort the entries. */ 61342273Sbostic if (sp->fts_compar && nitems > 1) 61445600Sbostic head = fts_sort(sp, head, nitems); 61539800Sbostic return(head); 61639800Sbostic } 61739800Sbostic 61845600Sbostic static u_short 61945600Sbostic fts_stat(sp, p, follow) 62045600Sbostic FTS *sp; 62139800Sbostic register FTSENT *p; 62245600Sbostic int follow; 62339800Sbostic { 624*47194Sbostic int saved_errno; 625*47194Sbostic 62639800Sbostic /* 62745600Sbostic * If doing a logical walk, or application requested FTS_FOLLOW, do 628*47194Sbostic * a stat(2). If that fails, check for a non-existent symlink. If 629*47194Sbostic * fail, return the errno from the stat call. 63039800Sbostic */ 63145600Sbostic if (ISSET(FTS_LOGICAL) || follow) { 63245600Sbostic if (stat(p->fts_accpath, &p->fts_statb)) { 633*47194Sbostic saved_errno = errno; 634*47194Sbostic if (!lstat(p->fts_accpath, &p->fts_statb)) { 635*47194Sbostic errno = 0; 63645600Sbostic return(FTS_SLNONE); 637*47194Sbostic } 638*47194Sbostic errno = saved_errno; 639*47194Sbostic bzero(&p->fts_statb, sizeof(struct stat)); 640*47194Sbostic return(FTS_NS); 64145600Sbostic } 64245600Sbostic } else if (lstat(p->fts_accpath, &p->fts_statb)) { 643*47194Sbostic bzero(&p->fts_statb, sizeof(struct stat)); 64445600Sbostic return(FTS_NS); 64545600Sbostic } 64639800Sbostic 647*47194Sbostic /* 648*47194Sbostic * Cycle detection is done as soon as we find a directory. Detection 649*47194Sbostic * is by brute force; if the tree gets deep enough or the number of 650*47194Sbostic * symbolic links to directories high enough something faster might 651*47194Sbostic * be worthwhile. 652*47194Sbostic */ 653*47194Sbostic if (S_ISDIR(p->fts_statb.st_mode)) { 654*47194Sbostic register FTSENT *t; 655*47194Sbostic register dev_t dev; 656*47194Sbostic register ino_t ino; 657*47194Sbostic 658*47194Sbostic dev = p->fts_statb.st_dev; 659*47194Sbostic ino = p->fts_statb.st_ino; 660*47194Sbostic for (t = p->fts_parent; t->fts_level > ROOTLEVEL; 661*47194Sbostic t = t->fts_parent) 662*47194Sbostic if (ino == t->fts_statb.st_ino && 663*47194Sbostic dev == t->fts_statb.st_dev) { 664*47194Sbostic sp->fts_savelink = p->fts_link; 665*47194Sbostic p->fts_link = t; 666*47194Sbostic return(FTS_DC); 667*47194Sbostic } 66839800Sbostic return(FTS_D); 669*47194Sbostic } 67045600Sbostic if (S_ISLNK(p->fts_statb.st_mode)) 67139800Sbostic return(FTS_SL); 67245600Sbostic if (S_ISREG(p->fts_statb.st_mode)) 67339800Sbostic return(FTS_F); 67440939Sbostic return(FTS_DEFAULT); 67539800Sbostic } 67639800Sbostic 67739800Sbostic #define R(type, nelem, ptr) \ 67842299Sbostic (type *)realloc((void *)ptr, (u_int)((nelem) * sizeof(type))) 67939800Sbostic 68039800Sbostic static FTSENT * 68145600Sbostic fts_sort(sp, head, nitems) 68245600Sbostic FTS *sp; 68339800Sbostic FTSENT *head; 68439800Sbostic register int nitems; 68539800Sbostic { 68639800Sbostic register FTSENT **ap, *p; 68739800Sbostic 68839800Sbostic /* 68945600Sbostic * Construct an array of pointers to the structures and call qsort(3). 69039800Sbostic * Reassemble the array in the order returned by qsort. If unable to 69139800Sbostic * sort for memory reasons, return the directory entries in their 69239800Sbostic * current order. Allocate enough space for the current needs plus 69339800Sbostic * 40 so we don't realloc one entry at a time. 69439800Sbostic */ 69545600Sbostic if (nitems > sp->fts_nitems) { 69645600Sbostic sp->fts_nitems = nitems + 40; 69745600Sbostic if (!(sp->fts_array = 69845600Sbostic R(FTSENT *, sp->fts_nitems, sp->fts_array))) { 69945600Sbostic sp->fts_nitems = 0; 70039800Sbostic return(head); 70139800Sbostic } 70239800Sbostic } 70345600Sbostic for (ap = sp->fts_array, p = head; p; p = p->fts_link) 70439800Sbostic *ap++ = p; 70545600Sbostic qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); 70645600Sbostic for (head = *(ap = sp->fts_array); --nitems; ++ap) 70742273Sbostic ap[0]->fts_link = ap[1]; 70842273Sbostic ap[0]->fts_link = NULL; 70939800Sbostic return(head); 71039800Sbostic } 71139800Sbostic 71239800Sbostic static FTSENT * 71345600Sbostic fts_alloc(sp, name, len) 71445600Sbostic FTS *sp; 71539800Sbostic char *name; 71639800Sbostic register int len; 71739800Sbostic { 71839800Sbostic register FTSENT *p; 71939800Sbostic 72039800Sbostic /* 72145600Sbostic * Variable sized structures; the name is the last element so 722*47194Sbostic * we allocate enough extra space after the structure to store 723*47194Sbostic * it. 72439800Sbostic */ 72542299Sbostic if (!(p = (FTSENT *)malloc((size_t)(sizeof(FTSENT) + len)))) 72639800Sbostic return(NULL); 72742273Sbostic bcopy(name, p->fts_name, len + 1); 72842273Sbostic p->fts_namelen = len; 72945600Sbostic p->fts_path = sp->fts_path; 730*47194Sbostic p->fts_instr = FTS_NOINSTR; 731*47194Sbostic p->fts_cderr = 0; 73245600Sbostic p->fts_number = 0; 73345600Sbostic p->fts_pointer = NULL; 73439800Sbostic return(p); 73539800Sbostic } 73639800Sbostic 73745600Sbostic static void 73839800Sbostic fts_lfree(head) 73939800Sbostic register FTSENT *head; 74039800Sbostic { 74139800Sbostic register FTSENT *p; 74239800Sbostic 74345600Sbostic /* Free a linked list of structures. */ 74439800Sbostic while (p = head) { 74542273Sbostic head = head->fts_link; 746*47194Sbostic free(p); 74739800Sbostic } 74839800Sbostic } 74939800Sbostic 75039800Sbostic /* 75145600Sbostic * Allow essentially unlimited paths; certain programs (find, rm, ls) need to 75245600Sbostic * work on any tree. Most systems will allow creation of paths much longer 75345600Sbostic * than MAXPATHLEN, even though the kernel won't resolve them. Add an extra 75445600Sbostic * 128 bytes to the requested size so that we don't realloc the path 2 bytes 75545600Sbostic * at a time. 75639800Sbostic */ 75742299Sbostic static char * 75845600Sbostic fts_path(sp, size) 75945600Sbostic FTS *sp; 76039800Sbostic int size; 76139800Sbostic { 76245600Sbostic sp->fts_pathlen += size + 128; 76347155Sbostic return(sp->fts_path = R(char, sp->fts_pathlen, sp->fts_path)); 76447155Sbostic } 765