142273Sbostic /*- 266811Sbostic * Copyright (c) 1990, 1993, 1994 361111Sbostic * The Regents of the University of California. All rights reserved. 439800Sbostic * 542273Sbostic * %sccs.include.redist.c% 639800Sbostic */ 739800Sbostic 839800Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*66813Sbostic static char sccsid[] = "@(#)fts.c 8.4 (Berkeley) 04/16/94"; 1039800Sbostic #endif /* LIBC_SCCS and not lint */ 1139800Sbostic 1239800Sbostic #include <sys/param.h> 1339800Sbostic #include <sys/stat.h> 1466811Sbostic 1539800Sbostic #include <dirent.h> 1639800Sbostic #include <errno.h> 1766811Sbostic #include <fcntl.h> 1852209Sbostic #include <fts.h> 1947194Sbostic #include <stdlib.h> 2042273Sbostic #include <string.h> 2147155Sbostic #include <unistd.h> 2239800Sbostic 2352061Sbostic static FTSENT *fts_alloc __P((FTS *, char *, int)); 2452061Sbostic static FTSENT *fts_build __P((FTS *, int)); 2552061Sbostic static void fts_lfree __P((FTSENT *)); 2652061Sbostic static void fts_load __P((FTS *, FTSENT *)); 2755557Sbostic static size_t fts_maxarglen __P((char * const *)); 2852209Sbostic static void fts_padjust __P((FTS *, void *)); 2953801Sbostic static int fts_palloc __P((FTS *, size_t)); 3052061Sbostic static FTSENT *fts_sort __P((FTS *, FTSENT *, int)); 3152061Sbostic static u_short fts_stat __P((FTS *, FTSENT *, int)); 3239800Sbostic 3352209Sbostic #define ISDOT(a) (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2])) 3452209Sbostic 3545600Sbostic #define ISSET(opt) (sp->fts_options & opt) 3645600Sbostic #define SET(opt) (sp->fts_options |= opt) 3739800Sbostic 3845600Sbostic #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) 3945600Sbostic #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 4039800Sbostic 4142299Sbostic /* fts_build flags */ 4252770Sbostic #define BCHILD 1 /* fts_children */ 4352770Sbostic #define BNAMES 2 /* fts_children, names only */ 4452770Sbostic #define BREAD 3 /* fts_read */ 4542299Sbostic 4639800Sbostic FTS * 4745600Sbostic fts_open(argv, options, compar) 4847155Sbostic char * const *argv; 4939800Sbostic register int options; 5047194Sbostic int (*compar)(); 5139800Sbostic { 5239800Sbostic register FTS *sp; 5339800Sbostic register FTSENT *p, *root; 5455557Sbostic register int nitems; 5539800Sbostic FTSENT *parent, *tmp; 5647194Sbostic int len; 5739800Sbostic 5852770Sbostic /* Options check. */ 5952770Sbostic if (options & ~FTS_OPTIONMASK) { 6052770Sbostic errno = EINVAL; 6152770Sbostic return (NULL); 6252770Sbostic } 6352770Sbostic 6445600Sbostic /* Allocate/initialize the stream */ 6552150Sbostic if ((sp = malloc((u_int)sizeof(FTS))) == NULL) 6652150Sbostic return (NULL); 67*66813Sbostic memset(sp, 0, sizeof(FTS)); 6842273Sbostic sp->fts_compar = compar; 6942273Sbostic sp->fts_options = options; 7039800Sbostic 7145600Sbostic /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 7245600Sbostic if (ISSET(FTS_LOGICAL)) 7345600Sbostic SET(FTS_NOCHDIR); 7445600Sbostic 7553801Sbostic /* 7655557Sbostic * Start out with 1K of path space, and enough, in any case, 7755557Sbostic * to hold the user's paths. 7853801Sbostic */ 7955557Sbostic if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) 8053801Sbostic goto mem1; 8153801Sbostic 8245600Sbostic /* Allocate/initialize root's parent. */ 8352155Sbostic if ((parent = fts_alloc(sp, "", 0)) == NULL) 8453801Sbostic goto mem2; 8547212Sbostic parent->fts_level = FTS_ROOTPARENTLEVEL; 8639800Sbostic 8745600Sbostic /* Allocate/initialize root(s). */ 8855557Sbostic for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { 8952160Sbostic /* Don't allow zero-length paths. */ 9052209Sbostic if ((len = strlen(*argv)) == 0) { 9147194Sbostic errno = ENOENT; 9253801Sbostic goto mem3; 9347194Sbostic } 9452209Sbostic 9547194Sbostic p = fts_alloc(sp, *argv, len); 9649519Sbostic p->fts_level = FTS_ROOTLEVEL; 9749519Sbostic p->fts_parent = parent; 9852218Sbostic p->fts_accpath = p->fts_name; 9952344Sbostic p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); 10052209Sbostic 10152209Sbostic /* Command-line "." and ".." are real directories. */ 10252209Sbostic if (p->fts_info == FTS_DOT) 10352209Sbostic p->fts_info = FTS_D; 10452209Sbostic 10543070Sbostic /* 10645600Sbostic * If comparison routine supplied, traverse in sorted 10743070Sbostic * order; otherwise traverse in the order specified. 10843070Sbostic */ 10943070Sbostic if (compar) { 11043070Sbostic p->fts_link = root; 11143070Sbostic root = p; 11243070Sbostic } else { 11343070Sbostic p->fts_link = NULL; 11452155Sbostic if (root == NULL) 11543070Sbostic tmp = root = p; 11643070Sbostic else { 11743070Sbostic tmp->fts_link = p; 11843070Sbostic tmp = p; 11939800Sbostic } 12039800Sbostic } 12139800Sbostic } 12243070Sbostic if (compar && nitems > 1) 12345600Sbostic root = fts_sort(sp, root, nitems); 12439800Sbostic 12542281Sbostic /* 12645600Sbostic * Allocate a dummy pointer and make fts_read think that we've just 12752160Sbostic * finished the node before the root(s); set p->fts_info to FTS_INIT 12842281Sbostic * so that everything about the "current" node is ignored. 12942281Sbostic */ 13052155Sbostic if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) 13153801Sbostic goto mem3; 13242281Sbostic sp->fts_cur->fts_link = root; 13352160Sbostic sp->fts_cur->fts_info = FTS_INIT; 13442281Sbostic 13552160Sbostic /* 13645600Sbostic * If using chdir(2), grab a file descriptor pointing to dot to insure 13742299Sbostic * that we can get back here; this could be avoided for some paths, 13842299Sbostic * but almost certainly not worth the effort. Slashes, symbolic links, 13942299Sbostic * and ".." are all fairly nasty problems. Note, if we can't get the 14042299Sbostic * descriptor we run anyway, just more slowly. 14139800Sbostic */ 14247194Sbostic if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) 14345600Sbostic SET(FTS_NOCHDIR); 14439800Sbostic 14552150Sbostic return (sp); 14639800Sbostic 14753801Sbostic mem3: fts_lfree(root); 14847194Sbostic free(parent); 14953801Sbostic mem2: free(sp->fts_path); 15047194Sbostic mem1: free(sp); 15152150Sbostic return (NULL); 15239800Sbostic } 15339800Sbostic 15447404Sbostic static void 15545600Sbostic fts_load(sp, p) 15645600Sbostic FTS *sp; 15739800Sbostic register FTSENT *p; 15839800Sbostic { 15939800Sbostic register int len; 16039800Sbostic register char *cp; 16139800Sbostic 16239800Sbostic /* 16347220Sbostic * Load the stream structure for the next traversal. Since we don't 16447220Sbostic * actually enter the directory until after the preorder visit, set 16547220Sbostic * the fts_accpath field specially so the chdir gets done to the right 16652209Sbostic * place and the user can access the first node. From fts_open it's 16752209Sbostic * known that the path will fit. 16839800Sbostic */ 16942273Sbostic len = p->fts_pathlen = p->fts_namelen; 170*66813Sbostic memmove(sp->fts_path, p->fts_name, len + 1); 171*66813Sbostic if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 17239800Sbostic len = strlen(++cp); 173*66813Sbostic memmove(p->fts_name, cp, len + 1); 17442273Sbostic p->fts_namelen = len; 17539800Sbostic } 17645600Sbostic p->fts_accpath = p->fts_path = sp->fts_path; 17752209Sbostic sp->fts_dev = p->fts_dev; 17839800Sbostic } 17939800Sbostic 18052209Sbostic int 18145600Sbostic fts_close(sp) 18239800Sbostic FTS *sp; 18339800Sbostic { 18439800Sbostic register FTSENT *freep, *p; 18539800Sbostic int saved_errno; 18639800Sbostic 18752209Sbostic /* 18852209Sbostic * This still works if we haven't read anything -- the dummy structure 18952209Sbostic * points to the root list, so we step through to the end of the root 19052209Sbostic * list which has a valid parent pointer. 19152209Sbostic */ 19242281Sbostic if (sp->fts_cur) { 19352209Sbostic for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 19442281Sbostic freep = p; 19542281Sbostic p = p->fts_link ? p->fts_link : p->fts_parent; 19647194Sbostic free(freep); 19739800Sbostic } 19847194Sbostic 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) 20547194Sbostic free(sp->fts_array); 20647194Sbostic free(sp->fts_path); 20739800Sbostic 20847194Sbostic /* Return to original directory, save errno if necessary. */ 20945600Sbostic if (!ISSET(FTS_NOCHDIR)) { 21047194Sbostic saved_errno = fchdir(sp->fts_rfd) ? errno : 0; 21147194Sbostic (void)close(sp->fts_rfd); 21239800Sbostic } 21339800Sbostic 21445600Sbostic /* Free up the stream pointer. */ 21547194Sbostic free(sp); 21639800Sbostic 21745600Sbostic /* Set errno and return. */ 21845600Sbostic if (!ISSET(FTS_NOCHDIR) && saved_errno) { 21939800Sbostic errno = saved_errno; 22052150Sbostic return (-1); 22139800Sbostic } 22252150Sbostic return (0); 22339800Sbostic } 22439800Sbostic 22547194Sbostic /* 22652160Sbostic * Special case a root of "/" so that slashes aren't appended which would 22752160Sbostic * cause paths to be written as "//foo". 22847194Sbostic */ 22955557Sbostic #define NAPPEND(p) \ 23055557Sbostic (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ 23147194Sbostic p->fts_path[0] == '/' ? 0 : p->fts_pathlen) 23247194Sbostic 23339800Sbostic FTSENT * 23445600Sbostic fts_read(sp) 23539800Sbostic register FTS *sp; 23639800Sbostic { 23742299Sbostic register FTSENT *p, *tmp; 23839800Sbostic register int instr; 23947194Sbostic register char *t; 24053032Sbostic int saved_errno; 24139800Sbostic 24245600Sbostic /* If finished or unrecoverable error, return NULL. */ 24352155Sbostic if (sp->fts_cur == NULL || ISSET(FTS_STOP)) 24452150Sbostic return (NULL); 24539800Sbostic 24645600Sbostic /* Set current node pointer. */ 24742273Sbostic p = sp->fts_cur; 24839800Sbostic 24945600Sbostic /* Save and zero out user instructions. */ 25042273Sbostic instr = p->fts_instr; 25147194Sbostic p->fts_instr = FTS_NOINSTR; 25239800Sbostic 25347194Sbostic /* Any type of file may be re-visited; re-stat and re-turn. */ 25439800Sbostic if (instr == FTS_AGAIN) { 25545600Sbostic p->fts_info = fts_stat(sp, p, 0); 25652150Sbostic return (p); 25739800Sbostic } 25839800Sbostic 25947194Sbostic /* 26047194Sbostic * Following a symlink -- SLNONE test allows application to see 26152290Sbostic * SLNONE and recover. If indirecting through a symlink, have 26252290Sbostic * keep a pointer to current location. If unable to get that 26352290Sbostic * pointer, follow fails. 26447194Sbostic */ 26547194Sbostic if (instr == FTS_FOLLOW && 26647194Sbostic (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 26745600Sbostic p->fts_info = fts_stat(sp, p, 1); 26852290Sbostic if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) 26952290Sbostic if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { 27052290Sbostic p->fts_errno = errno; 27152290Sbostic p->fts_info = FTS_ERR; 27252290Sbostic } else 27352290Sbostic p->fts_flags |= FTS_SYMFOLLOW; 27452150Sbostic return (p); 27542299Sbostic } 27642299Sbostic 27745600Sbostic /* Directory in pre-order. */ 27842299Sbostic if (p->fts_info == FTS_D) { 27945600Sbostic /* If skipped or crossed mount point, do post-order visit. */ 28047194Sbostic if (instr == FTS_SKIP || 28152209Sbostic ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) { 28252290Sbostic if (p->fts_flags & FTS_SYMFOLLOW) 28352290Sbostic (void)close(p->fts_symfd); 28442273Sbostic if (sp->fts_child) { 28542273Sbostic fts_lfree(sp->fts_child); 28642273Sbostic sp->fts_child = NULL; 28739800Sbostic } 28842301Sbostic p->fts_info = FTS_DP; 28952150Sbostic return (p); 29042299Sbostic } 29142299Sbostic 29253096Sbostic /* Rebuild if only read the names and now traversing. */ 29352770Sbostic if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) { 29452770Sbostic sp->fts_options &= ~FTS_NAMEONLY; 29552770Sbostic fts_lfree(sp->fts_child); 29652770Sbostic sp->fts_child = NULL; 29752770Sbostic } 29852770Sbostic 29947194Sbostic /* 30053096Sbostic * Cd to the subdirectory. 30153096Sbostic * 30247220Sbostic * If have already read and now fail to chdir, whack the list 30353096Sbostic * to make the names come out right, and set the parent errno 30447220Sbostic * so the application will eventually get an error condition. 30553096Sbostic * Set the FTS_DONTCHDIR flag so that when we logically change 30653096Sbostic * directories back to the parent we don't do a chdir. 30753096Sbostic * 30853096Sbostic * If haven't read do so. If the read fails, fts_build sets 30953096Sbostic * FTS_STOP or the fts_info field of the node. 31047194Sbostic */ 31147194Sbostic if (sp->fts_child) { 31242299Sbostic if (CHDIR(sp, p->fts_accpath)) { 31352278Sbostic p->fts_errno = errno; 31452290Sbostic p->fts_flags |= FTS_DONTCHDIR; 31547194Sbostic for (p = sp->fts_child; p; p = p->fts_link) 31647194Sbostic p->fts_accpath = 31747194Sbostic p->fts_parent->fts_accpath; 31842299Sbostic } 31952155Sbostic } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { 32052290Sbostic if (ISSET(FTS_STOP)) 32152150Sbostic return (NULL); 32252150Sbostic return (p); 32347220Sbostic } 32447194Sbostic p = sp->fts_child; 32542299Sbostic sp->fts_child = NULL; 32647194Sbostic goto name; 32739800Sbostic } 32839800Sbostic 32952278Sbostic /* Move to the next node on this level. */ 33042299Sbostic next: tmp = p; 33142299Sbostic if (p = p->fts_link) { 33247194Sbostic free(tmp); 33347194Sbostic 33458532Sbostic /* 33558532Sbostic * If reached the top, return to the original directory, and 33658532Sbostic * load the paths for the next root. 33758532Sbostic */ 33847212Sbostic if (p->fts_level == FTS_ROOTLEVEL) { 33958532Sbostic if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { 34058532Sbostic SET(FTS_STOP); 34158532Sbostic return (NULL); 34258532Sbostic } 34347404Sbostic fts_load(sp, p); 34452150Sbostic return (sp->fts_cur = p); 34547194Sbostic } 34642299Sbostic 34752290Sbostic /* 34852290Sbostic * User may have called fts_set on the node. If skipped, 34952290Sbostic * ignore. If followed, get a file descriptor so we can 35052290Sbostic * get back if necessary. 35152290Sbostic */ 35247194Sbostic if (p->fts_instr == FTS_SKIP) 35347194Sbostic goto next; 35447194Sbostic if (p->fts_instr == FTS_FOLLOW) { 35547194Sbostic p->fts_info = fts_stat(sp, p, 1); 35652290Sbostic if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) 35752290Sbostic if ((p->fts_symfd = 35852290Sbostic open(".", O_RDONLY, 0)) < 0) { 35952290Sbostic p->fts_errno = errno; 36052290Sbostic p->fts_info = FTS_ERR; 36152290Sbostic } else 36252290Sbostic p->fts_flags |= FTS_SYMFOLLOW; 36347194Sbostic p->fts_instr = FTS_NOINSTR; 36447194Sbostic } 36542299Sbostic 36647194Sbostic name: t = sp->fts_path + NAPPEND(p->fts_parent); 36747194Sbostic *t++ = '/'; 368*66813Sbostic memmove(t, p->fts_name, p->fts_namelen + 1); 36952150Sbostic return (sp->fts_cur = p); 37039800Sbostic } 37139800Sbostic 37247220Sbostic /* Move up to the parent node. */ 37342299Sbostic p = tmp->fts_parent; 37447194Sbostic free(tmp); 37542299Sbostic 37647212Sbostic if (p->fts_level == FTS_ROOTPARENTLEVEL) { 37739800Sbostic /* 37845600Sbostic * Done; free everything up and set errno to 0 so the user 37939800Sbostic * can distinguish between error and EOF. 38039800Sbostic */ 38147194Sbostic free(p); 38239800Sbostic errno = 0; 38352150Sbostic return (sp->fts_cur = NULL); 38439800Sbostic } 38539800Sbostic 38653096Sbostic /* Nul terminate the pathname. */ 38742273Sbostic sp->fts_path[p->fts_pathlen] = '\0'; 38847194Sbostic 38947194Sbostic /* 39053096Sbostic * Return to the parent directory. If at a root node or came through 39153096Sbostic * a symlink, go back through the file descriptor. Otherwise, cd up 39253096Sbostic * one directory. 39347194Sbostic */ 39447220Sbostic if (p->fts_level == FTS_ROOTLEVEL) { 39553096Sbostic if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { 39647220Sbostic SET(FTS_STOP); 39752150Sbostic return (NULL); 39847220Sbostic } 39952290Sbostic } else if (p->fts_flags & FTS_SYMFOLLOW) { 40052290Sbostic if (FCHDIR(sp, p->fts_symfd)) { 40153032Sbostic saved_errno = errno; 40252290Sbostic (void)close(p->fts_symfd); 40353032Sbostic errno = saved_errno; 40452290Sbostic SET(FTS_STOP); 40552290Sbostic return (NULL); 40652290Sbostic } 40752290Sbostic (void)close(p->fts_symfd); 40852290Sbostic } else if (!(p->fts_flags & FTS_DONTCHDIR)) { 40952278Sbostic if (CHDIR(sp, "..")) { 41052278Sbostic SET(FTS_STOP); 41152278Sbostic return (NULL); 41252278Sbostic } 41352278Sbostic } 41452290Sbostic p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 41552150Sbostic return (sp->fts_cur = p); 41639800Sbostic } 41739800Sbostic 41839800Sbostic /* 41947220Sbostic * Fts_set takes the stream as an argument although it's not used in this 42039800Sbostic * implementation; it would be necessary if anyone wanted to add global 42145600Sbostic * semantics to fts using fts_set. An error return is allowed for similar 42245600Sbostic * reasons. 42339800Sbostic */ 42439800Sbostic /* ARGSUSED */ 42552209Sbostic int 42645600Sbostic fts_set(sp, p, instr) 42739800Sbostic FTS *sp; 42839800Sbostic FTSENT *p; 42939800Sbostic int instr; 43039800Sbostic { 43152770Sbostic if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && 43252770Sbostic instr != FTS_NOINSTR && instr != FTS_SKIP) { 43352770Sbostic errno = EINVAL; 43452770Sbostic return (1); 43552770Sbostic } 43642273Sbostic p->fts_instr = instr; 43752150Sbostic return (0); 43839800Sbostic } 43939800Sbostic 44039800Sbostic FTSENT * 44152770Sbostic fts_children(sp, instr) 44239800Sbostic register FTS *sp; 44352770Sbostic int instr; 44439800Sbostic { 44542299Sbostic register FTSENT *p; 44642299Sbostic int fd; 44742299Sbostic 44852770Sbostic if (instr && instr != FTS_NAMEONLY) { 44952770Sbostic errno = EINVAL; 45052770Sbostic return (NULL); 45152770Sbostic } 45252770Sbostic 45345600Sbostic /* Set current node pointer. */ 45445600Sbostic p = sp->fts_cur; 45545600Sbostic 45639800Sbostic /* 45752160Sbostic * Errno set to 0 so user can distinguish empty directory from 45852160Sbostic * an error. 45939800Sbostic */ 46039800Sbostic errno = 0; 46152160Sbostic 46252160Sbostic /* Fatal errors stop here. */ 46352160Sbostic if (ISSET(FTS_STOP)) 46452150Sbostic return (NULL); 46545600Sbostic 46652160Sbostic /* Return logical hierarchy of user's arguments. */ 46752160Sbostic if (p->fts_info == FTS_INIT) 46852160Sbostic return (p->fts_link); 46952160Sbostic 47052290Sbostic /* 47152290Sbostic * If not a directory being visited in pre-order, stop here. Could 47252290Sbostic * allow FTS_DNR, assuming the user has fixed the problem, but the 47352290Sbostic * same effect is available with FTS_AGAIN. 47452290Sbostic */ 47552290Sbostic if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) 47652160Sbostic return (NULL); 47752160Sbostic 47845600Sbostic /* Free up any previous child list. */ 47942273Sbostic if (sp->fts_child) 48042273Sbostic fts_lfree(sp->fts_child); 48142299Sbostic 48252770Sbostic if (instr == FTS_NAMEONLY) { 48352770Sbostic sp->fts_options |= FTS_NAMEONLY; 48452770Sbostic instr = BNAMES; 48552770Sbostic } else 48652770Sbostic instr = BCHILD; 48752770Sbostic 48842299Sbostic /* 48945600Sbostic * If using chdir on a relative path and called BEFORE fts_read does 49047194Sbostic * its chdir to the root of a traversal, we can lose -- we need to 49147194Sbostic * chdir into the subdirectory, and we don't know where the current 49247194Sbostic * directory is, so we can't get back so that the upcoming chdir by 49347194Sbostic * fts_read will work. 49442299Sbostic */ 49547212Sbostic if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 49645600Sbostic ISSET(FTS_NOCHDIR)) 49752770Sbostic return (sp->fts_child = fts_build(sp, instr)); 49842299Sbostic 49942299Sbostic if ((fd = open(".", O_RDONLY, 0)) < 0) 50052150Sbostic return (NULL); 50152770Sbostic sp->fts_child = fts_build(sp, instr); 50242299Sbostic if (fchdir(fd)) 50352150Sbostic return (NULL); 50442299Sbostic (void)close(fd); 50552150Sbostic return (sp->fts_child); 50639800Sbostic } 50739800Sbostic 50847194Sbostic /* 50947194Sbostic * This is the tricky part -- do not casually change *anything* in here. The 51047194Sbostic * idea is to build the linked list of entries that are used by fts_children 51147194Sbostic * and fts_read. There are lots of special cases. 51247194Sbostic * 51347194Sbostic * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 51447194Sbostic * set and it's a physical walk (so that symbolic links can't be directories), 51559307Sbostic * we can do things quickly. First, if it's a 4.4BSD file system, the type 51659307Sbostic * of the file is in the directory entry. Otherwise, we assume that the number 51759307Sbostic * of subdirectories in a node is equal to the number of links to the parent. 51859307Sbostic * The former skips all stat calls. The latter skips stat calls in any leaf 51959307Sbostic * directories and for any files after the subdirectories in the directory have 52059307Sbostic * been found, cutting the stat calls by about 2/3. 52147194Sbostic */ 52247155Sbostic static FTSENT * 52342299Sbostic fts_build(sp, type) 52439800Sbostic register FTS *sp; 52542299Sbostic int type; 52639800Sbostic { 52739800Sbostic register struct dirent *dp; 52839800Sbostic register FTSENT *p, *head; 52939800Sbostic register int nitems; 53052290Sbostic FTSENT *cur, *tail; 53139800Sbostic DIR *dirp; 53252209Sbostic void *adjaddr; 53352278Sbostic int cderrno, descend, len, level, maxlen, nlinks, saved_errno; 53439800Sbostic char *cp; 53539800Sbostic 53645600Sbostic /* Set current node pointer. */ 53747194Sbostic cur = sp->fts_cur; 53845600Sbostic 53947194Sbostic /* 54047194Sbostic * Open the directory for reading. If this fails, we're done. 54147194Sbostic * If being called from fts_read, set the fts_info field. 54247194Sbostic */ 54352155Sbostic if ((dirp = opendir(cur->fts_accpath)) == NULL) { 54452206Sbostic if (type == BREAD) { 54547194Sbostic cur->fts_info = FTS_DNR; 54652206Sbostic cur->fts_errno = errno; 54752206Sbostic } 54852150Sbostic return (NULL); 54939800Sbostic } 55039800Sbostic 55139800Sbostic /* 55247194Sbostic * Nlinks is the number of possible entries of type directory in the 55347194Sbostic * directory if we're cheating on stat calls, 0 if we're not doing 55447194Sbostic * any stat calls at all, -1 if we're doing stats on everything. 55539800Sbostic */ 55652770Sbostic if (type == BNAMES) 55752770Sbostic nlinks = 0; 55852770Sbostic else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) 55952770Sbostic nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 56052770Sbostic else 56152770Sbostic nlinks = -1; 56239800Sbostic 56352290Sbostic #ifdef notdef 56452290Sbostic (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); 56552290Sbostic (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", 56652290Sbostic ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); 56752290Sbostic #endif 56847194Sbostic /* 56947194Sbostic * If we're going to need to stat anything or we want to descend 57053379Sbostic * and stay in the directory, chdir. If this fails we keep going, 57153379Sbostic * but set a flag so we don't chdir after the post-order visit. 57247194Sbostic * We won't be able to stat anything, but we can still return the 57347194Sbostic * names themselves. Note, that since fts_read won't be able to 57447194Sbostic * chdir into the directory, it will have to return different path 57547194Sbostic * names than before, i.e. "a/b" instead of "b". Since the node 57647194Sbostic * has already been visited in pre-order, have to wait until the 57752290Sbostic * post-order visit to return the error. There is a special case 57852290Sbostic * here, if there was nothing to stat then it's not an error to 57952290Sbostic * not be able to stat. This is all fairly nasty. If a program 58052290Sbostic * needed sorted entries or stat information, they had better be 58152290Sbostic * checking FTS_NS on the returned nodes. 58247194Sbostic */ 58358532Sbostic cderrno = 0; 58445600Sbostic if (nlinks || type == BREAD) 58547194Sbostic if (FCHDIR(sp, dirfd(dirp))) { 58653380Sbostic if (nlinks && type == BREAD) 58752160Sbostic cur->fts_errno = errno; 58853380Sbostic cur->fts_flags |= FTS_DONTCHDIR; 58952290Sbostic descend = 0; 59052278Sbostic cderrno = errno; 59158532Sbostic } else 59245600Sbostic descend = 1; 59347194Sbostic else 59447194Sbostic descend = 0; 59539962Sbostic 59647194Sbostic /* 59747194Sbostic * Figure out the max file name length that can be stored in the 59847194Sbostic * current path -- the inner loop allocates more path as necessary. 59947194Sbostic * We really wouldn't have to do the maxlen calculations here, we 60047194Sbostic * could do them in fts_read before returning the path, but it's a 60147194Sbostic * lot easier here since the length is part of the dirent structure. 60247194Sbostic * 60352209Sbostic * If not changing directories set a pointer so that can just append 60452209Sbostic * each new name into the path. 60547194Sbostic */ 60647194Sbostic maxlen = sp->fts_pathlen - cur->fts_pathlen - 1; 60747194Sbostic len = NAPPEND(cur); 60847194Sbostic if (ISSET(FTS_NOCHDIR)) { 60947194Sbostic cp = sp->fts_path + len; 61047194Sbostic *cp++ = '/'; 61147194Sbostic } 61240939Sbostic 61347194Sbostic level = cur->fts_level + 1; 61440939Sbostic 61547194Sbostic /* Read the directory, attaching each entry to the `link' pointer. */ 61652209Sbostic adjaddr = NULL; 61752290Sbostic for (head = tail = NULL, nitems = 0; dp = readdir(dirp);) { 61847194Sbostic if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 61939800Sbostic continue; 62039800Sbostic 62152155Sbostic if ((p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen)) == NULL) 62239800Sbostic goto mem1; 62339800Sbostic if (dp->d_namlen > maxlen) { 62453801Sbostic if (fts_palloc(sp, (size_t)dp->d_namlen)) { 62547194Sbostic /* 62647194Sbostic * No more memory for path or structures. Save 62747194Sbostic * errno, free up the current structure and the 62847194Sbostic * structures already allocated. 62947194Sbostic */ 63047194Sbostic mem1: saved_errno = errno; 63147194Sbostic if (p) 63247194Sbostic free(p); 63347194Sbostic fts_lfree(head); 63447194Sbostic (void)closedir(dirp); 63539800Sbostic errno = saved_errno; 63647194Sbostic cur->fts_info = FTS_ERR; 63747194Sbostic SET(FTS_STOP); 63852150Sbostic return (NULL); 63939800Sbostic } 64052209Sbostic adjaddr = sp->fts_path; 64142273Sbostic maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1; 64239800Sbostic } 64339800Sbostic 64442273Sbostic p->fts_pathlen = len + dp->d_namlen + 1; 64542273Sbostic p->fts_parent = sp->fts_cur; 64642273Sbostic p->fts_level = level; 64739800Sbostic 64852290Sbostic if (cderrno) { 64952290Sbostic if (nlinks) { 65052290Sbostic p->fts_info = FTS_NS; 65152290Sbostic p->fts_errno = cderrno; 65252290Sbostic } else 65352290Sbostic p->fts_info = FTS_NSOK; 65452290Sbostic p->fts_accpath = cur->fts_accpath; 65559307Sbostic } else if (nlinks == 0 65659307Sbostic #ifdef DT_DIR 65759307Sbostic || nlinks > 0 && 65859307Sbostic dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN 65959307Sbostic #endif 66059307Sbostic ) { 66159307Sbostic p->fts_accpath = 66259307Sbostic ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 66359307Sbostic p->fts_info = FTS_NSOK; 66459307Sbostic } else { 66547194Sbostic /* Build a file name for fts_stat to stat. */ 66647194Sbostic if (ISSET(FTS_NOCHDIR)) { 66747194Sbostic p->fts_accpath = p->fts_path; 668*66813Sbostic memmove(cp, p->fts_name, p->fts_namelen + 1); 66947194Sbostic } else 67047194Sbostic p->fts_accpath = p->fts_name; 67159307Sbostic /* Stat it. */ 67245600Sbostic p->fts_info = fts_stat(sp, p, 0); 67359307Sbostic 67459307Sbostic /* Decrement link count if applicable. */ 67552209Sbostic if (nlinks > 0 && (p->fts_info == FTS_D || 67652209Sbostic p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) 67739800Sbostic --nlinks; 67847194Sbostic } 67939800Sbostic 68052290Sbostic /* We walk in directory order so "ls -f" doesn't get upset. */ 68152290Sbostic p->fts_link = NULL; 68252290Sbostic if (head == NULL) 68352290Sbostic head = tail = p; 68452290Sbostic else { 68552290Sbostic tail->fts_link = p; 68652290Sbostic tail = p; 68752290Sbostic } 68839800Sbostic ++nitems; 68939800Sbostic } 69039800Sbostic (void)closedir(dirp); 69139800Sbostic 69247194Sbostic /* 69352209Sbostic * If had to realloc the path, adjust the addresses for the rest 69452209Sbostic * of the tree. 69552209Sbostic */ 69652209Sbostic if (adjaddr) 69752209Sbostic fts_padjust(sp, adjaddr); 69852209Sbostic 69952209Sbostic /* 70047194Sbostic * If not changing directories, reset the path back to original 70147194Sbostic * state. 70247194Sbostic */ 70347194Sbostic if (ISSET(FTS_NOCHDIR)) { 70447194Sbostic if (cp - 1 > sp->fts_path) 70547194Sbostic --cp; 70647194Sbostic *cp = '\0'; 70747194Sbostic } 70842299Sbostic 70942299Sbostic /* 71066811Sbostic * If descended after called from fts_children or after called from 71166811Sbostic * fts_read and nothing found, get back. At the root level we use 71266811Sbostic * the saved fd; if one of fts_open()'s arguments is a relative path 71366811Sbostic * to an empty directory, we wind up here with no other way back. If 71466811Sbostic * can't get back, we're done. 71542299Sbostic */ 71666811Sbostic if (descend && (type == BCHILD || !nitems) && 71766811Sbostic (cur->fts_level == FTS_ROOTLEVEL ? 71866811Sbostic FCHDIR(sp, sp->fts_rfd) : CHDIR(sp, ".."))) { 71947194Sbostic cur->fts_info = FTS_ERR; 72047194Sbostic SET(FTS_STOP); 72152150Sbostic return (NULL); 72239962Sbostic } 72339962Sbostic 72453032Sbostic /* If didn't find anything, return NULL. */ 72553096Sbostic if (!nitems) { 72653096Sbostic if (type == BREAD) 72753096Sbostic cur->fts_info = FTS_DP; 72852150Sbostic return (NULL); 72953096Sbostic } 73039800Sbostic 73147194Sbostic /* Sort the entries. */ 73242273Sbostic if (sp->fts_compar && nitems > 1) 73345600Sbostic head = fts_sort(sp, head, nitems); 73452150Sbostic return (head); 73539800Sbostic } 73639800Sbostic 73745600Sbostic static u_short 73845600Sbostic fts_stat(sp, p, follow) 73945600Sbostic FTS *sp; 74039800Sbostic register FTSENT *p; 74145600Sbostic int follow; 74239800Sbostic { 74352160Sbostic register FTSENT *t; 74452160Sbostic register dev_t dev; 74552160Sbostic register ino_t ino; 74652209Sbostic struct stat *sbp, sb; 74747194Sbostic int saved_errno; 74847194Sbostic 74952209Sbostic /* If user needs stat info, stat buffer already allocated. */ 75052209Sbostic sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; 75152209Sbostic 75239800Sbostic /* 75345600Sbostic * If doing a logical walk, or application requested FTS_FOLLOW, do 75447194Sbostic * a stat(2). If that fails, check for a non-existent symlink. If 75552160Sbostic * fail, set the errno from the stat call. 75639800Sbostic */ 75745600Sbostic if (ISSET(FTS_LOGICAL) || follow) { 75852209Sbostic if (stat(p->fts_accpath, sbp)) { 75947194Sbostic saved_errno = errno; 76052209Sbostic if (!lstat(p->fts_accpath, sbp)) { 76147194Sbostic errno = 0; 76252150Sbostic return (FTS_SLNONE); 76347194Sbostic } 76452160Sbostic p->fts_errno = saved_errno; 76552209Sbostic goto err; 76645600Sbostic } 76752209Sbostic } else if (lstat(p->fts_accpath, sbp)) { 76852160Sbostic p->fts_errno = errno; 769*66813Sbostic err: memset(sbp, 0, sizeof(struct stat)); 77052150Sbostic return (FTS_NS); 77145600Sbostic } 77239800Sbostic 77352209Sbostic if (S_ISDIR(sbp->st_mode)) { 77452209Sbostic /* 77552209Sbostic * Set the device/inode. Used to find cycles and check for 77652209Sbostic * crossing mount points. Also remember the link count, used 77752209Sbostic * in fts_build to limit the number of stat calls. It is 77852209Sbostic * understood that these fields are only referenced if fts_info 77952209Sbostic * is set to FTS_D. 78052209Sbostic */ 78152209Sbostic dev = p->fts_dev = sbp->st_dev; 78252209Sbostic ino = p->fts_ino = sbp->st_ino; 78352209Sbostic p->fts_nlink = sbp->st_nlink; 78452209Sbostic 78552290Sbostic if (ISDOT(p->fts_name)) 78652290Sbostic return (FTS_DOT); 78752290Sbostic 78852209Sbostic /* 78952209Sbostic * Cycle detection is done by brute force when the directory 79052209Sbostic * is first encountered. If the tree gets deep enough or the 79152209Sbostic * number of symbolic links to directories is high enough, 79252209Sbostic * something faster might be worthwhile. 79352209Sbostic */ 79452209Sbostic for (t = p->fts_parent; 79552209Sbostic t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) 79652209Sbostic if (ino == t->fts_ino && dev == t->fts_dev) { 79752073Sbostic p->fts_cycle = t; 79852150Sbostic return (FTS_DC); 79947194Sbostic } 80052150Sbostic return (FTS_D); 80147194Sbostic } 80252209Sbostic if (S_ISLNK(sbp->st_mode)) 80352150Sbostic return (FTS_SL); 80452209Sbostic if (S_ISREG(sbp->st_mode)) 80552150Sbostic return (FTS_F); 80652150Sbostic return (FTS_DEFAULT); 80739800Sbostic } 80839800Sbostic 80939800Sbostic static FTSENT * 81045600Sbostic fts_sort(sp, head, nitems) 81145600Sbostic FTS *sp; 81239800Sbostic FTSENT *head; 81339800Sbostic register int nitems; 81439800Sbostic { 81539800Sbostic register FTSENT **ap, *p; 81639800Sbostic 81739800Sbostic /* 81845600Sbostic * Construct an array of pointers to the structures and call qsort(3). 81939800Sbostic * Reassemble the array in the order returned by qsort. If unable to 82039800Sbostic * sort for memory reasons, return the directory entries in their 82139800Sbostic * current order. Allocate enough space for the current needs plus 82252209Sbostic * 40 so don't realloc one entry at a time. 82339800Sbostic */ 82445600Sbostic if (nitems > sp->fts_nitems) { 82545600Sbostic sp->fts_nitems = nitems + 40; 82652209Sbostic if ((sp->fts_array = realloc(sp->fts_array, 82752209Sbostic (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) { 82845600Sbostic sp->fts_nitems = 0; 82952150Sbostic return (head); 83039800Sbostic } 83139800Sbostic } 83245600Sbostic for (ap = sp->fts_array, p = head; p; p = p->fts_link) 83339800Sbostic *ap++ = p; 83445600Sbostic qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); 83545600Sbostic for (head = *(ap = sp->fts_array); --nitems; ++ap) 83642273Sbostic ap[0]->fts_link = ap[1]; 83742273Sbostic ap[0]->fts_link = NULL; 83852150Sbostic return (head); 83939800Sbostic } 84039800Sbostic 84139800Sbostic static FTSENT * 84253801Sbostic fts_alloc(sp, name, namelen) 84345600Sbostic FTS *sp; 84439800Sbostic char *name; 84553801Sbostic register int namelen; 84639800Sbostic { 84739800Sbostic register FTSENT *p; 84853801Sbostic size_t len; 84939800Sbostic 85039800Sbostic /* 85153801Sbostic * The file name is a variable length array and no stat structure is 85253801Sbostic * necessary if the user has set the nostat bit. Allocate the FTSENT 85353801Sbostic * structure, the file name and the stat structure in one chunk, but 85453801Sbostic * be careful that the stat structure is reasonably aligned. Since the 85553801Sbostic * fts_name field is declared to be of size 1, the fts_name pointer is 85653801Sbostic * namelen + 2 before the first possible address of the stat structure. 85739800Sbostic */ 85853801Sbostic len = sizeof(FTSENT) + namelen; 85953801Sbostic if (!ISSET(FTS_NOSTAT)) 86053801Sbostic len += sizeof(struct stat) + ALIGNBYTES; 86153801Sbostic if ((p = malloc(len)) == NULL) 86252150Sbostic return (NULL); 86353801Sbostic 86453801Sbostic /* Copy the name plus the trailing NULL. */ 865*66813Sbostic memmove(p->fts_name, name, namelen + 1); 86653801Sbostic 86753801Sbostic if (!ISSET(FTS_NOSTAT)) 86853801Sbostic p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); 86953801Sbostic p->fts_namelen = namelen; 87045600Sbostic p->fts_path = sp->fts_path; 87152290Sbostic p->fts_errno = 0; 87252290Sbostic p->fts_flags = 0; 87347194Sbostic p->fts_instr = FTS_NOINSTR; 87445600Sbostic p->fts_number = 0; 87545600Sbostic p->fts_pointer = NULL; 87652150Sbostic return (p); 87739800Sbostic } 87839800Sbostic 87945600Sbostic static void 88039800Sbostic fts_lfree(head) 88139800Sbostic register FTSENT *head; 88239800Sbostic { 88339800Sbostic register FTSENT *p; 88439800Sbostic 88545600Sbostic /* Free a linked list of structures. */ 88639800Sbostic while (p = head) { 88742273Sbostic head = head->fts_link; 88847194Sbostic free(p); 88939800Sbostic } 89039800Sbostic } 89139800Sbostic 89239800Sbostic /* 89352209Sbostic * Allow essentially unlimited paths; find, rm, ls should all work on any tree. 89452209Sbostic * Most systems will allow creation of paths much longer than MAXPATHLEN, even 89552209Sbostic * though the kernel won't resolve them. Add the size (not just what's needed) 89652209Sbostic * plus 256 bytes so don't realloc the path 2 bytes at a time. 89739800Sbostic */ 89852209Sbostic static int 89952209Sbostic fts_palloc(sp, more) 90045600Sbostic FTS *sp; 90153801Sbostic size_t more; 90239800Sbostic { 90352209Sbostic sp->fts_pathlen += more + 256; 90452209Sbostic sp->fts_path = realloc(sp->fts_path, (size_t)sp->fts_pathlen); 90552209Sbostic return (sp->fts_path == NULL); 90647155Sbostic } 90752209Sbostic 90852209Sbostic /* 90952209Sbostic * When the path is realloc'd, have to fix all of the pointers in structures 91052209Sbostic * already returned. 91152209Sbostic */ 91252209Sbostic static void 91352209Sbostic fts_padjust(sp, addr) 91452209Sbostic FTS *sp; 91552209Sbostic void *addr; 91652209Sbostic { 91752209Sbostic FTSENT *p; 91852209Sbostic 91955557Sbostic #define ADJUST(p) { \ 92065345Sbostic (p)->fts_accpath = \ 92165345Sbostic (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ 92255557Sbostic (p)->fts_path = addr; \ 92352209Sbostic } 92452209Sbostic /* Adjust the current set of children. */ 92552209Sbostic for (p = sp->fts_child; p; p = p->fts_link) 92652209Sbostic ADJUST(p); 92752209Sbostic 92852209Sbostic /* Adjust the rest of the tree. */ 92952209Sbostic for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 93052209Sbostic ADJUST(p); 93152209Sbostic p = p->fts_link ? p->fts_link : p->fts_parent; 93252209Sbostic } 93352209Sbostic } 93455557Sbostic 93555557Sbostic static size_t 93655557Sbostic fts_maxarglen(argv) 93755557Sbostic char * const *argv; 93855557Sbostic { 93955557Sbostic size_t len, max; 94055557Sbostic 94155557Sbostic for (max = 0; *argv; ++argv) 94255557Sbostic if ((len = strlen(*argv)) > max) 94355557Sbostic max = len; 94455557Sbostic return (max); 94555557Sbostic } 946