openenvutils/commandshell/shell/commands/src/fts.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 /*	$Id: fts.c,v 1.5 2000/11/25 16:33:36 arnd Exp $	*/
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*-
       
     6  * Copyright (c) 1990, 1993, 1994
       
     7  *	The Regents of the University of California.  All rights reserved.
       
     8  *
       
     9  * Redistribution and use in source and binary forms, with or without
       
    10  * modification, are permitted provided that the following conditions
       
    11  * are met:
       
    12  * 1. Redistributions of source code must retain the above copyright
       
    13  *    notice, this list of conditions and the following disclaimer.
       
    14  * 2. Redistributions in binary form must reproduce the above copyright
       
    15  *    notice, this list of conditions and the following disclaimer in the
       
    16  *    documentation and/or other materials provided with the distribution.
       
    17  * 3. All advertising materials mentioning features or use of this software
       
    18  *    must display the following acknowledgement:
       
    19  *	This product includes software developed by the University of
       
    20  *	California, Berkeley and its contributors.
       
    21  * 4. Neither the name of the University nor the names of its contributors
       
    22  *    may be used to endorse or promote products derived from this software
       
    23  *    without specific prior written permission.
       
    24  *
       
    25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
    26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
    29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
    31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
    32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
    33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
    34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
    35  * SUCH DAMAGE.
       
    36  */
       
    37 
       
    38 #define __NO_FCHDIR /* Fix me! fchdir fn not yet implemented (AH) */
       
    39 
       
    40 #define _BSD_SOURCE
       
    41 #include <sys/param.h>
       
    42 #include <sys/stat.h>
       
    43 #include <dirent.h>
       
    44 #ifndef __SYMBIAN32__
       
    45 #include <sys/direntx.h>
       
    46 #endif
       
    47 #include <errno.h>
       
    48 #include <fcntl.h>
       
    49 #include "fts.h"
       
    50 #include <stdlib.h>
       
    51 #include <string.h>
       
    52 #include <unistd.h>
       
    53 
       
    54 static FTSENT	*fts_alloc(FTS *, char *, size_t);
       
    55 static FTSENT	*fts_build(FTS *, int);
       
    56 static void	 fts_lfree(FTSENT *);
       
    57 static void	 fts_load(FTS *, FTSENT *);
       
    58 static size_t	 fts_maxarglen(char * const *);
       
    59 static void	 fts_padjust(FTS *, FTSENT *);
       
    60 static int	 fts_palloc(FTS *, size_t);
       
    61 static FTSENT	*fts_sort(FTS *, FTSENT *, size_t);
       
    62 static u_short	 fts_stat(FTS *, FTSENT *, int);
       
    63 static int	 fts_safe_changedir(FTS *, FTSENT *, int);
       
    64 
       
    65 #define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
       
    66 
       
    67 #define	CLR(opt)	(sp->fts_options &= ~(opt))
       
    68 #define	ISSET(opt)	(sp->fts_options & (opt))
       
    69 #define	SET(opt)	(sp->fts_options |= (opt))
       
    70 
       
    71 #ifndef __NO_FCHDIR
       
    72 #define	CHDIR(sp, path)	(!ISSET(FTS_NOCHDIR) && chdir(path))
       
    73 #define	FCHDIR(sp, fd)	(!ISSET(FTS_NOCHDIR) && fchdir(fd))
       
    74 #else
       
    75 #define	CHDIR(sp, path)	(0)
       
    76 #define	FCHDIR(sp, fd)	(0)
       
    77 #endif
       
    78 
       
    79 #ifdef __SYMBIAN32__
       
    80 #ifdef __WINSCW__
       
    81 #pragma warn_unusedarg off
       
    82 #endif//__WINSCW__
       
    83 #ifdef __ARMCC__
       
    84 // Turn off the 'extended constant initialiser used' warning
       
    85 #pragma diag_remark 1294
       
    86 #endif
       
    87 #endif//__SYMBIAN32__
       
    88 
       
    89 /* fts_build flags */
       
    90 #define	BCHILD		1		/* fts_children */
       
    91 #define	BNAMES		2		/* fts_children, names only */
       
    92 #define	BREAD		3		/* fts_read */
       
    93 
       
    94 static void
       
    95 fts_load(sp, p)
       
    96 	FTS *sp;
       
    97 	register FTSENT *p;
       
    98 {
       
    99 	register size_t len;
       
   100 	register char *cp;
       
   101 
       
   102 	/*
       
   103 	 * Load the stream structure for the next traversal.  Since we don't
       
   104 	 * actually enter the directory until after the preorder visit, set
       
   105 	 * the fts_accpath field specially so the chdir gets done to the right
       
   106 	 * place and the user can access the first node.  From fts_open it's
       
   107 	 * known that the path will fit.
       
   108 	 */
       
   109 	len = p->fts_pathlen = p->fts_namelen;
       
   110 	memmove(sp->fts_path, p->fts_name, len + 1);
       
   111 
       
   112 	if (!(cp = strrchr(p->fts_name, '\\')))
       
   113 		cp = strrchr(p->fts_name, '\\');
       
   114 	if (cp && (cp != p->fts_name || cp[1])) {
       
   115 		len = strlen(++cp);
       
   116 		memmove(p->fts_name, cp, len + 1);
       
   117 		p->fts_namelen = len;
       
   118 	}
       
   119 	p->fts_accpath = p->fts_path = sp->fts_path;
       
   120 	sp->fts_dev = p->fts_dev;
       
   121 }
       
   122 
       
   123 /*
       
   124  * Special case of "/" at the end of the path so that slashes aren't
       
   125  * appended which would cause paths to be written as "....//foo".
       
   126  */
       
   127 #define	NAPPEND(p)							\
       
   128 	(p->fts_path[p->fts_pathlen - 1] == '/'				\
       
   129 	    ? p->fts_pathlen - 1 : p->fts_pathlen)
       
   130 
       
   131 /*
       
   132  * This is the tricky part -- do not casually change *anything* in here.  The
       
   133  * idea is to build the linked list of entries that are used by fts_children
       
   134  * and fts_read.  There are lots of special cases.
       
   135  *
       
   136  * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
       
   137  * set and it's a physical walk (so that symbolic links can't be directories),
       
   138  * we can do things quickly.  First, if it's a 4.4BSD file system, the type
       
   139  * of the file is in the directory entry.  Otherwise, we assume that the number
       
   140  * of subdirectories in a node is equal to the number of links to the parent.
       
   141  * The former skips all stat calls.  The latter skips stat calls in any leaf
       
   142  * directories and for any files after the subdirectories in the directory have
       
   143  * been found, cutting the stat calls by about 2/3.
       
   144  */
       
   145 static FTSENT *
       
   146 fts_build(sp, type)
       
   147 	register FTS *sp;
       
   148 	int type;
       
   149 {
       
   150 	register struct dirent *dp;
       
   151 	register FTSENT *p, *head;
       
   152 	register size_t nitems;
       
   153 	FTSENT *cur, *tail;
       
   154 	DIR *dirp;
       
   155 	void *oldaddr;
       
   156 	int cderrno, descend, level, nlinks, /* oflag, */ saved_errno,
       
   157 	    nostat = 0, doadjust;
       
   158 	size_t len, maxlen;
       
   159 	char *cp = NULL;
       
   160 
       
   161 	/* Set current node pointer. */
       
   162 	cur = sp->fts_cur;
       
   163 
       
   164 	/*
       
   165 	 * Open the directory for reading.  If this fails, we're done.
       
   166 	 * If being called from fts_read, set the fts_info field.
       
   167 	 */
       
   168 #ifdef FTS_WHITEOUT
       
   169 	if (ISSET(FTS_WHITEOUT))
       
   170 		oflag = DTF_NODUP|DTF_REWIND;
       
   171 	else
       
   172 		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
       
   173 #else
       
   174 #define __opendir2(path, flag) opendir(path)
       
   175 #endif
       
   176 	if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
       
   177 		if (type == BREAD) {
       
   178 			cur->fts_info = FTS_DNR;
       
   179 			cur->fts_errno = errno;
       
   180 		}
       
   181 		return (NULL);
       
   182 	}
       
   183 
       
   184 	/*
       
   185 	 * Nlinks is the number of possible entries of type directory in the
       
   186 	 * directory if we're cheating on stat calls, 0 if we're not doing
       
   187 	 * any stat calls at all, -1 if we're doing stats on everything.
       
   188 	 */
       
   189 	if (type == BNAMES)
       
   190 		nlinks = 0;
       
   191 	else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
       
   192 		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
       
   193 		nostat = 1;
       
   194 	} else {
       
   195 		nlinks = -1;
       
   196 		nostat = 0;
       
   197 	}
       
   198 
       
   199 #ifdef notdef
       
   200 	(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
       
   201 	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
       
   202 	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
       
   203 #endif
       
   204 	/*
       
   205 	 * If we're going to need to stat anything or we want to descend
       
   206 	 * and stay in the directory, chdir.  If this fails we keep going,
       
   207 	 * but set a flag so we don't chdir after the post-order visit.
       
   208 	 * We won't be able to stat anything, but we can still return the
       
   209 	 * names themselves.  Note, that since fts_read won't be able to
       
   210 	 * chdir into the directory, it will have to return different path
       
   211 	 * names than before, i.e. "a/b" instead of "b".  Since the node
       
   212 	 * has already been visited in pre-order, have to wait until the
       
   213 	 * post-order visit to return the error.  There is a special case
       
   214 	 * here, if there was nothing to stat then it's not an error to
       
   215 	 * not be able to stat.  This is all fairly nasty.  If a program
       
   216 	 * needed sorted entries or stat information, they had better be
       
   217 	 * checking FTS_NS on the returned nodes.
       
   218 	 */
       
   219 	cderrno = 0;
       
   220 	if (nlinks || type == BREAD) {
       
   221 		if (fts_safe_changedir(sp, cur, dirfd(dirp))) {
       
   222 			if (nlinks && type == BREAD)
       
   223 				cur->fts_errno = errno;
       
   224 			cur->fts_flags |= FTS_DONTCHDIR;
       
   225 			descend = 0;
       
   226 			cderrno = errno;
       
   227 			(void)closedir(dirp);
       
   228 			dirp = NULL;
       
   229 		} else
       
   230 			descend = 1;
       
   231 	} else
       
   232 		descend = 0;
       
   233 
       
   234 	/*
       
   235 	 * Figure out the max file name length that can be stored in the
       
   236 	 * current path -- the inner loop allocates more path as necessary.
       
   237 	 * We really wouldn't have to do the maxlen calculations here, we
       
   238 	 * could do them in fts_read before returning the path, but it's a
       
   239 	 * lot easier here since the length is part of the dirent structure.
       
   240 	 *
       
   241 	 * If not changing directories set a pointer so that can just append
       
   242 	 * each new name into the path.
       
   243 	 */
       
   244 	len = NAPPEND(cur);
       
   245 	if (ISSET(FTS_NOCHDIR)) {
       
   246 		cp = sp->fts_path + len;
       
   247 		*cp++ = '\\';
       
   248 	}
       
   249 	len++;
       
   250 	maxlen = sp->fts_pathlen - len;
       
   251 
       
   252 	level = cur->fts_level + 1;
       
   253 
       
   254 	/* Read the directory, attaching each entry to the `link' pointer. */
       
   255 	doadjust = 0;
       
   256 	for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
       
   257 		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
       
   258 			continue;
       
   259 
       
   260 		if ((p = fts_alloc(sp, dp->d_name, dp->d_namlen)) == NULL)
       
   261 			goto mem1;
       
   262 		if (dp->d_namlen >= maxlen) {	/* include space for NUL */
       
   263 			oldaddr = sp->fts_path;
       
   264 			if (fts_palloc(sp, dp->d_namlen +len + 1)) {
       
   265 				/*
       
   266 				 * No more memory for path or structures.  Save
       
   267 				 * errno, free up the current structure and the
       
   268 				 * structures already allocated.
       
   269 				 */
       
   270 mem1:				saved_errno = errno;
       
   271 				if (p)
       
   272 					free(p);
       
   273 				fts_lfree(head);
       
   274 				(void)closedir(dirp);
       
   275 				cur->fts_info = FTS_ERR;
       
   276 				SET(FTS_STOP);
       
   277 				errno = saved_errno;
       
   278 				return (NULL);
       
   279 			}
       
   280 			/* Did realloc() change the pointer? */
       
   281 			if (oldaddr != sp->fts_path) {
       
   282 				doadjust = 1;
       
   283 				if (ISSET(FTS_NOCHDIR))
       
   284 					cp = sp->fts_path + len;
       
   285 			}
       
   286 			maxlen = sp->fts_pathlen - len;
       
   287 		}
       
   288 
       
   289 		if (len + dp->d_namlen >= USHRT_MAX) {
       
   290 			/*
       
   291 			 * In an FTSENT, fts_pathlen is a u_short so it is
       
   292 			 * possible to wraparound here.  If we do, free up
       
   293 			 * the current structure and the structures already
       
   294 			 * allocated, then error out with ENAMETOOLONG.
       
   295 			 */
       
   296 			free(p);
       
   297 			fts_lfree(head);
       
   298 			(void)closedir(dirp);
       
   299 			cur->fts_info = FTS_ERR;
       
   300 			SET(FTS_STOP);
       
   301 			errno = ENAMETOOLONG;
       
   302 			return (NULL);
       
   303 		}
       
   304 		p->fts_level = level;
       
   305 		p->fts_parent = sp->fts_cur;
       
   306 		p->fts_pathlen = len + dp->d_namlen;
       
   307 
       
   308 #ifdef FTS_WHITEOUT
       
   309 		if (dp->d_type == DT_WHT)
       
   310 			p->fts_flags |= FTS_ISW;
       
   311 #endif
       
   312 
       
   313 		if (nlinks == 0 || (nostat &&
       
   314 		    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
       
   315 		    ) {
       
   316 			p->fts_accpath =
       
   317 			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
       
   318 			p->fts_info = FTS_NSOK;
       
   319 		} else {
       
   320 			/* Build a file name for fts_stat to stat. */
       
   321 			if (ISSET(FTS_NOCHDIR)) {
       
   322 				p->fts_accpath = p->fts_path;
       
   323 				memmove(cp, p->fts_name, p->fts_namelen + 1);
       
   324 			} else
       
   325 				p->fts_accpath = p->fts_name;
       
   326 			/* Stat it. */
       
   327 			p->fts_info = fts_stat(sp, p, 0);
       
   328 
       
   329 			/* Decrement link count if applicable. */
       
   330 			if (nlinks > 0 && (p->fts_info == FTS_D ||
       
   331 			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
       
   332 				--nlinks;
       
   333 		}
       
   334 
       
   335 		/* We walk in directory order so "ls -f" doesn't get upset. */
       
   336 		p->fts_link = NULL;
       
   337 		if (head == NULL)
       
   338 			head = tail = p;
       
   339 		else {
       
   340 			tail->fts_link = p;
       
   341 			tail = p;
       
   342 		}
       
   343 		++nitems;
       
   344 	}
       
   345 	if (dirp)
       
   346 		(void)closedir(dirp);
       
   347 
       
   348 	/*
       
   349 	 * If realloc() changed the address of the path, adjust the
       
   350 	 * addresses for the rest of the tree and the dir list.
       
   351 	 */
       
   352 	if (doadjust)
       
   353 		fts_padjust(sp, head);
       
   354 
       
   355 	/*
       
   356 	 * If not changing directories, reset the path back to original
       
   357 	 * state.
       
   358 	 */
       
   359 	if (ISSET(FTS_NOCHDIR)) {
       
   360 		if (len == sp->fts_pathlen || nitems == 0)
       
   361 			--cp;
       
   362 		*cp = '\0';
       
   363 	}
       
   364 
       
   365 	/*
       
   366 	 * If descended after called from fts_children or after called from
       
   367 	 * fts_read and nothing found, get back.  At the root level we use
       
   368 	 * the saved fd; if one of fts_open()'s arguments is a relative path
       
   369 	 * to an empty directory, we wind up here with no other way back.  If
       
   370 	 * can't get back, we're done.
       
   371 	 */
       
   372 	if (descend && (type == BCHILD || !nitems) &&
       
   373 	    (cur->fts_level == FTS_ROOTLEVEL ?
       
   374 	    FCHDIR(sp, sp->fts_rfd) : CHDIR(sp, ".."))) {
       
   375 		cur->fts_info = FTS_ERR;
       
   376 		SET(FTS_STOP);
       
   377 		return (NULL);
       
   378 	}
       
   379 
       
   380 	/* If didn't find anything, return NULL. */
       
   381 	if (!nitems && (head == NULL)) {
       
   382 		if (type == BREAD)
       
   383 			cur->fts_info = FTS_DP;
       
   384 		return (NULL);
       
   385 	}
       
   386 
       
   387 	/* Sort the entries. */
       
   388 	if (sp->fts_compar && nitems > 1)
       
   389 		head = fts_sort(sp, head, nitems);
       
   390 	return (head);
       
   391 }
       
   392 
       
   393 static u_short
       
   394 fts_stat(sp, p, follow)
       
   395 	FTS *sp;
       
   396 	register FTSENT *p;
       
   397 	int follow;
       
   398 {
       
   399 
       
   400 	register dev_t dev;
       
   401 	register ino_t ino;
       
   402 	struct stat *sbp, sb;
       
   403 	int saved_errno;
       
   404 
       
   405 	/* If user needs stat info, stat buffer already allocated. */
       
   406 	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
       
   407 
       
   408 #ifdef FTS_WHITEOUT
       
   409 	/* check for whiteout */
       
   410 	if (p->fts_flags & FTS_ISW) {
       
   411 		if (sbp != &sb) {
       
   412 			memset(sbp, '\0', sizeof (*sbp));
       
   413 			sbp->st_mode = S_IFWHT;
       
   414 		}
       
   415 		return (FTS_W);
       
   416 	}
       
   417 #endif
       
   418 
       
   419 	/*
       
   420 	 * If doing a logical walk, or application requested FTS_FOLLOW, do
       
   421 	 * a stat(2).  If that fails, check for a non-existent symlink.  If
       
   422 	 * fail, set the errno from the stat call.
       
   423 	 */
       
   424 	if (ISSET(FTS_LOGICAL) || follow) {
       
   425 		if (stat(p->fts_accpath, sbp)) {
       
   426 			saved_errno = errno;
       
   427 			if (!lstat(p->fts_accpath, sbp)) {
       
   428 				errno = 0;
       
   429 				return (FTS_SLNONE);
       
   430 			}
       
   431 			p->fts_errno = saved_errno;
       
   432 			goto err;
       
   433 		}
       
   434 	} else if (lstat(p->fts_accpath, sbp)) {
       
   435 		p->fts_errno = errno;
       
   436 err:		memset(sbp, 0, sizeof(struct stat));
       
   437 		return (FTS_NS);
       
   438 	}
       
   439 
       
   440 	if (S_ISDIR(sbp->st_mode)) {
       
   441 		/*
       
   442 		 * Set the device/inode.  Used to find cycles and check for
       
   443 		 * crossing mount points.  Also remember the link count, used
       
   444 		 * in fts_build to limit the number of stat calls.  It is
       
   445 		 * understood that these fields are only referenced if fts_info
       
   446 		 * is set to FTS_D.
       
   447 		 */
       
   448 		dev = p->fts_dev = sbp->st_dev;
       
   449 		ino = p->fts_ino = sbp->st_ino;
       
   450 		p->fts_nlink = sbp->st_nlink;
       
   451 
       
   452 		if (ISDOT(p->fts_name))
       
   453 			return (FTS_DOT);
       
   454 
       
   455 		/*
       
   456 		 * Cycle detection is done by brute force when the directory
       
   457 		 * is first encountered.  If the tree gets deep enough or the
       
   458 		 * number of symbolic links to directories is high enough,
       
   459 		 * something faster might be worthwhile.
       
   460 		 */
       
   461 #ifndef __SYMBIAN32__		 
       
   462 		//fts_ino is set
       
   463 		for (t = p->fts_parent;
       
   464 		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
       
   465 			if (ino == t->fts_ino && dev == t->fts_dev) {
       
   466 				p->fts_cycle = t;
       
   467 				return (FTS_DC);
       
   468 			}
       
   469 #endif
       
   470 		return (FTS_D);
       
   471 	}
       
   472 	if (S_ISLNK(sbp->st_mode))
       
   473 		return (FTS_SL);
       
   474 	if (S_ISREG(sbp->st_mode))
       
   475 		return (FTS_F);
       
   476 	return (FTS_DEFAULT);
       
   477 }
       
   478 
       
   479 typedef int (*qsType)(const void *, const void *);
       
   480 
       
   481 static FTSENT *
       
   482 fts_sort(sp, head, nitems)
       
   483 	FTS *sp;
       
   484 	FTSENT *head;
       
   485 	register size_t nitems;
       
   486 {
       
   487 	register FTSENT **ap, *p;
       
   488 
       
   489 	/*
       
   490 	 * Construct an array of pointers to the structures and call qsort(3).
       
   491 	 * Reassemble the array in the order returned by qsort.  If unable to
       
   492 	 * sort for memory reasons, return the directory entries in their
       
   493 	 * current order.  Allocate enough space for the current needs plus
       
   494 	 * 40 so don't realloc one entry at a time.
       
   495 	 */
       
   496 	if (nitems > sp->fts_nitems) {
       
   497 		struct _ftsent **a;
       
   498 
       
   499 		sp->fts_nitems = nitems + 40;
       
   500 		if ((a = realloc(sp->fts_array,
       
   501 		    sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
       
   502 			if (sp->fts_array)
       
   503 				free(sp->fts_array);
       
   504 			sp->fts_array = NULL;
       
   505 			sp->fts_nitems = 0;
       
   506 			return (head);
       
   507 		}
       
   508 		sp->fts_array = a;
       
   509 	}
       
   510 	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
       
   511 		*ap++ = p;
       
   512 	qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), 
       
   513 		(qsType)sp->fts_compar);
       
   514 	for (head = *(ap = sp->fts_array); --nitems; ++ap)
       
   515 		ap[0]->fts_link = ap[1];
       
   516 	ap[0]->fts_link = NULL;
       
   517 	return (head);
       
   518 }
       
   519 
       
   520 static FTSENT *
       
   521 fts_alloc(sp, name, namelen)
       
   522 	FTS *sp;
       
   523 	char *name;
       
   524 	register size_t namelen;
       
   525 {
       
   526 	register FTSENT *p;
       
   527 	size_t len;
       
   528 
       
   529 	/*
       
   530 	 * The file name is a variable length array and no stat structure is
       
   531 	 * necessary if the user has set the nostat bit.  Allocate the FTSENT
       
   532 	 * structure, the file name and the stat structure in one chunk, but
       
   533 	 * be careful that the stat structure is reasonably aligned.  Since the
       
   534 	 * fts_name field is declared to be of size 1, the fts_name pointer is
       
   535 	 * namelen + 2 before the first possible address of the stat structure.
       
   536 	 */
       
   537 	len = sizeof(FTSENT) + namelen;
       
   538 	if (!ISSET(FTS_NOSTAT))
       
   539 		len += sizeof(struct stat) + ALIGNBYTES;
       
   540 	if ((p = malloc(len)) == NULL)
       
   541 		return (NULL);
       
   542 
       
   543 	/* Copy the name and guarantee NUL termination. */
       
   544 	memmove(p->fts_name, name, namelen);
       
   545 	p->fts_name[namelen] = '\0';
       
   546 
       
   547 	if (!ISSET(FTS_NOSTAT))
       
   548 		p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
       
   549 	p->fts_namelen = namelen;
       
   550 	p->fts_path = sp->fts_path;
       
   551 	p->fts_errno = 0;
       
   552 	p->fts_flags = 0;
       
   553 	p->fts_instr = FTS_NOINSTR;
       
   554 	p->fts_number = 0;
       
   555 	p->fts_pointer = NULL;
       
   556 	return (p);
       
   557 }
       
   558 
       
   559 static void
       
   560 fts_lfree(head)
       
   561 	register FTSENT *head;
       
   562 {
       
   563 	register FTSENT *p;
       
   564 
       
   565 	/* Free a linked list of structures. */
       
   566 	while ((p = head)) {
       
   567 		head = head->fts_link;
       
   568 		free(p);
       
   569 	}
       
   570 }
       
   571 
       
   572 /*
       
   573  * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
       
   574  * Most systems will allow creation of paths much longer than MAXPATHLEN, even
       
   575  * though the kernel won't resolve them.  Add the size (not just what's needed)
       
   576  * plus 256 bytes so don't realloc the path 2 bytes at a time.
       
   577  */
       
   578 static int
       
   579 fts_palloc(sp, more)
       
   580 	FTS *sp;
       
   581 	size_t more;
       
   582 {
       
   583 	char *p;
       
   584 
       
   585 	sp->fts_pathlen += more + 256;
       
   586 	/*
       
   587 	 * Check for possible wraparound.  In an FTS, fts_pathlen is
       
   588 	 * a signed int but in an FTSENT it is an unsigned short.
       
   589 	 * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
       
   590 	 */
       
   591 	if (/* sp->fts_pathlen < 0 || */ sp->fts_pathlen >= USHRT_MAX) {
       
   592 		if (sp->fts_path)
       
   593 			free(sp->fts_path);
       
   594 		sp->fts_path = NULL;
       
   595 		errno = ENAMETOOLONG;
       
   596 		return (1);
       
   597 	}
       
   598 	p = realloc(sp->fts_path, sp->fts_pathlen);
       
   599 	if (p == NULL) {
       
   600 		if (sp->fts_path)
       
   601 			free(sp->fts_path);
       
   602 		sp->fts_path = NULL;
       
   603 		return (1);
       
   604 	}
       
   605 	sp->fts_path = p;
       
   606 	return (0);
       
   607 }
       
   608 
       
   609 /*
       
   610  * When the path is realloc'd, have to fix all of the pointers in structures
       
   611  * already returned.
       
   612  */
       
   613 static void
       
   614 fts_padjust(sp, head)
       
   615 	FTS *sp;
       
   616 	FTSENT *head;
       
   617 {
       
   618 	FTSENT *p;
       
   619 	char *addr = sp->fts_path;
       
   620 
       
   621 #define	ADJUST(p) {							\
       
   622 	if ((p)->fts_accpath != (p)->fts_name) {			\
       
   623 		(p)->fts_accpath =					\
       
   624 		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
       
   625 	}								\
       
   626 	(p)->fts_path = addr;						\
       
   627 }
       
   628 	/* Adjust the current set of children. */
       
   629 	for (p = sp->fts_child; p; p = p->fts_link)
       
   630 		ADJUST(p);
       
   631 
       
   632 	/* Adjust the rest of the tree, including the current level. */
       
   633 	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
       
   634 		ADJUST(p);
       
   635 		p = p->fts_link ? p->fts_link : p->fts_parent;
       
   636 	}
       
   637 }
       
   638 
       
   639 static size_t
       
   640 fts_maxarglen(argv)
       
   641 	char * const *argv;
       
   642 {
       
   643 	size_t len, max;
       
   644 
       
   645 	for (max = 0; *argv; ++argv)
       
   646 		if ((len = strlen(*argv)) > max)
       
   647 			max = len;
       
   648 	return (max + 1);
       
   649 }
       
   650 
       
   651 /*
       
   652  * Change to dir specified by fd or p->fts_accpath without getting
       
   653  * tricked by someone changing the world out from underneath us.
       
   654  * Assumes p->fts_dev and p->fts_ino are filled in.
       
   655  */
       
   656 static int
       
   657 fts_safe_changedir(sp, p, fd)
       
   658 	FTS *sp;
       
   659 	FTSENT *p;
       
   660 	int fd;
       
   661 {
       
   662 #ifndef __NO_FCHDIR
       
   663 	int ret, oerrno, newfd;
       
   664 	struct stat sb;
       
   665 
       
   666 	newfd = fd;
       
   667 	if (ISSET(FTS_NOCHDIR))
       
   668 		return (0);
       
   669 	if (fd < 0 && (newfd = open(p->fts_accpath, O_RDONLY, 0)) < 0)
       
   670 		return (-1);
       
   671 	if (fstat(newfd, &sb)) {
       
   672 		ret = -1;
       
   673 		goto bail;
       
   674 	}
       
   675 	if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
       
   676 		errno = ENOENT;		/* disinformation */
       
   677 		ret = -1;
       
   678 		goto bail;
       
   679 	}
       
   680 	ret = fchdir(newfd);
       
   681 bail:
       
   682 	oerrno = errno;
       
   683 	if (fd < 0)
       
   684 		(void)close(newfd);
       
   685 	errno = oerrno;
       
   686 	return (ret);
       
   687 #else
       
   688 	return (0);
       
   689 #endif
       
   690 }
       
   691 
       
   692 
       
   693 FTS *
       
   694 fts_open(argv, options, compar)
       
   695 	char * const *argv;
       
   696 	register int options;
       
   697 	int (*compar)(const FTSENT **, const FTSENT **);
       
   698 {
       
   699 	register FTS *sp;
       
   700 	register FTSENT *p, *root;
       
   701 	register size_t nitems;
       
   702 	FTSENT *parent, *tmp = NULL;
       
   703 	size_t len;
       
   704 
       
   705 	/* Options check. */
       
   706 	if (options & ~FTS_OPTIONMASK) {
       
   707 		errno = EINVAL;
       
   708 		return (NULL);
       
   709 	}
       
   710 
       
   711 	/* Allocate/initialize the stream */
       
   712 	if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
       
   713 		return (NULL);
       
   714 	memset(sp, 0, sizeof(FTS));
       
   715 	sp->fts_compar = compar;
       
   716 #ifndef __NO_FCHDIR 
       
   717 	sp->fts_options = options;
       
   718 
       
   719 	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
       
   720 	if (ISSET(FTS_LOGICAL))
       
   721 		SET(FTS_NOCHDIR);
       
   722 #else
       
   723 	sp->fts_options = options | FTS_NOCHDIR;
       
   724 #endif
       
   725 	/*
       
   726 	 * Start out with 1K of path space, and enough, in any case,
       
   727 	 * to hold the user's paths.
       
   728 	 */
       
   729 	if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
       
   730 		goto mem1;
       
   731 
       
   732 	/* Allocate/initialize root's parent. */
       
   733 	if ((parent = fts_alloc(sp, "", 0)) == NULL)
       
   734 		goto mem2;
       
   735 	parent->fts_level = FTS_ROOTPARENTLEVEL;
       
   736 
       
   737 	/* Allocate/initialize root(s). */
       
   738 	for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
       
   739 		/* Don't allow zero-length paths. */
       
   740 		if ((len = strlen(*argv)) == 0) {
       
   741 			errno = ENOENT;
       
   742 			goto mem3;
       
   743 		}
       
   744 
       
   745 		p = fts_alloc(sp, *argv, len);
       
   746 		p->fts_level = FTS_ROOTLEVEL;
       
   747 		p->fts_parent = parent;
       
   748 		p->fts_accpath = p->fts_name;
       
   749 		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
       
   750 
       
   751 		/* Command-line "." and ".." are real directories. */
       
   752 		if (p->fts_info == FTS_DOT)
       
   753 			p->fts_info = FTS_D;
       
   754 
       
   755 		/*
       
   756 		 * If comparison routine supplied, traverse in sorted
       
   757 		 * order; otherwise traverse in the order specified.
       
   758 		 */
       
   759 		if (compar) {
       
   760 			p->fts_link = root;
       
   761 			root = p;
       
   762 		} else {
       
   763 			p->fts_link = NULL;
       
   764 			if (root == NULL)
       
   765 				tmp = root = p;
       
   766 			else {
       
   767 				tmp->fts_link = p;
       
   768 				tmp = p;
       
   769 			}
       
   770 		}
       
   771 	}
       
   772 	if (compar && nitems > 1)
       
   773 		root = fts_sort(sp, root, nitems);
       
   774 
       
   775 	/*
       
   776 	 * Allocate a dummy pointer and make fts_read think that we've just
       
   777 	 * finished the node before the root(s); set p->fts_info to FTS_INIT
       
   778 	 * so that everything about the "current" node is ignored.
       
   779 	 */
       
   780 	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
       
   781 		goto mem3;
       
   782 	sp->fts_cur->fts_link = root;
       
   783 	sp->fts_cur->fts_info = FTS_INIT;
       
   784 
       
   785 #ifndef __NO_FCHDIR 
       
   786 	/*
       
   787 	 * If using chdir(2), grab a file descriptor pointing to dot to ensure
       
   788 	 * that we can get back here; this could be avoided for some paths,
       
   789 	 * but almost certainly not worth the effort.  Slashes, symbolic links,
       
   790 	 * and ".." are all fairly nasty problems.  Note, if we can't get the
       
   791 	 * descriptor we run anyway, just more slowly.
       
   792 	 */
       
   793 	if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
       
   794 		SET(FTS_NOCHDIR);
       
   795 #endif
       
   796 
       
   797 	return (sp);
       
   798 
       
   799 mem3:	fts_lfree(root);
       
   800 	free(parent);
       
   801 mem2:	free(sp->fts_path);
       
   802 mem1:	free(sp);
       
   803 	return (NULL);
       
   804 }
       
   805 
       
   806 
       
   807 int
       
   808 fts_close(sp)
       
   809 	FTS *sp;
       
   810 {
       
   811 	register FTSENT *freep, *p;
       
   812 	/* int saved_errno = 0; */
       
   813 
       
   814 	/*
       
   815 	 * This still works if we haven't read anything -- the dummy structure
       
   816 	 * points to the root list, so we step through to the end of the root
       
   817 	 * list which has a valid parent pointer.
       
   818 	 */
       
   819 	if (sp->fts_cur) {
       
   820 		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
       
   821 			freep = p;
       
   822 			p = p->fts_link ? p->fts_link : p->fts_parent;
       
   823 			free(freep);
       
   824 		}
       
   825 		free(p);
       
   826 	}
       
   827 
       
   828 	/* Free up child linked list, sort array, path buffer. */
       
   829 	if (sp->fts_child)
       
   830 		fts_lfree(sp->fts_child);
       
   831 	if (sp->fts_array)
       
   832 		free(sp->fts_array);
       
   833 	free(sp->fts_path);
       
   834 
       
   835 #ifndef __NO_FCHDIR 
       
   836 	/* Return to original directory, save errno if necessary. */
       
   837 	if (!ISSET(FTS_NOCHDIR)) {
       
   838 		saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
       
   839 		(void)close(sp->fts_rfd);
       
   840 	}
       
   841 	/* Set errno and return. */
       
   842 	if (!ISSET(FTS_NOCHDIR) && saved_errno) {
       
   843 		/* Free up the stream pointer. */
       
   844 		free(sp);
       
   845 		errno = saved_errno;
       
   846 		return (-1);
       
   847 	}
       
   848 #endif
       
   849 
       
   850 	/* Free up the stream pointer. */
       
   851 	free(sp);
       
   852 	return (0);
       
   853 }
       
   854 
       
   855 FTSENT *
       
   856 fts_read(sp)
       
   857 	register FTS *sp;
       
   858 {
       
   859 	register FTSENT *p, *tmp;
       
   860 	register int instr;
       
   861 	register char *t;
       
   862 	/* int saved_errno; */
       
   863 
       
   864 	/* If finished or unrecoverable error, return NULL. */
       
   865 	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
       
   866 		return (NULL);
       
   867 
       
   868 	/* Set current node pointer. */
       
   869 	p = sp->fts_cur;
       
   870 
       
   871 	/* Save and zero out user instructions. */
       
   872 	instr = p->fts_instr;
       
   873 	p->fts_instr = FTS_NOINSTR;
       
   874 
       
   875 	/* Any type of file may be re-visited; re-stat and re-turn. */
       
   876 	if (instr == FTS_AGAIN) {
       
   877 		p->fts_info = fts_stat(sp, p, 0);
       
   878 		return (p);
       
   879 	}
       
   880 
       
   881 	/*
       
   882 	 * Following a symlink -- SLNONE test allows application to see
       
   883 	 * SLNONE and recover.  If indirecting through a symlink, have
       
   884 	 * keep a pointer to current location.  If unable to get that
       
   885 	 * pointer, follow fails.
       
   886 	 */
       
   887 	if (instr == FTS_FOLLOW &&
       
   888 	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
       
   889 		p->fts_info = fts_stat(sp, p, 1);
       
   890 		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
       
   891 			if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
       
   892 				p->fts_errno = errno;
       
   893 				p->fts_info = FTS_ERR;
       
   894 			} else
       
   895 				p->fts_flags |= FTS_SYMFOLLOW;
       
   896 		}
       
   897 		return (p);
       
   898 	}
       
   899 
       
   900 	/* Directory in pre-order. */
       
   901 	if (p->fts_info == FTS_D) {
       
   902 		/* If skipped or crossed mount point, do post-order visit. */
       
   903 		if (instr == FTS_SKIP ||
       
   904 		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
       
   905 			if (p->fts_flags & FTS_SYMFOLLOW)
       
   906 				(void)close(p->fts_symfd);
       
   907 			if (sp->fts_child) {
       
   908 				fts_lfree(sp->fts_child);
       
   909 				sp->fts_child = NULL;
       
   910 			}
       
   911 			p->fts_info = FTS_DP;
       
   912 			return (p);
       
   913 		}
       
   914 
       
   915 		/* Rebuild if only read the names and now traversing. */
       
   916 		if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
       
   917 			CLR(FTS_NAMEONLY);
       
   918 			fts_lfree(sp->fts_child);
       
   919 			sp->fts_child = NULL;
       
   920 		}
       
   921 
       
   922 		/*
       
   923 		 * Cd to the subdirectory.
       
   924 		 *
       
   925 		 * If have already read and now fail to chdir, whack the list
       
   926 		 * to make the names come out right, and set the parent errno
       
   927 		 * so the application will eventually get an error condition.
       
   928 		 * Set the FTS_DONTCHDIR flag so that when we logically change
       
   929 		 * directories back to the parent we don't do a chdir.
       
   930 		 *
       
   931 		 * If haven't read do so.  If the read fails, fts_build sets
       
   932 		 * FTS_STOP or the fts_info field of the node.
       
   933 		 */
       
   934 		if (sp->fts_child) {
       
   935 			if (fts_safe_changedir(sp, p, -1)) {
       
   936 				p->fts_errno = errno;
       
   937 				p->fts_flags |= FTS_DONTCHDIR;
       
   938 				for (p = sp->fts_child; p; p = p->fts_link)
       
   939 					p->fts_accpath =
       
   940 					    p->fts_parent->fts_accpath;
       
   941 			}
       
   942 		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
       
   943 			if (ISSET(FTS_STOP))
       
   944 				return (NULL);
       
   945 			return (p);
       
   946 		}
       
   947 		p = sp->fts_child;
       
   948 		sp->fts_child = NULL;
       
   949 		goto name;
       
   950 	}
       
   951 
       
   952 	/* Move to the next node on this level. */
       
   953 next:	tmp = p;
       
   954 	if ((p = p->fts_link)) {
       
   955 		free(tmp);
       
   956 
       
   957 		/*
       
   958 		 * If reached the top, return to the original directory (or
       
   959 		 * the root of the tree), and load the paths for the next root.
       
   960 		 */
       
   961 		if (p->fts_level == FTS_ROOTLEVEL) {
       
   962 			if ((sp->fts_options & FTS_CHDIRROOT)) {
       
   963 				if (chdir(p->fts_accpath)) {
       
   964 					SET(FTS_STOP);
       
   965 					return (NULL);
       
   966 				}
       
   967 			} else {
       
   968 				if (FCHDIR(sp, sp->fts_rfd)) {
       
   969 					SET(FTS_STOP);
       
   970 					return (NULL);
       
   971 				}
       
   972 			}
       
   973 			fts_load(sp, p);
       
   974 			return (sp->fts_cur = p);
       
   975 		}
       
   976 
       
   977 		/*
       
   978 		 * User may have called fts_set on the node.  If skipped,
       
   979 		 * ignore.  If followed, get a file descriptor so we can
       
   980 		 * get back if necessary.
       
   981 		 */
       
   982 		if (p->fts_instr == FTS_SKIP)
       
   983 			goto next;
       
   984 		if (p->fts_instr == FTS_FOLLOW) {
       
   985 			p->fts_info = fts_stat(sp, p, 1);
       
   986 			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
       
   987 				if ((p->fts_symfd =
       
   988 				    open(".", O_RDONLY, 0)) < 0) {
       
   989 					p->fts_errno = errno;
       
   990 					p->fts_info = FTS_ERR;
       
   991 				} else
       
   992 					p->fts_flags |= FTS_SYMFOLLOW;
       
   993 			}
       
   994 			p->fts_instr = FTS_NOINSTR;
       
   995 		}
       
   996 
       
   997 name:		t = sp->fts_path + NAPPEND(p->fts_parent);
       
   998 		*t++ = '\\';
       
   999 		memmove(t, p->fts_name, p->fts_namelen + 1);
       
  1000 		return (sp->fts_cur = p);
       
  1001 	}
       
  1002 
       
  1003 	/* Move up to the parent node. */
       
  1004 	p = tmp->fts_parent;
       
  1005 	free(tmp);
       
  1006 
       
  1007 	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
       
  1008 		/*
       
  1009 		 * Done; free everything up and set errno to 0 so the user
       
  1010 		 * can distinguish between error and EOF.
       
  1011 		 */
       
  1012 		free(p);
       
  1013 		errno = 0;
       
  1014 		return (sp->fts_cur = NULL);
       
  1015 	}
       
  1016 
       
  1017 	/* NUL terminate the pathname. */
       
  1018 	sp->fts_path[p->fts_pathlen] = '\0';
       
  1019 
       
  1020 	/*
       
  1021 	 * Return to the parent directory.  If at a root node or came through
       
  1022 	 * a symlink, go back through the file descriptor.  Otherwise, cd up
       
  1023 	 * one directory.
       
  1024 	 */
       
  1025 	if (p->fts_level == FTS_ROOTLEVEL) {
       
  1026 		if ((sp->fts_options & FTS_CHDIRROOT)) {
       
  1027 			if (chdir(p->fts_accpath)) {
       
  1028 				SET(FTS_STOP);
       
  1029 				return (NULL);
       
  1030 			}
       
  1031 		} else {
       
  1032 			if (FCHDIR(sp, sp->fts_rfd)) {
       
  1033 				SET(FTS_STOP);
       
  1034 				return (NULL);
       
  1035 			}
       
  1036 		}
       
  1037 	} else if (p->fts_flags & FTS_SYMFOLLOW) {
       
  1038 #ifndef __NO_FCHDIR 
       
  1039 		if (FCHDIR(sp, p->fts_symfd)) {
       
  1040 			saved_errno = errno;
       
  1041 			(void)close(p->fts_symfd);
       
  1042 			errno = saved_errno;
       
  1043 			SET(FTS_STOP);
       
  1044 			return (NULL);
       
  1045 		}
       
  1046 #endif
       
  1047 		(void)close(p->fts_symfd);
       
  1048 	} else if (!(p->fts_flags & FTS_DONTCHDIR)) {
       
  1049 		if (CHDIR(sp, "..")) {
       
  1050 			SET(FTS_STOP);
       
  1051 			return (NULL);
       
  1052 		}
       
  1053 	}
       
  1054 	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
       
  1055 	return (sp->fts_cur = p);
       
  1056 }
       
  1057 
       
  1058 /*
       
  1059  * Fts_set takes the stream as an argument although it's not used in this
       
  1060  * implementation; it would be necessary if anyone wanted to add global
       
  1061  * semantics to fts using fts_set.  An error return is allowed for similar
       
  1062  * reasons.
       
  1063  */
       
  1064 /* ARGSUSED */
       
  1065 int
       
  1066 fts_set(FTS *sp_dummy, FTSENT *p, int instr)
       
  1067 {
       
  1068 	if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
       
  1069 	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
       
  1070 		errno = EINVAL;
       
  1071 		return (1);
       
  1072 	}
       
  1073 	p->fts_instr = instr;
       
  1074 	return (0);
       
  1075 }
       
  1076 
       
  1077 FTSENT *
       
  1078 fts_children(sp, instr)
       
  1079 	register FTS *sp;
       
  1080 	int instr;
       
  1081 {
       
  1082 	register FTSENT *p;
       
  1083 /*	int fd; */
       
  1084 
       
  1085 	if (instr && instr != FTS_NAMEONLY) {
       
  1086 		errno = EINVAL;
       
  1087 		return (NULL);
       
  1088 	}
       
  1089 
       
  1090 	/* Set current node pointer. */
       
  1091 	p = sp->fts_cur;
       
  1092 
       
  1093 	/*
       
  1094 	 * Errno set to 0 so user can distinguish empty directory from
       
  1095 	 * an error.
       
  1096 	 */
       
  1097 	errno = 0;
       
  1098 
       
  1099 	/* Fatal errors stop here. */
       
  1100 	if (ISSET(FTS_STOP))
       
  1101 		return (NULL);
       
  1102 
       
  1103 	/* Return logical hierarchy of user's arguments. */
       
  1104 	if (p->fts_info == FTS_INIT)
       
  1105 		return (p->fts_link);
       
  1106 
       
  1107 	/*
       
  1108 	 * If not a directory being visited in pre-order, stop here.  Could
       
  1109 	 * allow FTS_DNR, assuming the user has fixed the problem, but the
       
  1110 	 * same effect is available with FTS_AGAIN.
       
  1111 	 */
       
  1112 	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
       
  1113 		return (NULL);
       
  1114 
       
  1115 	/* Free up any previous child list. */
       
  1116 	if (sp->fts_child)
       
  1117 		fts_lfree(sp->fts_child);
       
  1118 
       
  1119 	if (instr == FTS_NAMEONLY) {
       
  1120 		SET(FTS_NAMEONLY);
       
  1121 		instr = BNAMES;
       
  1122 	} else
       
  1123 		instr = BCHILD;
       
  1124 
       
  1125 #ifndef __NO_FCHDIR 
       
  1126 	/*
       
  1127 	 * If using chdir on a relative path and called BEFORE fts_read does
       
  1128 	 * its chdir to the root of a traversal, we can lose -- we need to
       
  1129 	 * chdir into the subdirectory, and we don't know where the current
       
  1130 	 * directory is, so we can't get back so that the upcoming chdir by
       
  1131 	 * fts_read will work.
       
  1132 	 */
       
  1133 	if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '\\' ||
       
  1134 	    p->fts_accpath[0] == '\\' || ISSET(FTS_NOCHDIR))
       
  1135 		return (sp->fts_child = fts_build(sp, instr));
       
  1136 
       
  1137 	if ((fd = open(".", O_RDONLY, 0)) < 0)
       
  1138 		return (NULL);
       
  1139 	sp->fts_child = fts_build(sp, instr);
       
  1140 	if (fchdir(fd))
       
  1141 		return (NULL);
       
  1142 	(void)close(fd);
       
  1143 	return (sp->fts_child);
       
  1144 #else
       
  1145 	return (sp->fts_child = fts_build(sp, instr));
       
  1146 #endif
       
  1147 
       
  1148 }
       
  1149