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