164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* $OpenBSD: fts.c,v 1.43 2009/08/27 16:19:27 millert Exp $ */ 264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*- 464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Copyright (c) 1990, 1993, 1994 564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The Regents of the University of California. All rights reserved. 664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Redistribution and use in source and binary forms, with or without 864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * modification, are permitted provided that the following conditions 964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * are met: 1064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 1. Redistributions of source code must retain the above copyright 1164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * notice, this list of conditions and the following disclaimer. 1264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 2. Redistributions in binary form must reproduce the above copyright 1364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * notice, this list of conditions and the following disclaimer in the 1464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * documentation and/or other materials provided with the distribution. 1564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 3. Neither the name of the University nor the names of its contributors 1664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * may be used to endorse or promote products derived from this software 1764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * without specific prior written permission. 1864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 1964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * SUCH DAMAGE. 3064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 3164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 3264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <sys/param.h> 3364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <sys/stat.h> 3464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 3564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <dirent.h> 3664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <errno.h> 3764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <fcntl.h> 3864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <fts.h> 3964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <stdlib.h> 4064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <string.h> 4164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <unistd.h> 4264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 4364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define MAX(a,b) ((a)>(b)?(a):(b)) 4464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 4564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *fts_alloc(FTS *, char *, size_t); 4664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *fts_build(FTS *, int); 4764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void fts_lfree(FTSENT *); 4864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void fts_load(FTS *, FTSENT *); 4964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic size_t fts_maxarglen(char * const *); 5064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void fts_padjust(FTS *, FTSENT *); 5164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int fts_palloc(FTS *, size_t); 5264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *fts_sort(FTS *, FTSENT *, int); 5364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic u_short fts_stat(FTS *, FTSENT *, int); 5464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int fts_safe_changedir(FTS *, FTSENT *, int, char *); 5564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 5664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) 5764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 5864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define CLR(opt) (sp->fts_options &= ~(opt)) 5964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define ISSET(opt) (sp->fts_options & (opt)) 6064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define SET(opt) (sp->fts_options |= (opt)) 6164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 6264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 6364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 6464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* fts_build flags */ 6564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define BCHILD 1 /* fts_children */ 6664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define BNAMES 2 /* fts_children, names only */ 6764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define BREAD 3 /* fts_read */ 6864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 6964ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTS * 7064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_open(char * const *argv, int options, 7164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int (*compar)(const FTSENT **, const FTSENT **)) 7264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 7364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTS *sp; 7464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p, *root; 7564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int nitems; 7664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *parent, *tmp; 7764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross size_t len; 7864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 7964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Options check. */ 8064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (options & ~FTS_OPTIONMASK) { 8164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = EINVAL; 8264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 8364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 8464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 8564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Allocate/initialize the stream */ 8664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((sp = calloc(1, sizeof(FTS))) == NULL) 8764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 8864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_compar = compar; 8964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_options = options; 9064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 9164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 9264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_LOGICAL)) 9364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_NOCHDIR); 9464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 9564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 9664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Start out with 1K of path space, and enough, in any case, 9764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * to hold the user's paths. 9864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 9964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) 10064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem1; 10164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 10264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Allocate/initialize root's parent. */ 10364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((parent = fts_alloc(sp, "", 0)) == NULL) 10464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem2; 10564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross parent->fts_level = FTS_ROOTPARENTLEVEL; 10664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 10764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Allocate/initialize root(s). */ 10864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { 10964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Don't allow zero-length paths. */ 11064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((len = strlen(*argv)) == 0) { 11164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = ENOENT; 11264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem3; 11364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 11464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 11564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p = fts_alloc(sp, *argv, len)) == NULL) 11664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem3; 11764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_level = FTS_ROOTLEVEL; 11864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_parent = parent; 11964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = p->fts_name; 12064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); 12164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 12264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Command-line "." and ".." are real directories. */ 12364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info == FTS_DOT) 12464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_D; 12564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 12664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 12764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If comparison routine supplied, traverse in sorted 12864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * order; otherwise traverse in the order specified. 12964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 13064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (compar) { 13164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_link = root; 13264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross root = p; 13364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else { 13464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_link = NULL; 13564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (root == NULL) 13664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross tmp = root = p; 13764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross else { 13864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross tmp->fts_link = p; 13964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross tmp = p; 14064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 14164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 14264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 14364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (compar && nitems > 1) 14464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross root = fts_sort(sp, root, nitems); 14564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 14664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 14764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Allocate a dummy pointer and make fts_read think that we've just 14864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * finished the node before the root(s); set p->fts_info to FTS_INIT 14964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * so that everything about the "current" node is ignored. 15064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 15164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) 15264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem3; 15364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_cur->fts_link = root; 15464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_cur->fts_info = FTS_INIT; 15564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 15664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 15764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If using chdir(2), grab a file descriptor pointing to dot to ensure 15864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * that we can get back here; this could be avoided for some paths, 15964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * but almost certainly not worth the effort. Slashes, symbolic links, 16064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * and ".." are all fairly nasty problems. Note, if we can't get the 16164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * descriptor we run anyway, just more slowly. 16264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 16364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) 16464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_NOCHDIR); 16564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 16664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nitems == 0) 16764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(parent); 16864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 16964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp); 17064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 17164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem3: fts_lfree(root); 17264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(parent); 17364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem2: free(sp->fts_path); 17464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem1: free(sp); 17564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 17664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 17764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 17864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void 17964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_load(FTS *sp, FTSENT *p) 18064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 18164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross size_t len; 18264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross char *cp; 18364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 18464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 18564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Load the stream structure for the next traversal. Since we don't 18664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * actually enter the directory until after the preorder visit, set 18764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * the fts_accpath field specially so the chdir gets done to the right 18864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * place and the user can access the first node. From fts_open it's 18964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * known that the path will fit. 19064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 19164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len = p->fts_pathlen = p->fts_namelen; 19264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memmove(sp->fts_path, p->fts_name, len + 1); 19364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 19464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len = strlen(++cp); 19564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memmove(p->fts_name, cp, len + 1); 19664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_namelen = len; 19764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 19864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = p->fts_path = sp->fts_path; 19964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_dev = p->fts_dev; 20064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 20164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 20264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossint 20364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_close(FTS *sp) 20464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 20564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *freep, *p; 20664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int rfd, error = 0; 20764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 20864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 20964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * This still works if we haven't read anything -- the dummy structure 21064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * points to the root list, so we step through to the end of the root 21164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * list which has a valid parent pointer. 21264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 21364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_cur) { 21464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 21564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross freep = p; 21664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = p->fts_link ? p->fts_link : p->fts_parent; 21764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(freep); 21864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 21964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(p); 22064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 22164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 22264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Stash the original directory fd if needed. */ 22364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd; 22464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 22564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Free up child linked list, sort array, path buffer, stream ptr.*/ 22664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_child) 22764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(sp->fts_child); 22864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_array) 22964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp->fts_array); 23064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp->fts_path); 23164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp); 23264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 23364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Return to original directory, checking for error. */ 23464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (rfd != -1) { 23564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int saved_errno; 23664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross error = fchdir(rfd); 23764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross saved_errno = errno; 23864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(rfd); 23964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = saved_errno; 24064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 24164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 24264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (error); 24364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 24464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 24564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 24664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Special case of "/" at the end of the path so that slashes aren't 24764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * appended which would cause paths to be written as "....//foo". 24864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 24964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define NAPPEND(p) \ 25064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (p->fts_path[p->fts_pathlen - 1] == '/' \ 25164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ? p->fts_pathlen - 1 : p->fts_pathlen) 25264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 25364ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTSENT * 25464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_read(FTS *sp) 25564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 25664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p, *tmp; 25764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int instr; 25864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross char *t; 25964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int saved_errno; 26064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 26164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* If finished or unrecoverable error, return NULL. */ 26264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_cur == NULL || ISSET(FTS_STOP)) 26364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 26464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 26564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Set current node pointer. */ 26664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = sp->fts_cur; 26764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 26864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Save and zero out user instructions. */ 26964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross instr = p->fts_instr; 27064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_instr = FTS_NOINSTR; 27164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 27264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Any type of file may be re-visited; re-stat and re-turn. */ 27364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr == FTS_AGAIN) { 27464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = fts_stat(sp, p, 0); 27564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p); 27664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 27764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 27864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 27964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Following a symlink -- SLNONE test allows application to see 28064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * SLNONE and recover. If indirecting through a symlink, have 28164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * keep a pointer to current location. If unable to get that 28264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * pointer, follow fails. 28364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 28464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr == FTS_FOLLOW && 28564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 28664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = fts_stat(sp, p, 1); 28764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 28864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { 28964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = errno; 29064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_ERR; 29164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 29264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_flags |= FTS_SYMFOLLOW; 29364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 29464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p); 29564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 29664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 29764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Directory in pre-order. */ 29864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info == FTS_D) { 29964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* If skipped or crossed mount point, do post-order visit. */ 30064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr == FTS_SKIP || 30164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 30264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_flags & FTS_SYMFOLLOW) 30364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(p->fts_symfd); 30464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_child) { 30564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(sp->fts_child); 30664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_child = NULL; 30764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 30864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_DP; 30964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p); 31064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 31164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 31264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Rebuild if only read the names and now traversing. */ 31364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_child && ISSET(FTS_NAMEONLY)) { 31464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross CLR(FTS_NAMEONLY); 31564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(sp->fts_child); 31664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_child = NULL; 31764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 31864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 31964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 32064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Cd to the subdirectory. 32164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 32264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If have already read and now fail to chdir, whack the list 32364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * to make the names come out right, and set the parent errno 32464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * so the application will eventually get an error condition. 32564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Set the FTS_DONTCHDIR flag so that when we logically change 32664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * directories back to the parent we don't do a chdir. 32764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 32864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If haven't read do so. If the read fails, fts_build sets 32964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * FTS_STOP or the fts_info field of the node. 33064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 33164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_child) { 33264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { 33364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = errno; 33464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_flags |= FTS_DONTCHDIR; 33564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (p = sp->fts_child; p; p = p->fts_link) 33664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = 33764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_parent->fts_accpath; 33864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 33964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { 34064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_STOP)) 34164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 34264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p); 34364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 34464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = sp->fts_child; 34564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_child = NULL; 34664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto name; 34764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 34864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 34964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Move to the next node on this level. */ 35064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossnext: tmp = p; 35164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p = p->fts_link)) { 35264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(tmp); 35364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 35464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 35564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If reached the top, return to the original directory (or 35664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * the root of the tree), and load the paths for the next root. 35764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 35864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_level == FTS_ROOTLEVEL) { 35964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (FCHDIR(sp, sp->fts_rfd)) { 36064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 36164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 36264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 36364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_load(sp, p); 36464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_cur = p); 36564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 36664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 36764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 36864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * User may have called fts_set on the node. If skipped, 36964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * ignore. If followed, get a file descriptor so we can 37064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * get back if necessary. 37164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 37264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_instr == FTS_SKIP) 37364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto next; 37464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_instr == FTS_FOLLOW) { 37564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = fts_stat(sp, p, 1); 37664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 37764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p->fts_symfd = 37864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross open(".", O_RDONLY, 0)) < 0) { 37964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = errno; 38064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_ERR; 38164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 38264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_flags |= FTS_SYMFOLLOW; 38364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 38464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_instr = FTS_NOINSTR; 38564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 38664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 38764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossname: t = sp->fts_path + NAPPEND(p->fts_parent); 38864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *t++ = '/'; 38964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memmove(t, p->fts_name, p->fts_namelen + 1); 39064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_cur = p); 39164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 39264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 39364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Move up to the parent node. */ 39464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = tmp->fts_parent; 39564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(tmp); 39664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 39764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_level == FTS_ROOTPARENTLEVEL) { 39864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 39964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Done; free everything up and set errno to 0 so the user 40064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * can distinguish between error and EOF. 40164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 40264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(p); 40364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = 0; 40464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_cur = NULL); 40564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 40664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 40764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* NUL terminate the pathname. */ 40864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_path[p->fts_pathlen] = '\0'; 40964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 41064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 41164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Return to the parent directory. If at a root node or came through 41264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * a symlink, go back through the file descriptor. Otherwise, cd up 41364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * one directory. 41464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 41564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_level == FTS_ROOTLEVEL) { 41664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (FCHDIR(sp, sp->fts_rfd)) { 41764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 41864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_cur = p; 41964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 42064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 42164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else if (p->fts_flags & FTS_SYMFOLLOW) { 42264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (FCHDIR(sp, p->fts_symfd)) { 42364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross saved_errno = errno; 42464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(p->fts_symfd); 42564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = saved_errno; 42664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 42764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_cur = p; 42864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 42964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 43064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(p->fts_symfd); 43164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else if (!(p->fts_flags & FTS_DONTCHDIR) && 43264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_safe_changedir(sp, p->fts_parent, -1, "..")) { 43364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 43464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_cur = p; 43564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 43664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 43764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 43864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_cur = p); 43964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 44064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 44164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 44264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Fts_set takes the stream as an argument although it's not used in this 44364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * implementation; it would be necessary if anyone wanted to add global 44464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * semantics to fts using fts_set. An error return is allowed for similar 44564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * reasons. 44664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 44764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* ARGSUSED */ 44864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossint 44964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_set(FTS *sp, FTSENT *p, int instr) 45064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 45164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && 45264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross instr != FTS_NOINSTR && instr != FTS_SKIP) { 45364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = EINVAL; 45464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (1); 45564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 45664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_instr = instr; 45764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (0); 45864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 45964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 46064ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTSENT * 46164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_children(FTS *sp, int instr) 46264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 46364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p; 46464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int fd; 46564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 46664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr && instr != FTS_NAMEONLY) { 46764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = EINVAL; 46864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 46964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 47064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 47164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Set current node pointer. */ 47264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = sp->fts_cur; 47364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 47464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 47564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Errno set to 0 so user can distinguish empty directory from 47664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * an error. 47764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 47864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = 0; 47964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 48064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Fatal errors stop here. */ 48164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_STOP)) 48264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 48364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 48464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Return logical hierarchy of user's arguments. */ 48564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info == FTS_INIT) 48664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p->fts_link); 48764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 48864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 48964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If not a directory being visited in pre-order, stop here. Could 49064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * allow FTS_DNR, assuming the user has fixed the problem, but the 49164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * same effect is available with FTS_AGAIN. 49264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 49364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) 49464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 49564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 49664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Free up any previous child list. */ 49764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_child) 49864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(sp->fts_child); 49964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 50064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (instr == FTS_NAMEONLY) { 50164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_NAMEONLY); 50264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross instr = BNAMES; 50364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 50464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross instr = BCHILD; 50564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 50664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 50764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If using chdir on a relative path and called BEFORE fts_read does 50864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * its chdir to the root of a traversal, we can lose -- we need to 50964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * chdir into the subdirectory, and we don't know where the current 51064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * directory is, so we can't get back so that the upcoming chdir by 51164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * fts_read will work. 51264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 51364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 51464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ISSET(FTS_NOCHDIR)) 51564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_child = fts_build(sp, instr)); 51664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 51764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((fd = open(".", O_RDONLY, 0)) < 0) 51864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 51964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_child = fts_build(sp, instr); 52064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fchdir(fd)) { 52164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(fd); 52264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 52364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 52464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(fd); 52564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (sp->fts_child); 52664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 52764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 52864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 52964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * This is the tricky part -- do not casually change *anything* in here. The 53064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * idea is to build the linked list of entries that are used by fts_children 53164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * and fts_read. There are lots of special cases. 53264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 53364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 53464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * set and it's a physical walk (so that symbolic links can't be directories), 53564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * we can do things quickly. First, if it's a 4.4BSD file system, the type 53664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * of the file is in the directory entry. Otherwise, we assume that the number 53764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * of subdirectories in a node is equal to the number of links to the parent. 53864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The former skips all stat calls. The latter skips stat calls in any leaf 53964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * directories and for any files after the subdirectories in the directory have 54064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * been found, cutting the stat calls by about 2/3. 54164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 54264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT * 54364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_build(FTS *sp, int type) 54464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 54564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross struct dirent *dp; 54664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p, *head; 54764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *cur, *tail; 54864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross DIR *dirp; 54964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross void *oldaddr; 55064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross size_t len, maxlen; 55150ace4fec5e8cb5afcbc656a4556fa528adfd760David 'Digit' Turner int nitems, cderrno, descend, level, nlinks, nostat = 0, doadjust; 55264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int saved_errno; 55350ace4fec5e8cb5afcbc656a4556fa528adfd760David 'Digit' Turner char *cp = NULL; 55464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 55564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Set current node pointer. */ 55664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur = sp->fts_cur; 55764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 55864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 55964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Open the directory for reading. If this fails, we're done. 56064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If being called from fts_read, set the fts_info field. 56164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 56264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((dirp = opendir(cur->fts_accpath)) == NULL) { 56364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (type == BREAD) { 56464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_info = FTS_DNR; 56564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_errno = errno; 56664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 56764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 56864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 56964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 57064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 57164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Nlinks is the number of possible entries of type directory in the 57264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * directory if we're cheating on stat calls, 0 if we're not doing 57364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * any stat calls at all, -1 if we're doing stats on everything. 57464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 57564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (type == BNAMES) 57664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross nlinks = 0; 57764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { 57864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 57964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross nostat = 1; 58064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else { 58164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross nlinks = -1; 58264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross nostat = 0; 58364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 58464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 58564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#ifdef notdef 58664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink); 58764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", 58864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); 58964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#endif 59064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 59164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If we're going to need to stat anything or we want to descend 59264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * and stay in the directory, chdir. If this fails we keep going, 59364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * but set a flag so we don't chdir after the post-order visit. 59464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * We won't be able to stat anything, but we can still return the 59564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * names themselves. Note, that since fts_read won't be able to 59664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * chdir into the directory, it will have to return different path 59764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * names than before, i.e. "a/b" instead of "b". Since the node 59864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * has already been visited in pre-order, have to wait until the 59964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * post-order visit to return the error. There is a special case 60064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * here, if there was nothing to stat then it's not an error to 60164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * not be able to stat. This is all fairly nasty. If a program 60264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * needed sorted entries or stat information, they had better be 60364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * checking FTS_NS on the returned nodes. 60464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 60564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cderrno = 0; 60664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nlinks || type == BREAD) { 60764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { 60864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nlinks && type == BREAD) 60964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_errno = errno; 61064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_flags |= FTS_DONTCHDIR; 61164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross descend = 0; 61264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cderrno = errno; 61364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)closedir(dirp); 61464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross dirp = NULL; 61564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 61664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross descend = 1; 61764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 61864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross descend = 0; 61964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 62064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 62164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Figure out the max file name length that can be stored in the 62264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * current path -- the inner loop allocates more path as necessary. 62364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * We really wouldn't have to do the maxlen calculations here, we 62464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * could do them in fts_read before returning the path, but it's a 62564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * lot easier here since the length is part of the dirent structure. 62664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 62764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If not changing directories set a pointer so that can just append 62864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * each new name into the path. 62964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 63064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len = NAPPEND(cur); 63164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_NOCHDIR)) { 63264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cp = sp->fts_path + len; 63364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *cp++ = '/'; 63464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 63564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len++; 63664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross maxlen = sp->fts_pathlen - len; 63764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 63864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 63964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * fts_level is a short so we must prevent it from wrapping 64064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. 64164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 64264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross level = cur->fts_level; 64364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (level < FTS_MAXLEVEL) 64464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross level++; 64564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 64664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Read the directory, attaching each entry to the `link' pointer. */ 64764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross doadjust = 0; 64864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { 64964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 65064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross continue; 65164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 65264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name)))) 65364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto mem1; 65464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (strlen(dp->d_name) >= maxlen) { /* include space for NUL */ 65564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross oldaddr = sp->fts_path; 65664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) { 65764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 65864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * No more memory for path or structures. Save 65964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * errno, free up the current structure and the 66064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * structures already allocated. 66164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 66264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem1: saved_errno = errno; 66364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p) 66464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(p); 66564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(head); 66664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)closedir(dirp); 66764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_info = FTS_ERR; 66864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 66964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = saved_errno; 67064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 67164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 67264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Did realloc() change the pointer? */ 67364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (oldaddr != sp->fts_path) { 67464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross doadjust = 1; 67564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_NOCHDIR)) 67664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cp = sp->fts_path + len; 67764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 67864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross maxlen = sp->fts_pathlen - len; 67964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 68064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 68164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_level = level; 68264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_parent = sp->fts_cur; 68364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_pathlen = len + strlen(dp->d_name); 68464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_pathlen < len) { 68564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 68664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If we wrap, free up the current structure and 68764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * the structures already allocated, then error 68864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * out with ENAMETOOLONG. 68964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 69064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(p); 69164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_lfree(head); 69264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)closedir(dirp); 69364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_info = FTS_ERR; 69464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 69564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = ENAMETOOLONG; 69664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 69764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 69864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 69964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (cderrno) { 70064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nlinks) { 70164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_NS; 70264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = cderrno; 70364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 70464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_NSOK; 70564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = cur->fts_accpath; 70664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else if (nlinks == 0 70764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#ifdef DT_DIR 70864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross || (nostat && 70964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) 71064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#endif 71164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ) { 71264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = 71364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 71464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = FTS_NSOK; 71564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else { 71664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Build a file name for fts_stat to stat. */ 71764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_NOCHDIR)) { 71864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = p->fts_path; 71964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memmove(cp, p->fts_name, p->fts_namelen + 1); 72064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else 72164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_accpath = p->fts_name; 72264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Stat it. */ 72364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info = fts_stat(sp, p, 0); 72464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 72564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Decrement link count if applicable. */ 72664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nlinks > 0 && (p->fts_info == FTS_D || 72764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) 72864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross --nlinks; 72964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 73064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 73164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* We walk in directory order so "ls -f" doesn't get upset. */ 73264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_link = NULL; 73364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (head == NULL) 73464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross head = tail = p; 73564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross else { 73664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross tail->fts_link = p; 73764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross tail = p; 73864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 73964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ++nitems; 74064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 74164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (dirp) 74264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)closedir(dirp); 74364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 74464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 74564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If realloc() changed the address of the path, adjust the 74664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * addresses for the rest of the tree and the dir list. 74764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 74864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (doadjust) 74964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_padjust(sp, head); 75064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 75164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 75264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If not changing directories, reset the path back to original 75364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * state. 75464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 75564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_NOCHDIR)) { 75664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (len == sp->fts_pathlen || nitems == 0) 75764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross --cp; 75864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *cp = '\0'; 75964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 76064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 76164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 76264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If descended after called from fts_children or after called from 76364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * fts_read and nothing found, get back. At the root level we use 76464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * the saved fd; if one of fts_open()'s arguments is a relative path 76564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * to an empty directory, we wind up here with no other way back. If 76664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * can't get back, we're done. 76764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 76864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (descend && (type == BCHILD || !nitems) && 76964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) : 77064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { 77164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_info = FTS_ERR; 77264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross SET(FTS_STOP); 77364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 77464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 77564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 77664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* If didn't find anything, return NULL. */ 77764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!nitems) { 77864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (type == BREAD) 77964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross cur->fts_info = FTS_DP; 78064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 78164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 78264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 78364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Sort the entries. */ 78464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_compar && nitems > 1) 78564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross head = fts_sort(sp, head, nitems); 78664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (head); 78764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 78864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 78964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic u_short 79064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_stat(FTS *sp, FTSENT *p, int follow) 79164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 79264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *t; 79364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross dev_t dev; 79464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ino_t ino; 79564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross struct stat *sbp, sb; 79664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int saved_errno; 79764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 79864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* If user needs stat info, stat buffer already allocated. */ 79964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; 80064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 80164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 80264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * If doing a logical walk, or application requested FTS_FOLLOW, do 80364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * a stat(2). If that fails, check for a non-existent symlink. If 80464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * fail, set the errno from the stat call. 80564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 80664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_LOGICAL) || follow) { 80764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (stat(p->fts_accpath, sbp)) { 80864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross saved_errno = errno; 80964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!lstat(p->fts_accpath, sbp)) { 81064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = 0; 81164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_SLNONE); 81264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 81364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = saved_errno; 81464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto err; 81564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 81664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } else if (lstat(p->fts_accpath, sbp)) { 81764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_errno = errno; 81864ceac3f493e3063a289aec4a12c74787be974e4Colin Crosserr: memset(sbp, 0, sizeof(struct stat)); 81964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_NS); 82064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 82164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 82264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (S_ISDIR(sbp->st_mode)) { 82364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 82464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Set the device/inode. Used to find cycles and check for 82564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * crossing mount points. Also remember the link count, used 82664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * in fts_build to limit the number of stat calls. It is 82764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * understood that these fields are only referenced if fts_info 82864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * is set to FTS_D. 82964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 83064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross dev = p->fts_dev = sbp->st_dev; 83164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ino = p->fts_ino = sbp->st_ino; 83264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_nlink = sbp->st_nlink; 83364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 83464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISDOT(p->fts_name)) 83564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_DOT); 83664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 83764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 83864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Cycle detection is done by brute force when the directory 83964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * is first encountered. If the tree gets deep enough or the 84064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * number of symbolic links to directories is high enough, 84164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * something faster might be worthwhile. 84264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 84364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (t = p->fts_parent; 84464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) 84564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ino == t->fts_ino && dev == t->fts_dev) { 84664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_cycle = t; 84764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_DC); 84864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 84964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_D); 85064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 85164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (S_ISLNK(sbp->st_mode)) 85264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_SL); 85364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (S_ISREG(sbp->st_mode)) 85464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_F); 85564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (FTS_DEFAULT); 85664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 85764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 85864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT * 85964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_sort(FTS *sp, FTSENT *head, int nitems) 86064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 86164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT **ap, *p; 86264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 86364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 86464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Construct an array of pointers to the structures and call qsort(3). 86564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Reassemble the array in the order returned by qsort. If unable to 86664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * sort for memory reasons, return the directory entries in their 86764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * current order. Allocate enough space for the current needs plus 86864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 40 so don't realloc one entry at a time. 86964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 87064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (nitems > sp->fts_nitems) { 87164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross struct _ftsent **a; 87264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 87364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_nitems = nitems + 40; 87464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((a = realloc(sp->fts_array, 87564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_nitems * sizeof(FTSENT *))) == NULL) { 87664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_array) 87764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp->fts_array); 87864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_array = NULL; 87964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_nitems = 0; 88064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (head); 88164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 88264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_array = a; 88364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 88464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (ap = sp->fts_array, p = head; p; p = p->fts_link) 88564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *ap++ = p; 88664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); 88764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (head = *(ap = sp->fts_array); --nitems; ++ap) 88864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ap[0]->fts_link = ap[1]; 88964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ap[0]->fts_link = NULL; 89064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (head); 89164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 89264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 89364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT * 89464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_alloc(FTS *sp, char *name, size_t namelen) 89564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 89664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p; 89764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross size_t len; 89864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 89964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 90064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The file name is a variable length array and no stat structure is 90164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * necessary if the user has set the nostat bit. Allocate the FTSENT 90264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * structure, the file name and the stat structure in one chunk, but 90364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * be careful that the stat structure is reasonably aligned. Since the 90464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * fts_name field is declared to be of size 1, the fts_name pointer is 90564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * namelen + 2 before the first possible address of the stat structure. 90664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 90764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len = sizeof(FTSENT) + namelen; 90864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!ISSET(FTS_NOSTAT)) 90964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross len += sizeof(struct stat) + ALIGNBYTES; 91064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p = malloc(len)) == NULL) 91164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (NULL); 91264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 91364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memset(p, 0, len); 91464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_path = sp->fts_path; 91564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_namelen = namelen; 91664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_instr = FTS_NOINSTR; 91764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (!ISSET(FTS_NOSTAT)) 91864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); 91964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross memcpy(p->fts_name, name, namelen); 92064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 92164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (p); 92264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 92364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 92464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void 92564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_lfree(FTSENT *head) 92664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 92764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p; 92864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 92964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Free a linked list of structures. */ 93064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross while ((p = head)) { 93164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross head = head->fts_link; 93264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(p); 93364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 93464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 93564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 93664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 93764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Allow essentially unlimited paths; find, rm, ls should all work on any tree. 93864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Most systems will allow creation of paths much longer than MAXPATHLEN, even 93964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * though the kernel won't resolve them. Add the size (not just what's needed) 94064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * plus 256 bytes so don't realloc the path 2 bytes at a time. 94164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 94264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int 94364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_palloc(FTS *sp, size_t more) 94464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 94564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross char *p; 94664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 94764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* 94864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Check for possible wraparound. 94964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 95064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross more += 256; 95164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_pathlen + more < sp->fts_pathlen) { 95264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_path) 95364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp->fts_path); 95464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_path = NULL; 95564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = ENAMETOOLONG; 95664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (1); 95764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 95864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_pathlen += more; 95964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = realloc(sp->fts_path, sp->fts_pathlen); 96064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p == NULL) { 96164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (sp->fts_path) 96264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross free(sp->fts_path); 96364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_path = NULL; 96464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (1); 96564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 96664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross sp->fts_path = p; 96764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (0); 96864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 96964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 97064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 97164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * When the path is realloc'd, have to fix all of the pointers in structures 97264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * already returned. 97364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 97464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void 97564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_padjust(FTS *sp, FTSENT *head) 97664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 97764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross FTSENT *p; 97864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross char *addr = sp->fts_path; 97964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 98064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define ADJUST(p) { \ 98164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((p)->fts_accpath != (p)->fts_name) { \ 98264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (p)->fts_accpath = \ 98364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ 98464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } \ 98564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (p)->fts_path = addr; \ 98664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 98764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Adjust the current set of children. */ 98864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (p = sp->fts_child; p; p = p->fts_link) 98964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ADJUST(p); 99064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 99164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross /* Adjust the rest of the tree, including the current level. */ 99264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { 99364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ADJUST(p); 99464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross p = p->fts_link ? p->fts_link : p->fts_parent; 99564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 99664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 99764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 99864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic size_t 99964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_maxarglen(char * const *argv) 100064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 100164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross size_t len, max; 100264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 100364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross for (max = 0; *argv; ++argv) 100464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if ((len = strlen(*argv)) > max) 100564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross max = len; 100664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (max + 1); 100764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 100864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 100964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* 101064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Change to dir specified by fd or p->fts_accpath without getting 101164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * tricked by someone changing the world out from underneath us. 101264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Assumes p->fts_dev and p->fts_ino are filled in. 101364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */ 101464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int 101564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) 101664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{ 101764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross int ret, oerrno, newfd; 101864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross struct stat sb; 101964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross 102064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross newfd = fd; 102164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (ISSET(FTS_NOCHDIR)) 102264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (0); 102364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0) 102464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (-1); 102564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fstat(newfd, &sb)) { 102664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ret = -1; 102764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto bail; 102864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 102964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { 103064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = ENOENT; /* disinformation */ 103164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ret = -1; 103264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross goto bail; 103364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross } 103464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross ret = fchdir(newfd); 103564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossbail: 103664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross oerrno = errno; 103764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross if (fd < 0) 103864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross (void)close(newfd); 103964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross errno = oerrno; 104064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross return (ret); 104164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross} 1042