New fts module.
[pspp] / lib / fts.c
1 /* Traverse a file hierarchy.
2
3    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 /*-
20  * Copyright (c) 1990, 1993, 1994
21  *      The Regents of the University of California.  All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 4. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif
51
52 #if defined(LIBC_SCCS) && !defined(lint)
53 static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
54 #endif /* LIBC_SCCS and not lint */
55
56 #include "fts_.h"
57
58 #if HAVE_SYS_PARAM_H || defined _LIBC
59 # include <sys/param.h>
60 #endif
61 #ifdef _LIBC
62 # include <include/sys/stat.h>
63 #else
64 # include <sys/stat.h>
65 #endif
66 #include <fcntl.h>
67 #include <errno.h>
68 #include "dirfd.h"
69 #include "unistd-safer.h"
70 #include <stdbool.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 #if HAVE_INTTYPES_H
75 # include <inttypes.h>
76 #endif
77 #if HAVE_STDINT_H
78 # include <stdint.h>
79 #endif
80 #if ULONG_MAX < ULLONG_MAX
81 # define LONGEST_MODIFIER "ll"
82 #else
83 # define LONGEST_MODIFIER "l"
84 #endif
85 #if PRI_MACROS_BROKEN
86 # undef PRIuMAX
87 #endif
88 #ifndef PRIuMAX
89 # define PRIuMAX LONGEST_MODIFIER "u"
90 #endif
91
92 #if defined _LIBC
93 # include <dirent.h>
94 # define NAMLEN(dirent) _D_EXACT_NAMLEN (dirent)
95 #else
96 # if HAVE_DIRENT_H
97 #  include <dirent.h>
98 #  define NAMLEN(dirent) strlen ((dirent)->d_name)
99 # else
100 #  define dirent direct
101 #  define NAMLEN(dirent) (dirent)->d_namlen
102 #  if HAVE_SYS_NDIR_H
103 #   include <sys/ndir.h>
104 #  endif
105 #  if HAVE_SYS_DIR_H
106 #   include <sys/dir.h>
107 #  endif
108 #  if HAVE_NDIR_H
109 #   include <ndir.h>
110 #  endif
111 # endif
112 #endif
113
114 #ifdef _LIBC
115 # undef close
116 # define close __close
117 # undef closedir
118 # define closedir __closedir
119 # undef fchdir
120 # define fchdir __fchdir
121 # undef open
122 # define open __open
123 # undef opendir
124 # define opendir __opendir
125 # undef readdir
126 # define readdir __readdir
127 #else
128 # undef internal_function
129 # define internal_function /* empty */
130 #endif
131
132 /* Arrange to make lstat calls go through the wrapper function
133    on systems with an lstat function that does not dereference symlinks
134    that are specified with a trailing slash.  */
135 #if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK
136 int rpl_lstat (const char *, struct stat *);
137 # undef lstat
138 # define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
139 #endif
140
141 #ifndef __set_errno
142 # define __set_errno(Val) errno = (Val)
143 #endif
144
145 #ifndef __attribute__
146 # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
147 #  define __attribute__(x) /* empty */
148 # endif
149 #endif
150
151 #ifndef ATTRIBUTE_UNUSED
152 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
153 #endif
154
155
156 static FTSENT   *fts_alloc (FTS *, const char *, size_t) internal_function;
157 static FTSENT   *fts_build (FTS *, int) internal_function;
158 static void      fts_lfree (FTSENT *) internal_function;
159 static void      fts_load (FTS *, FTSENT *) internal_function;
160 static size_t    fts_maxarglen (char * const *) internal_function;
161 static void      fts_padjust (FTS *, FTSENT *) internal_function;
162 static bool      fts_palloc (FTS *, size_t) internal_function;
163 static FTSENT   *fts_sort (FTS *, FTSENT *, size_t) internal_function;
164 static unsigned short int fts_stat (FTS *, FTSENT *, bool) internal_function;
165 static int      fts_safe_changedir (FTS *, FTSENT *, int, const char *)
166      internal_function;
167
168 #if _LGPL_PACKAGE
169 static bool enter_dir (FTS *fts, FTSENT *ent) { return true; }
170 static void leave_dir (FTS *fts, FTSENT *ent) {}
171 static bool setup_dir (FTS *fts) { return true; }
172 static void free_dir (FTS *fts) {}
173 #else
174 # include "fts-cycle.c"
175 #endif
176
177 #ifndef MAX
178 # define MAX(a,b) ((a) > (b) ? (a) : (b))
179 #endif
180
181 #ifndef SIZE_MAX
182 # define SIZE_MAX ((size_t) -1)
183 #endif
184
185 #ifndef O_DIRECTORY
186 # define O_DIRECTORY 0
187 #endif
188
189 #define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
190
191 #define CLR(opt)        (sp->fts_options &= ~(opt))
192 #define ISSET(opt)      (sp->fts_options & (opt))
193 #define SET(opt)        (sp->fts_options |= (opt))
194
195 #define FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))
196
197 /* fts_build flags */
198 #define BCHILD          1               /* fts_children */
199 #define BNAMES          2               /* fts_children, names only */
200 #define BREAD           3               /* fts_read */
201
202 #if FTS_DEBUG
203 bool fts_debug = false;
204 # include <stdio.h>
205 # define Dprintf(x) do { if (fts_debug) printf x; } while (0)
206 #else
207 # define Dprintf(x)
208 #endif
209
210 #define LEAVE_DIR(Fts, Ent, Tag)                                \
211   do                                                            \
212     {                                                           \
213       Dprintf (("  %s-leaving: %s\n", Tag, (Ent)->fts_path));   \
214       leave_dir (Fts, Ent);                                     \
215     }                                                           \
216   while (false)
217
218 /* Open the directory DIR if possible, and return a file
219    descriptor.  Return -1 and set errno on failure.  It doesn't matter
220    whether the file descriptor has read or write access.  */
221
222 static int
223 internal_function
224 diropen (char const *dir)
225 {
226   int fd = open (dir, O_RDONLY | O_DIRECTORY);
227   if (fd < 0)
228     fd = open (dir, O_WRONLY | O_DIRECTORY);
229   return fd;
230 }
231
232 FTS *
233 fts_open (char * const *argv,
234           register int options,
235           int (*compar) (FTSENT const **, FTSENT const **))
236 {
237         register FTS *sp;
238         register FTSENT *p, *root;
239         register size_t nitems;
240         FTSENT *parent, *tmp = NULL;    /* pacify gcc */
241         size_t len;
242
243         /* Options check. */
244         if (options & ~FTS_OPTIONMASK) {
245                 __set_errno (EINVAL);
246                 return (NULL);
247         }
248
249         /* Allocate/initialize the stream */
250         if ((sp = malloc(sizeof(FTS))) == NULL)
251                 return (NULL);
252         memset(sp, 0, sizeof(FTS));
253         sp->fts_compar = compar;
254         sp->fts_options = options;
255
256         /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
257         if (ISSET(FTS_LOGICAL))
258                 SET(FTS_NOCHDIR);
259
260         /*
261          * Start out with 1K of path space, and enough, in any case,
262          * to hold the user's paths.
263          */
264 #ifndef MAXPATHLEN
265 # define MAXPATHLEN 1024
266 #endif
267         if (! fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
268                 goto mem1;
269
270         /* Allocate/initialize root's parent. */
271         if ((parent = fts_alloc(sp, "", 0)) == NULL)
272                 goto mem2;
273         parent->fts_level = FTS_ROOTPARENTLEVEL;
274
275         /* Allocate/initialize root(s). */
276         for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
277                 /* Don't allow zero-length paths. */
278                 if ((len = strlen(*argv)) == 0) {
279                         __set_errno (ENOENT);
280                         goto mem3;
281                 }
282
283                 if ((p = fts_alloc(sp, *argv, len)) == NULL)
284                         goto mem3;
285                 p->fts_level = FTS_ROOTLEVEL;
286                 p->fts_parent = parent;
287                 p->fts_accpath = p->fts_name;
288                 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW) != 0);
289
290                 /* Command-line "." and ".." are real directories. */
291                 if (p->fts_info == FTS_DOT)
292                         p->fts_info = FTS_D;
293
294                 /*
295                  * If comparison routine supplied, traverse in sorted
296                  * order; otherwise traverse in the order specified.
297                  */
298                 if (compar) {
299                         p->fts_link = root;
300                         root = p;
301                 } else {
302                         p->fts_link = NULL;
303                         if (root == NULL)
304                                 tmp = root = p;
305                         else {
306                                 tmp->fts_link = p;
307                                 tmp = p;
308                         }
309                 }
310         }
311         if (compar && nitems > 1)
312                 root = fts_sort(sp, root, nitems);
313
314         /*
315          * Allocate a dummy pointer and make fts_read think that we've just
316          * finished the node before the root(s); set p->fts_info to FTS_INIT
317          * so that everything about the "current" node is ignored.
318          */
319         if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
320                 goto mem3;
321         sp->fts_cur->fts_link = root;
322         sp->fts_cur->fts_info = FTS_INIT;
323         if (! setup_dir (sp))
324           goto mem3;
325
326         /*
327          * If using chdir(2), grab a file descriptor pointing to dot to ensure
328          * that we can get back here; this could be avoided for some paths,
329          * but almost certainly not worth the effort.  Slashes, symbolic links,
330          * and ".." are all fairly nasty problems.  Note, if we can't get the
331          * descriptor we run anyway, just more slowly.
332          */
333         if (!ISSET(FTS_NOCHDIR)
334             && (sp->fts_rfd = diropen (".")) < 0)
335                 SET(FTS_NOCHDIR);
336
337         return (sp);
338
339 mem3:   fts_lfree(root);
340         free(parent);
341 mem2:   free(sp->fts_path);
342 mem1:   free(sp);
343         return (NULL);
344 }
345
346 static void
347 internal_function
348 fts_load (FTS *sp, register FTSENT *p)
349 {
350         register size_t len;
351         register char *cp;
352
353         /*
354          * Load the stream structure for the next traversal.  Since we don't
355          * actually enter the directory until after the preorder visit, set
356          * the fts_accpath field specially so the chdir gets done to the right
357          * place and the user can access the first node.  From fts_open it's
358          * known that the path will fit.
359          */
360         len = p->fts_pathlen = p->fts_namelen;
361         memmove(sp->fts_path, p->fts_name, len + 1);
362         if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
363                 len = strlen(++cp);
364                 memmove(p->fts_name, cp, len + 1);
365                 p->fts_namelen = len;
366         }
367         p->fts_accpath = p->fts_path = sp->fts_path;
368         sp->fts_dev = p->fts_statp->st_dev;
369 }
370
371 int
372 fts_close (FTS *sp)
373 {
374         register FTSENT *freep, *p;
375         int saved_errno = 0;
376
377         /*
378          * This still works if we haven't read anything -- the dummy structure
379          * points to the root list, so we step through to the end of the root
380          * list which has a valid parent pointer.
381          */
382         if (sp->fts_cur) {
383                 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
384                         freep = p;
385                         p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
386                         free(freep);
387                 }
388                 free(p);
389         }
390
391         /* Free up child linked list, sort array, path buffer. */
392         if (sp->fts_child)
393                 fts_lfree(sp->fts_child);
394         if (sp->fts_array)
395                 free(sp->fts_array);
396         free(sp->fts_path);
397
398         /* Return to original directory, save errno if necessary. */
399         if (!ISSET(FTS_NOCHDIR)) {
400                 if (fchdir(sp->fts_rfd))
401                         saved_errno = errno;
402                 (void)close(sp->fts_rfd);
403         }
404
405         free_dir (sp);
406
407         /* Free up the stream pointer. */
408         free(sp);
409
410         /* Set errno and return. */
411         if (saved_errno) {
412                 __set_errno (saved_errno);
413                 return (-1);
414         }
415
416         return (0);
417 }
418
419 /*
420  * Special case of "/" at the end of the path so that slashes aren't
421  * appended which would cause paths to be written as "....//foo".
422  */
423 #define NAPPEND(p)                                                      \
424         (p->fts_path[p->fts_pathlen - 1] == '/'                         \
425             ? p->fts_pathlen - 1 : p->fts_pathlen)
426
427 FTSENT *
428 fts_read (register FTS *sp)
429 {
430         register FTSENT *p, *tmp;
431         register unsigned short int instr;
432         register char *t;
433         int saved_errno;
434
435         /* If finished or unrecoverable error, return NULL. */
436         if (sp->fts_cur == NULL || ISSET(FTS_STOP))
437                 return (NULL);
438
439         /* Set current node pointer. */
440         p = sp->fts_cur;
441
442         /* Save and zero out user instructions. */
443         instr = p->fts_instr;
444         p->fts_instr = FTS_NOINSTR;
445
446         /* Any type of file may be re-visited; re-stat and re-turn. */
447         if (instr == FTS_AGAIN) {
448                 p->fts_info = fts_stat(sp, p, false);
449                 return (p);
450         }
451         Dprintf (("fts_read: p=%s\n",
452                   p->fts_info == FTS_INIT ? "" : p->fts_path));
453
454         /*
455          * Following a symlink -- SLNONE test allows application to see
456          * SLNONE and recover.  If indirecting through a symlink, have
457          * keep a pointer to current location.  If unable to get that
458          * pointer, follow fails.
459          */
460         if (instr == FTS_FOLLOW &&
461             (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
462                 p->fts_info = fts_stat(sp, p, true);
463                 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
464                         if ((p->fts_symfd = diropen (".")) < 0) {
465                                 p->fts_errno = errno;
466                                 p->fts_info = FTS_ERR;
467                         } else
468                                 p->fts_flags |= FTS_SYMFOLLOW;
469                 }
470                 goto check_for_dir;
471         }
472
473         /* Directory in pre-order. */
474         if (p->fts_info == FTS_D) {
475                 /* If skipped or crossed mount point, do post-order visit. */
476                 if (instr == FTS_SKIP ||
477                     (ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
478                         if (p->fts_flags & FTS_SYMFOLLOW)
479                                 (void)close(p->fts_symfd);
480                         if (sp->fts_child) {
481                                 fts_lfree(sp->fts_child);
482                                 sp->fts_child = NULL;
483                         }
484                         p->fts_info = FTS_DP;
485                         LEAVE_DIR (sp, p, "1");
486                         return (p);
487                 }
488
489                 /* Rebuild if only read the names and now traversing. */
490                 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
491                         CLR(FTS_NAMEONLY);
492                         fts_lfree(sp->fts_child);
493                         sp->fts_child = NULL;
494                 }
495
496                 /*
497                  * Cd to the subdirectory.
498                  *
499                  * If have already read and now fail to chdir, whack the list
500                  * to make the names come out right, and set the parent errno
501                  * so the application will eventually get an error condition.
502                  * Set the FTS_DONTCHDIR flag so that when we logically change
503                  * directories back to the parent we don't do a chdir.
504                  *
505                  * If haven't read do so.  If the read fails, fts_build sets
506                  * FTS_STOP or the fts_info field of the node.
507                  */
508                 if (sp->fts_child != NULL) {
509                         if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
510                                 p->fts_errno = errno;
511                                 p->fts_flags |= FTS_DONTCHDIR;
512                                 for (p = sp->fts_child; p != NULL;
513                                      p = p->fts_link)
514                                         p->fts_accpath =
515                                             p->fts_parent->fts_accpath;
516                         }
517                 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
518                         if (ISSET(FTS_STOP))
519                                 return (NULL);
520                         /* If fts_build's call to fts_safe_changedir failed
521                            because it was not able to fchdir into a
522                            subdirectory, tell the caller.  */
523                         if (p->fts_errno)
524                                 p->fts_info = FTS_ERR;
525                         /* FIXME: see if this should be in an else block */
526                         LEAVE_DIR (sp, p, "2");
527                         return (p);
528                 }
529                 p = sp->fts_child;
530                 sp->fts_child = NULL;
531                 goto name;
532         }
533
534         /* Move to the next node on this level. */
535 next:   tmp = p;
536         if ((p = p->fts_link) != NULL) {
537                 free(tmp);
538
539                 /*
540                  * If reached the top, return to the original directory (or
541                  * the root of the tree), and load the paths for the next root.
542                  */
543                 if (p->fts_level == FTS_ROOTLEVEL) {
544                         if (FCHDIR(sp, sp->fts_rfd)) {
545                                 SET(FTS_STOP);
546                                 return (NULL);
547                         }
548                         fts_load(sp, p);
549                         goto check_for_dir;
550                 }
551
552                 /*
553                  * User may have called fts_set on the node.  If skipped,
554                  * ignore.  If followed, get a file descriptor so we can
555                  * get back if necessary.
556                  */
557                 if (p->fts_instr == FTS_SKIP)
558                         goto next;
559                 if (p->fts_instr == FTS_FOLLOW) {
560                         p->fts_info = fts_stat(sp, p, true);
561                         if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
562                                 if ((p->fts_symfd = diropen (".")) < 0) {
563                                         p->fts_errno = errno;
564                                         p->fts_info = FTS_ERR;
565                                 } else
566                                         p->fts_flags |= FTS_SYMFOLLOW;
567                         }
568                         p->fts_instr = FTS_NOINSTR;
569                 }
570
571 name:           t = sp->fts_path + NAPPEND(p->fts_parent);
572                 *t++ = '/';
573                 memmove(t, p->fts_name, p->fts_namelen + 1);
574 check_for_dir:
575                 sp->fts_cur = p;
576                 if (p->fts_info == FTS_D)
577                   {
578                     Dprintf (("  %s-entering: %s\n", sp, p->fts_path));
579                     if (! enter_dir (sp, p))
580                       {
581                         __set_errno (ENOMEM);
582                         return NULL;
583                       }
584                   }
585                 return p;
586         }
587
588         /* Move up to the parent node. */
589         p = tmp->fts_parent;
590         free(tmp);
591
592         if (p->fts_level == FTS_ROOTPARENTLEVEL) {
593                 /*
594                  * Done; free everything up and set errno to 0 so the user
595                  * can distinguish between error and EOF.
596                  */
597                 free(p);
598                 __set_errno (0);
599                 return (sp->fts_cur = NULL);
600         }
601
602         /* NUL terminate the pathname. */
603         sp->fts_path[p->fts_pathlen] = '\0';
604
605         /*
606          * Return to the parent directory.  If at a root node or came through
607          * a symlink, go back through the file descriptor.  Otherwise, cd up
608          * one directory.
609          */
610         if (p->fts_level == FTS_ROOTLEVEL) {
611                 if (FCHDIR(sp, sp->fts_rfd)) {
612                         p->fts_errno = errno;
613                         SET(FTS_STOP);
614                 }
615         } else if (p->fts_flags & FTS_SYMFOLLOW) {
616                 if (FCHDIR(sp, p->fts_symfd)) {
617                         saved_errno = errno;
618                         (void)close(p->fts_symfd);
619                         __set_errno (saved_errno);
620                         p->fts_errno = errno;
621                         SET(FTS_STOP);
622                 }
623                 (void)close(p->fts_symfd);
624         } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
625                    fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
626                 p->fts_errno = errno;
627                 SET(FTS_STOP);
628         }
629         p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
630         if (p->fts_errno == 0)
631                 LEAVE_DIR (sp, p, "3");
632         sp->fts_cur = p;
633         return ISSET(FTS_STOP) ? NULL : p;
634 }
635
636 /*
637  * Fts_set takes the stream as an argument although it's not used in this
638  * implementation; it would be necessary if anyone wanted to add global
639  * semantics to fts using fts_set.  An error return is allowed for similar
640  * reasons.
641  */
642 /* ARGSUSED */
643 int
644 fts_set(FTS *sp ATTRIBUTE_UNUSED, FTSENT *p, int instr)
645 {
646         if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
647             instr != FTS_NOINSTR && instr != FTS_SKIP) {
648                 __set_errno (EINVAL);
649                 return (1);
650         }
651         p->fts_instr = instr;
652         return (0);
653 }
654
655 FTSENT *
656 fts_children (register FTS *sp, int instr)
657 {
658         register FTSENT *p;
659         int fd;
660
661         if (instr != 0 && instr != FTS_NAMEONLY) {
662                 __set_errno (EINVAL);
663                 return (NULL);
664         }
665
666         /* Set current node pointer. */
667         p = sp->fts_cur;
668
669         /*
670          * Errno set to 0 so user can distinguish empty directory from
671          * an error.
672          */
673         __set_errno (0);
674
675         /* Fatal errors stop here. */
676         if (ISSET(FTS_STOP))
677                 return (NULL);
678
679         /* Return logical hierarchy of user's arguments. */
680         if (p->fts_info == FTS_INIT)
681                 return (p->fts_link);
682
683         /*
684          * If not a directory being visited in pre-order, stop here.  Could
685          * allow FTS_DNR, assuming the user has fixed the problem, but the
686          * same effect is available with FTS_AGAIN.
687          */
688         if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
689                 return (NULL);
690
691         /* Free up any previous child list. */
692         if (sp->fts_child != NULL)
693                 fts_lfree(sp->fts_child);
694
695         if (instr == FTS_NAMEONLY) {
696                 SET(FTS_NAMEONLY);
697                 instr = BNAMES;
698         } else
699                 instr = BCHILD;
700
701         /*
702          * If using chdir on a relative path and called BEFORE fts_read does
703          * its chdir to the root of a traversal, we can lose -- we need to
704          * chdir into the subdirectory, and we don't know where the current
705          * directory is, so we can't get back so that the upcoming chdir by
706          * fts_read will work.
707          */
708         if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
709             ISSET(FTS_NOCHDIR))
710                 return (sp->fts_child = fts_build(sp, instr));
711
712         if ((fd = diropen (".")) < 0)
713                 return (sp->fts_child = NULL);
714         sp->fts_child = fts_build(sp, instr);
715         if (fchdir(fd)) {
716                 (void)close(fd);
717                 return (NULL);
718         }
719         (void)close(fd);
720         return (sp->fts_child);
721 }
722
723 /*
724  * This is the tricky part -- do not casually change *anything* in here.  The
725  * idea is to build the linked list of entries that are used by fts_children
726  * and fts_read.  There are lots of special cases.
727  *
728  * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
729  * set and it's a physical walk (so that symbolic links can't be directories),
730  * we can do things quickly.  First, if it's a 4.4BSD file system, the type
731  * of the file is in the directory entry.  Otherwise, we assume that the number
732  * of subdirectories in a node is equal to the number of links to the parent.
733  * The former skips all stat calls.  The latter skips stat calls in any leaf
734  * directories and for any files after the subdirectories in the directory have
735  * been found, cutting the stat calls by about 2/3.
736  */
737 static FTSENT *
738 internal_function
739 fts_build (register FTS *sp, int type)
740 {
741         register struct dirent *dp;
742         register FTSENT *p, *head;
743         register size_t nitems;
744         FTSENT *cur, *tail;
745         DIR *dirp;
746         void *oldaddr;
747         int cderrno;
748         int saved_errno;
749         bool descend;
750         bool doadjust;
751         ptrdiff_t level;
752         nlink_t nlinks;
753         bool nostat;
754         size_t len, maxlen, new_len;
755         char *cp;
756
757         /* Set current node pointer. */
758         cur = sp->fts_cur;
759
760         /*
761          * Open the directory for reading.  If this fails, we're done.
762          * If being called from fts_read, set the fts_info field.
763          */
764 #if defined FTS_WHITEOUT && 0
765         if (ISSET(FTS_WHITEOUT))
766                 oflag = DTF_NODUP|DTF_REWIND;
767         else
768                 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
769 #else
770 # define __opendir2(path, flag) opendir(path)
771 #endif
772        if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
773                 if (type == BREAD) {
774                         cur->fts_info = FTS_DNR;
775                         cur->fts_errno = errno;
776                 }
777                 return (NULL);
778         }
779
780         /*
781          * Nlinks is the number of possible entries of type directory in the
782          * directory if we're cheating on stat calls, 0 if we're not doing
783          * any stat calls at all, (nlink_t) -1 if we're statting everything.
784          */
785         if (type == BNAMES) {
786                 nlinks = 0;
787                 /* Be quiet about nostat, GCC. */
788                 nostat = false;
789         } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
790                 nlinks = (cur->fts_statp->st_nlink
791                           - (ISSET(FTS_SEEDOT) ? 0 : 2));
792                 nostat = true;
793         } else {
794                 nlinks = -1;
795                 nostat = false;
796         }
797
798         /*
799          * If we're going to need to stat anything or we want to descend
800          * and stay in the directory, chdir.  If this fails we keep going,
801          * but set a flag so we don't chdir after the post-order visit.
802          * We won't be able to stat anything, but we can still return the
803          * names themselves.  Note, that since fts_read won't be able to
804          * chdir into the directory, it will have to return different path
805          * names than before, i.e. "a/b" instead of "b".  Since the node
806          * has already been visited in pre-order, have to wait until the
807          * post-order visit to return the error.  There is a special case
808          * here, if there was nothing to stat then it's not an error to
809          * not be able to stat.  This is all fairly nasty.  If a program
810          * needed sorted entries or stat information, they had better be
811          * checking FTS_NS on the returned nodes.
812          */
813         cderrno = 0;
814         if (nlinks || type == BREAD) {
815                 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
816                         if (nlinks && type == BREAD)
817                                 cur->fts_errno = errno;
818                         cur->fts_flags |= FTS_DONTCHDIR;
819                         descend = false;
820                         cderrno = errno;
821                         closedir(dirp);
822                         dirp = NULL;
823                 } else
824                         descend = true;
825         } else
826                 descend = false;
827
828         /*
829          * Figure out the max file name length that can be stored in the
830          * current path -- the inner loop allocates more path as necessary.
831          * We really wouldn't have to do the maxlen calculations here, we
832          * could do them in fts_read before returning the path, but it's a
833          * lot easier here since the length is part of the dirent structure.
834          *
835          * If not changing directories set a pointer so that can just append
836          * each new name into the path.
837          */
838         len = NAPPEND(cur);
839         if (ISSET(FTS_NOCHDIR)) {
840                 cp = sp->fts_path + len;
841                 *cp++ = '/';
842         } else {
843                 /* GCC, you're too verbose. */
844                 cp = NULL;
845         }
846         len++;
847         maxlen = sp->fts_pathlen - len;
848
849         level = cur->fts_level + 1;
850
851         /* Read the directory, attaching each entry to the `link' pointer. */
852         doadjust = false;
853         for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
854                 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
855                         continue;
856
857                 if ((p = fts_alloc(sp, dp->d_name, NAMLEN (dp))) == NULL)
858                         goto mem1;
859                 if (NAMLEN (dp) >= maxlen) {/* include space for NUL */
860                         oldaddr = sp->fts_path;
861                         if (! fts_palloc(sp, NAMLEN (dp) + len + 1)) {
862                                 /*
863                                  * No more memory for path or structures.  Save
864                                  * errno, free up the current structure and the
865                                  * structures already allocated.
866                                  */
867 mem1:                           saved_errno = errno;
868                                 if (p)
869                                         free(p);
870                                 fts_lfree(head);
871                                 closedir(dirp);
872                                 cur->fts_info = FTS_ERR;
873                                 SET(FTS_STOP);
874                                 __set_errno (saved_errno);
875                                 return (NULL);
876                         }
877                         /* Did realloc() change the pointer? */
878                         if (oldaddr != sp->fts_path) {
879                                 doadjust = true;
880                                 if (ISSET(FTS_NOCHDIR))
881                                         cp = sp->fts_path + len;
882                         }
883                         maxlen = sp->fts_pathlen - len;
884                 }
885
886                 new_len = len + NAMLEN (dp);
887                 if (new_len < len) {
888                         /*
889                          * In the unlikely even that we would end up
890                          * with a path longer than SIZE_MAX, free up
891                          * the current structure and the structures already
892                          * allocated, then error out with ENAMETOOLONG.
893                          */
894                         free(p);
895                         fts_lfree(head);
896                         closedir(dirp);
897                         cur->fts_info = FTS_ERR;
898                         SET(FTS_STOP);
899                         __set_errno (ENAMETOOLONG);
900                         return (NULL);
901                 }
902                 p->fts_level = level;
903                 p->fts_parent = sp->fts_cur;
904                 p->fts_pathlen = new_len;
905
906 #if defined FTS_WHITEOUT && 0
907                 if (dp->d_type == DT_WHT)
908                         p->fts_flags |= FTS_ISW;
909 #endif
910
911                 if (cderrno) {
912                         if (nlinks) {
913                                 p->fts_info = FTS_NS;
914                                 p->fts_errno = cderrno;
915                         } else
916                                 p->fts_info = FTS_NSOK;
917                         p->fts_accpath = cur->fts_accpath;
918                 } else if (nlinks == 0
919 #if HAVE_STRUCT_DIRENT_D_TYPE
920                            || (nostat &&
921                                dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
922 #endif
923                     ) {
924                         p->fts_accpath =
925                             ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
926                         p->fts_info = FTS_NSOK;
927                 } else {
928                         /* Build a file name for fts_stat to stat. */
929                         if (ISSET(FTS_NOCHDIR)) {
930                                 p->fts_accpath = p->fts_path;
931                                 memmove(cp, p->fts_name, p->fts_namelen + 1);
932                         } else
933                                 p->fts_accpath = p->fts_name;
934                         /* Stat it. */
935                         p->fts_info = fts_stat(sp, p, false);
936
937                         /* Decrement link count if applicable. */
938                         if (nlinks > 0 && (p->fts_info == FTS_D ||
939                             p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
940                                 nlinks -= nostat;
941                 }
942
943                 /* We walk in directory order so "ls -f" doesn't get upset. */
944                 p->fts_link = NULL;
945                 if (head == NULL)
946                         head = tail = p;
947                 else {
948                         tail->fts_link = p;
949                         tail = p;
950                 }
951                 ++nitems;
952         }
953         if (dirp)
954                 closedir(dirp);
955
956         /*
957          * If realloc() changed the address of the path, adjust the
958          * addresses for the rest of the tree and the dir list.
959          */
960         if (doadjust)
961                 fts_padjust(sp, head);
962
963         /*
964          * If not changing directories, reset the path back to original
965          * state.
966          */
967         if (ISSET(FTS_NOCHDIR)) {
968                 if (len == sp->fts_pathlen || nitems == 0)
969                         --cp;
970                 *cp = '\0';
971         }
972
973         /*
974          * If descended after called from fts_children or after called from
975          * fts_read and nothing found, get back.  At the root level we use
976          * the saved fd; if one of fts_open()'s arguments is a relative path
977          * to an empty directory, we wind up here with no other way back.  If
978          * can't get back, we're done.
979          */
980         if (descend && (type == BCHILD || !nitems) &&
981             (cur->fts_level == FTS_ROOTLEVEL ?
982              FCHDIR(sp, sp->fts_rfd) :
983              fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
984                 cur->fts_info = FTS_ERR;
985                 SET(FTS_STOP);
986                 return (NULL);
987         }
988
989         /* If didn't find anything, return NULL. */
990         if (!nitems) {
991                 if (type == BREAD)
992                         cur->fts_info = FTS_DP;
993                 return (NULL);
994         }
995
996         /* Sort the entries. */
997         if (sp->fts_compar && nitems > 1)
998                 head = fts_sort(sp, head, nitems);
999         return (head);
1000 }
1001
1002 #if FTS_DEBUG
1003
1004 /* Walk ->fts_parent links starting at E_CURR, until the root of the
1005    current hierarchy.  There should be a directory with dev/inode
1006    matching those of AD.  If not, print a lot of diagnostics.  */
1007 static void
1008 find_matching_ancestor (FTSENT const *e_curr, struct Active_dir const *ad)
1009 {
1010   FTSENT const *ent;
1011   for (ent = e_curr; ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
1012     {
1013       if (ad->ino == ent->fts_statp->st_ino
1014           && ad->dev == ent->fts_statp->st_dev)
1015         return;
1016     }
1017   printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
1018   printf ("active dirs:\n");
1019   for (ent = e_curr;
1020        ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
1021     printf ("  %s(%"PRIuMAX"/%"PRIuMAX") to %s(%"PRIuMAX"/%"PRIuMAX")...\n",
1022             ad->fts_ent->fts_accpath,
1023             (uintmax_t) ad->dev,
1024             (uintmax_t) ad->ino,
1025             ent->fts_accpath,
1026             (uintmax_t) ent->fts_statp->st_dev,
1027             (uintmax_t) ent->fts_statp->st_ino);
1028 }
1029
1030 void
1031 fts_cross_check (FTS const *sp)
1032 {
1033   FTSENT const *ent = sp->fts_cur;
1034   FTSENT const *t;
1035   if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
1036     return;
1037
1038   Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
1039   /* Make sure every parent dir is in the tree.  */
1040   for (t = ent->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
1041     {
1042       struct Active_dir ad;
1043       ad.ino = t->fts_statp->st_ino;
1044       ad.dev = t->fts_statp->st_dev;
1045       if ( ! hash_lookup (sp->active_dir_ht, &ad))
1046         printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
1047     }
1048
1049   /* Make sure every dir in the tree is an active dir.
1050      But ENT is not necessarily a directory.  If so, just skip this part. */
1051   if (ent->fts_parent->fts_level >= FTS_ROOTLEVEL
1052       && (ent->fts_info == FTS_DP
1053           || ent->fts_info == FTS_D))
1054     {
1055       struct Active_dir *ad;
1056       for (ad = hash_get_first (sp->active_dir_ht); ad != NULL;
1057            ad = hash_get_next (sp->active_dir_ht, ad))
1058         {
1059           find_matching_ancestor (ent, ad);
1060         }
1061     }
1062 }
1063 #endif
1064
1065 static unsigned short int
1066 internal_function
1067 fts_stat(FTS *sp, register FTSENT *p, bool follow)
1068 {
1069         struct stat *sbp = p->fts_statp;
1070         int saved_errno;
1071
1072 #if defined FTS_WHITEOUT && 0
1073         /* check for whiteout */
1074         if (p->fts_flags & FTS_ISW) {
1075                 memset(sbp, '\0', sizeof (*sbp));
1076                 sbp->st_mode = S_IFWHT;
1077                 return (FTS_W);
1078        }
1079 #endif
1080
1081         /*
1082          * If doing a logical walk, or application requested FTS_FOLLOW, do
1083          * a stat(2).  If that fails, check for a non-existent symlink.  If
1084          * fail, set the errno from the stat call.
1085          */
1086         if (ISSET(FTS_LOGICAL) || follow) {
1087                 if (stat(p->fts_accpath, sbp)) {
1088                         saved_errno = errno;
1089                         if (!lstat(p->fts_accpath, sbp)) {
1090                                 __set_errno (0);
1091                                 return (FTS_SLNONE);
1092                         }
1093                         p->fts_errno = saved_errno;
1094                         goto err;
1095                 }
1096         } else if (lstat(p->fts_accpath, sbp)) {
1097                 p->fts_errno = errno;
1098 err:            memset(sbp, 0, sizeof(struct stat));
1099                 return (FTS_NS);
1100         }
1101
1102         if (S_ISDIR(sbp->st_mode)) {
1103                 if (ISDOT(p->fts_name))
1104                         return (FTS_DOT);
1105
1106 #if _LGPL_PACKAGE
1107                 {
1108                   /*
1109                    * Cycle detection is done by brute force when the directory
1110                    * is first encountered.  If the tree gets deep enough or the
1111                    * number of symbolic links to directories is high enough,
1112                    * something faster might be worthwhile.
1113                    */
1114                   FTSENT *t;
1115
1116                   for (t = p->fts_parent;
1117                        t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
1118                     if (sbp->st_ino == t->fts_statp->st_ino
1119                         && sbp->st_dev == t->fts_statp->st_dev)
1120                       {
1121                         p->fts_cycle = t;
1122                         return (FTS_DC);
1123                       }
1124                 }
1125 #endif
1126
1127                 return (FTS_D);
1128         }
1129         if (S_ISLNK(sbp->st_mode))
1130                 return (FTS_SL);
1131         if (S_ISREG(sbp->st_mode))
1132                 return (FTS_F);
1133         return (FTS_DEFAULT);
1134 }
1135
1136 static int
1137 fts_compar (void const *a, void const *b)
1138 {
1139   /* Convert A and B to the correct types, to pacify the compiler, and
1140      for portability to bizarre hosts where "void const *" and "FTSENT
1141      const **" differ in runtime representation.  The comparison
1142      function cannot modify *a and *b, but there is no compile-time
1143      check for this.  */
1144   FTSENT const **pa = (FTSENT const **) a;
1145   FTSENT const **pb = (FTSENT const **) b;
1146   return pa[0]->fts_fts->fts_compar (pa, pb);
1147 }
1148
1149 static FTSENT *
1150 internal_function
1151 fts_sort (FTS *sp, FTSENT *head, register size_t nitems)
1152 {
1153         register FTSENT **ap, *p;
1154
1155         /* On most modern hosts, void * and FTSENT ** have the same
1156            run-time representation, and one can convert sp->fts_compar to
1157            the type qsort expects without problem.  Use the heuristic that
1158            this is OK if the two pointer types are the same size, and if
1159            converting FTSENT ** to long int is the same as converting
1160            FTSENT ** to void * and then to long int.  This heuristic isn't
1161            valid in general but we don't know of any counterexamples.  */
1162         FTSENT *dummy;
1163         int (*compare) (void const *, void const *) =
1164           ((sizeof &dummy == sizeof (void *)
1165             && (long int) &dummy == (long int) (void *) &dummy)
1166            ? (int (*) (void const *, void const *)) sp->fts_compar
1167            : fts_compar);
1168
1169         /*
1170          * Construct an array of pointers to the structures and call qsort(3).
1171          * Reassemble the array in the order returned by qsort.  If unable to
1172          * sort for memory reasons, return the directory entries in their
1173          * current order.  Allocate enough space for the current needs plus
1174          * 40 so don't realloc one entry at a time.
1175          */
1176         if (nitems > sp->fts_nitems) {
1177                 struct _ftsent **a;
1178
1179                 sp->fts_nitems = nitems + 40;
1180                 if (SIZE_MAX / sizeof *a < sp->fts_nitems
1181                     || ! (a = realloc (sp->fts_array,
1182                                        sp->fts_nitems * sizeof *a))) {
1183                         free(sp->fts_array);
1184                         sp->fts_array = NULL;
1185                         sp->fts_nitems = 0;
1186                         return (head);
1187                 }
1188                 sp->fts_array = a;
1189         }
1190         for (ap = sp->fts_array, p = head; p; p = p->fts_link)
1191                 *ap++ = p;
1192         qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), compare);
1193         for (head = *(ap = sp->fts_array); --nitems; ++ap)
1194                 ap[0]->fts_link = ap[1];
1195         ap[0]->fts_link = NULL;
1196         return (head);
1197 }
1198
1199 static FTSENT *
1200 internal_function
1201 fts_alloc (FTS *sp, const char *name, register size_t namelen)
1202 {
1203         register FTSENT *p;
1204         size_t len;
1205
1206         /*
1207          * The file name is a variable length array.  Allocate the FTSENT
1208          * structure and the file name in one chunk.
1209          */
1210         len = sizeof(FTSENT) + namelen;
1211         if ((p = malloc(len)) == NULL)
1212                 return (NULL);
1213
1214         /* Copy the name and guarantee NUL termination. */
1215         memmove(p->fts_name, name, namelen);
1216         p->fts_name[namelen] = '\0';
1217
1218         p->fts_namelen = namelen;
1219         p->fts_fts = sp;
1220         p->fts_path = sp->fts_path;
1221         p->fts_errno = 0;
1222         p->fts_flags = 0;
1223         p->fts_instr = FTS_NOINSTR;
1224         p->fts_number = 0;
1225         p->fts_pointer = NULL;
1226         return (p);
1227 }
1228
1229 static void
1230 internal_function
1231 fts_lfree (register FTSENT *head)
1232 {
1233         register FTSENT *p;
1234
1235         /* Free a linked list of structures. */
1236         while ((p = head)) {
1237                 head = head->fts_link;
1238                 free(p);
1239         }
1240 }
1241
1242 /*
1243  * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
1244  * Most systems will allow creation of paths much longer than MAXPATHLEN, even
1245  * though the kernel won't resolve them.  Add the size (not just what's needed)
1246  * plus 256 bytes so don't realloc the path 2 bytes at a time.
1247  */
1248 static bool
1249 internal_function
1250 fts_palloc (FTS *sp, size_t more)
1251 {
1252         char *p;
1253         size_t new_len = sp->fts_pathlen + more + 256;
1254
1255         /*
1256          * See if fts_pathlen would overflow.
1257          */
1258         if (new_len < sp->fts_pathlen) {
1259                 if (sp->fts_path) {
1260                         free(sp->fts_path);
1261                         sp->fts_path = NULL;
1262                 }
1263                 sp->fts_path = NULL;
1264                 __set_errno (ENAMETOOLONG);
1265                 return false;
1266         }
1267         sp->fts_pathlen = new_len;
1268         p = realloc(sp->fts_path, sp->fts_pathlen);
1269         if (p == NULL) {
1270                 free(sp->fts_path);
1271                 sp->fts_path = NULL;
1272                 return false;
1273         }
1274         sp->fts_path = p;
1275         return true;
1276 }
1277
1278 /*
1279  * When the path is realloc'd, have to fix all of the pointers in structures
1280  * already returned.
1281  */
1282 static void
1283 internal_function
1284 fts_padjust (FTS *sp, FTSENT *head)
1285 {
1286         FTSENT *p;
1287         char *addr = sp->fts_path;
1288
1289 #define ADJUST(p) do {                                                  \
1290         if ((p)->fts_accpath != (p)->fts_name) {                        \
1291                 (p)->fts_accpath =                                      \
1292                     (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
1293         }                                                               \
1294         (p)->fts_path = addr;                                           \
1295 } while (0)
1296         /* Adjust the current set of children. */
1297         for (p = sp->fts_child; p; p = p->fts_link)
1298                 ADJUST(p);
1299
1300         /* Adjust the rest of the tree, including the current level. */
1301         for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1302                 ADJUST(p);
1303                 p = p->fts_link ? p->fts_link : p->fts_parent;
1304         }
1305 }
1306
1307 static size_t
1308 internal_function
1309 fts_maxarglen (char * const *argv)
1310 {
1311         size_t len, max;
1312
1313         for (max = 0; *argv; ++argv)
1314                 if ((len = strlen(*argv)) > max)
1315                         max = len;
1316         return (max + 1);
1317 }
1318
1319 /*
1320  * Change to dir specified by fd or path without getting
1321  * tricked by someone changing the world out from underneath us.
1322  * Assumes p->fts_statp->st_dev and p->fts_statp->st_ino are filled in.
1323  */
1324 static int
1325 internal_function
1326 fts_safe_changedir (FTS *sp, FTSENT *p, int fd, char const *path)
1327 {
1328         int ret, oerrno, newfd;
1329         struct stat sb;
1330
1331         newfd = fd;
1332         if (ISSET(FTS_NOCHDIR))
1333                 return (0);
1334         if (fd < 0 && (newfd = fd_safer (diropen (path))) < 0)
1335                 return (-1);
1336         if (fstat(newfd, &sb)) {
1337                 ret = -1;
1338                 goto bail;
1339         }
1340         if (p->fts_statp->st_dev != sb.st_dev
1341             || p->fts_statp->st_ino != sb.st_ino) {
1342                 __set_errno (ENOENT);           /* disinformation */
1343                 ret = -1;
1344                 goto bail;
1345         }
1346         ret = fchdir(newfd);
1347 bail:
1348         oerrno = errno;
1349         if (fd < 0)
1350                 (void)close(newfd);
1351         __set_errno (oerrno);
1352         return (ret);
1353 }