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