Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

rpmio/fts.c

Go to the documentation of this file.
00001 /*@-boundsread@*/
00002 /*@-sysunrecog -noeffectuncon -nullpass -sizeoftype -unrecog -usereleased @*/
00003 /*@-compdef -compmempass -dependenttrans -retalias @*/
00004 /*-
00005  * Copyright (c) 1990, 1993, 1994
00006  *      The Regents of the University of California.  All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 4. Neither the name of the University nor the names of its contributors
00017  *    may be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00024  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00025  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00026  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00027  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00028  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00029  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  */
00032 
00033 #if defined(LIBC_SCCS) && !defined(lint)
00034 static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
00035 #endif /* LIBC_SCCS and not lint */
00036 
00037 #if defined(_LIBC)
00038 #include <sys/param.h>
00039 #include <include/sys/stat.h>
00040 #include <fcntl.h>
00041 #include <dirent.h>
00042 #include <errno.h>
00043 #include <fts.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #else
00048 #if defined(hpux) || defined(__hpux)
00049 # define        _INCLUDE_POSIX_SOURCE
00050 #   define __errno_location()   (&errno)
00051 #   define dirfd(dirp)          -1
00052 #   define stat64               stat
00053 #   define _STAT_VER            0
00054 #   define __fxstat64(_stat_ver, _fd, _sbp)     fstat((_fd), (_sbp))
00055 #endif
00056 #if defined(sun)
00057 #   define __errno_location()   (&errno)
00058 #   define dirfd(dirp)          -1
00059 #   define _STAT_VER            0
00060 #   define __fxstat64(_stat_ver, _fd, _sbp)     fstat((_fd), (_sbp))
00061 #endif
00062 #if defined(__APPLE__)
00063 #   define __errno_location()   (__error())
00064 #   define stat64               stat
00065 #   define _STAT_VER            0
00066 #   define __fxstat64(_stat_ver, _fd, _sbp)     fstat((_fd), (_sbp))
00067 #endif
00068 #if defined(__FreeBSD__)
00069 #   define __errno_location()  (&errno)
00070 #   define stat64              stat
00071 #   define __fxstat64(_stat_ver, _fd, _sbp)    fstat((_fd), (_sbp))
00072 #endif
00073 #include "system.h"
00074 #include "fts.h"
00075 #include "rpmio.h"
00076 #include "rpmurl.h"
00077 #   define __set_errno(val) (*__errno_location ()) = (val)
00078 #   define __open       open
00079 #   define __close      close
00080 #   define __fchdir     fchdir
00081 #endif
00082 
00083 #if !defined(USHRT_MAX)
00084 #define USHRT_MAX       65535
00085 #endif
00086 
00087 /* Largest alignment size needed, minus one.
00088    Usually long double is the worst case.  */
00089 #ifndef ALIGNBYTES
00090 #if defined __GNUC__ && __GNUC__ >= 2
00091 # define alignof(TYPE) __alignof__ (TYPE)
00092 #else
00093 # define alignof(TYPE) \
00094     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
00095 #endif
00096 #define ALIGNBYTES      (alignof(long double) - 1)
00097 #endif
00098 /* Align P to that size.  */
00099 #ifndef ALIGN
00100 #define ALIGN(p)        (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
00101 #endif
00102 
00103 /*@unchecked@*/
00104 static int _fts_debug = 0;
00105 
00106 /*@only@*/ /*@null@*/
00107 static FTSENT * fts_alloc(FTS * sp, const char * name, int namelen)
00108         /*@*/;
00109 /*@null@*/
00110 static FTSENT * fts_build(FTS * sp, int type)
00111         /*@globals fileSystem, internalState @*/
00112         /*@modifies *sp, fileSystem, internalState @*/;
00113 static void     fts_lfree(/*@only@*/ FTSENT * head)
00114         /*@modifies head @*/;
00115 static void     fts_load(FTS * sp, FTSENT * p)
00116         /*@modifies *sp, *p @*/;
00117 static size_t   fts_maxarglen(char * const * argv)
00118         /*@*/;
00119 static void     fts_padjust(FTS * sp, FTSENT * head)
00120         /*@modifies *sp, *head @*/;
00121 static int      fts_palloc(FTS * sp, size_t more)
00122         /*@modifies *sp @*/;
00123 static FTSENT * fts_sort(FTS * sp, /*@returned@*/ FTSENT * head, int nitems)
00124         /*@modifies *sp @*/;
00125 static u_short  fts_stat(FTS * sp, FTSENT * p, int follow)
00126         /*@modifies *p @*/;
00127 static int      fts_safe_changedir(FTS * sp, FTSENT * p, int fd,
00128                         const char * path)
00129         /*@globals fileSystem, internalState @*/
00130         /*@modifies fileSystem, internalState @*/;
00131 
00132 #define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
00133 
00134 #define CLR(opt)        (sp->fts_options &= ~(opt))
00135 #define ISSET(opt)      (sp->fts_options & (opt))
00136 #define SET(opt)        (sp->fts_options |= (opt))
00137 
00138 #define FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && __fchdir(fd))
00139 
00140 /* fts_build flags */
00141 #define BCHILD          1               /* fts_children */
00142 #define BNAMES          2               /* fts_children, names only */
00143 #define BREAD           3               /* fts_read */
00144 
00145 FTS *
00146 Fts_open(char * const * argv, int options,
00147                 int (*compar) (const FTSENT **, const FTSENT **))
00148 {
00149         register FTS *sp;
00150         register FTSENT *p, *root;
00151         register int nitems;
00152         FTSENT *parent = NULL;
00153         FTSENT *tmp = NULL;
00154         size_t len;
00155 
00156 /*@-formattype -modfilesys@*/
00157 if (_fts_debug)
00158 fprintf(stderr, "*** Fts_open(%p, 0x%x, %p)\n", argv, options, compar);
00159 /*@=formattype =modfilesys@*/
00160 
00161         /* Options check. */
00162         if (options & ~FTS_OPTIONMASK) {
00163 /*@-boundswrite@*/
00164                 __set_errno (EINVAL);
00165 /*@=boundswrite@*/
00166                 return (NULL);
00167         }
00168 
00169         /* Allocate/initialize the stream */
00170         if ((sp = malloc((u_int)sizeof(*sp))) == NULL)
00171                 return (NULL);
00172         memset(sp, 0, sizeof(*sp));
00173         sp->fts_compar = (int (*) (const void *, const void *)) compar;
00174         sp->fts_opendir = Opendir;
00175         sp->fts_readdir = Readdir;
00176         sp->fts_closedir = Closedir;
00177         sp->fts_stat = Stat;
00178         sp->fts_lstat = Lstat;
00179         sp->fts_options = options;
00180 
00181         /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
00182         if (ISSET(FTS_LOGICAL))
00183                 SET(FTS_NOCHDIR);
00184 
00185         /*
00186          * Start out with 1K of path space, and enough, in any case,
00187          * to hold the user's paths.
00188          */
00189 #ifndef MAXPATHLEN
00190 #define MAXPATHLEN 1024
00191 #endif
00192         len = fts_maxarglen(argv);
00193         if (len < MAXPATHLEN)
00194             len = MAXPATHLEN;
00195         if (fts_palloc(sp, len))
00196                 goto mem1;
00197 
00198         /* Allocate/initialize root's parent. */
00199 /*@-branchstate@*/
00200         if (*argv != NULL) {
00201                 if ((parent = fts_alloc(sp, "", 0)) == NULL)
00202                         goto mem2;
00203                 parent->fts_level = FTS_ROOTPARENTLEVEL;
00204         }
00205 /*@=branchstate@*/
00206 
00207         /* Allocate/initialize root(s). */
00208         for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
00209                 /* Don't allow zero-length paths. */
00210                 if ((len = strlen(*argv)) == 0) {
00211 /*@-boundswrite@*/
00212                         __set_errno (ENOENT);
00213 /*@=boundswrite@*/
00214                         goto mem3;
00215                 }
00216 
00217                 /* Use fchdir(2) speedup only if local DASDI. */
00218                 switch (urlIsURL(*argv)) {
00219                 case URL_IS_DASH:
00220                 case URL_IS_HKP:
00221 /*@-boundswrite@*/
00222                         __set_errno (ENOENT);
00223 /*@=boundswrite@*/
00224                         goto mem3;
00225                         /*@notreached@*/ /*@switchbreak@*/ break;
00226                 case URL_IS_HTTPS:
00227                 case URL_IS_HTTP:
00228                 case URL_IS_FTP:
00229                         SET(FTS_NOCHDIR);
00230                         /*@switchbreak@*/ break;
00231                 case URL_IS_UNKNOWN:
00232                 case URL_IS_PATH:
00233                         /*@switchbreak@*/ break;
00234                 }
00235 
00236                 p = fts_alloc(sp, *argv, len);
00237                 if (p == NULL)
00238                         goto mem3;
00239                 p->fts_level = FTS_ROOTLEVEL;
00240                 p->fts_parent = parent;
00241                 p->fts_accpath = p->fts_name;
00242                 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
00243 
00244                 /* Command-line "." and ".." are real directories. */
00245                 if (p->fts_info == FTS_DOT)
00246                         p->fts_info = FTS_D;
00247 
00248                 /*
00249                  * If comparison routine supplied, traverse in sorted
00250                  * order; otherwise traverse in the order specified.
00251                  */
00252                 if (compar) {
00253                         p->fts_link = root;
00254                         root = p;
00255                 } else {
00256                         p->fts_link = NULL;
00257                         if (root == NULL)
00258                                 tmp = root = p;
00259                         else {
00260                                 if (tmp != NULL)        /* XXX can't happen */
00261                                         tmp->fts_link = p;
00262                                 tmp = p;
00263                         }
00264                 }
00265         }
00266         /*@-branchstate@*/
00267         if (compar && nitems > 1)
00268                 root = fts_sort(sp, root, nitems);
00269         /*@=branchstate@*/
00270 
00271         /*
00272          * Allocate a dummy pointer and make fts_read think that we've just
00273          * finished the node before the root(s); set p->fts_info to FTS_INIT
00274          * so that everything about the "current" node is ignored.
00275          */
00276         if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
00277                 goto mem3;
00278         sp->fts_cur->fts_link = root;
00279         sp->fts_cur->fts_info = FTS_INIT;
00280 
00281         /*
00282          * If using chdir(2), grab a file descriptor pointing to dot to ensure
00283          * that we can get back here; this could be avoided for some paths,
00284          * but almost certainly not worth the effort.  Slashes, symbolic links,
00285          * and ".." are all fairly nasty problems.  Note, if we can't get the
00286          * descriptor we run anyway, just more slowly.
00287          */
00288         if (!ISSET(FTS_NOCHDIR)
00289             && (sp->fts_rfd = __open(".", O_RDONLY, 0)) < 0)
00290                 SET(FTS_NOCHDIR);
00291 
00292         return (sp);
00293 
00294 mem3:   fts_lfree(root);
00295         free(parent);
00296 mem2:   free(sp->fts_path);
00297 mem1:   free(sp);
00298         return (NULL);
00299 }
00300 
00301 static void
00302 fts_load(FTS * sp, FTSENT * p)
00303 {
00304         register int len;
00305         register char *cp;
00306 
00307         /*
00308          * Load the stream structure for the next traversal.  Since we don't
00309          * actually enter the directory until after the preorder visit, set
00310          * the fts_accpath field specially so the chdir gets done to the right
00311          * place and the user can access the first node.  From fts_open it's
00312          * known that the path will fit.
00313          */
00314         len = p->fts_pathlen = p->fts_namelen;
00315 /*@-boundswrite@*/
00316         memmove(sp->fts_path, p->fts_name, len + 1);
00317         if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
00318                 len = strlen(++cp);
00319                 memmove(p->fts_name, cp, len + 1);
00320                 p->fts_namelen = len;
00321         }
00322         p->fts_accpath = p->fts_path = sp->fts_path;
00323         sp->fts_dev = p->fts_dev;
00324 /*@=boundswrite@*/
00325 }
00326 
00327 int
00328 Fts_close(FTS * sp)
00329 {
00330         register FTSENT *freep, *p;
00331         int saved_errno;
00332 
00333         if (sp == NULL)
00334                 return 0;
00335 
00336         /*
00337          * This still works if we haven't read anything -- the dummy structure
00338          * points to the root list, so we step through to the end of the root
00339          * list which has a valid parent pointer.
00340          */
00341         /*@-branchstate@*/
00342         if (sp->fts_cur) {
00343                 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
00344                         freep = p;
00345                         p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
00346                         free(freep);
00347                 }
00348                 free(p);
00349         }
00350         /*@=branchstate@*/
00351 
00352         /* Free up child linked list, sort array, path buffer. */
00353         if (sp->fts_child)
00354                 fts_lfree(sp->fts_child);
00355         if (sp->fts_array)
00356                 free(sp->fts_array);
00357         free(sp->fts_path);
00358 
00359         /* Return to original directory, save errno if necessary. */
00360         if (!ISSET(FTS_NOCHDIR)) {
00361                 saved_errno = __fchdir(sp->fts_rfd) ? errno : 0;
00362                 (void)__close(sp->fts_rfd);
00363 
00364                 /* Set errno and return. */
00365                 if (saved_errno != 0) {
00366                         /* Free up the stream pointer. */
00367                         free(sp);
00368 /*@-boundswrite@*/
00369                         __set_errno (saved_errno);
00370 /*@=boundswrite@*/
00371                         return (-1);
00372                 }
00373         }
00374 
00375         /* Free up the stream pointer. */
00376         free(sp);
00377         return (0);
00378 }
00379 
00380 /*
00381  * Special case of "/" at the end of the path so that slashes aren't
00382  * appended which would cause paths to be written as "....//foo".
00383  */
00384 #define NAPPEND(p)                                                      \
00385         (p->fts_path[p->fts_pathlen - 1] == '/'                         \
00386             ? p->fts_pathlen - 1 : p->fts_pathlen)
00387 
00388 FTSENT *
00389 Fts_read(FTS * sp)
00390 {
00391         register FTSENT *p;
00392         register FTSENT *tmp;
00393         register int instr;
00394         register char *t;
00395         int saved_errno;
00396 
00397         /* If finished or unrecoverable error, return NULL. */
00398         if (sp == NULL || sp->fts_cur == NULL || ISSET(FTS_STOP))
00399                 return (NULL);
00400 
00401         /* Set current node pointer. */
00402         p = sp->fts_cur;
00403 
00404         /* Save and zero out user instructions. */
00405         instr = p->fts_instr;
00406         p->fts_instr = FTS_NOINSTR;
00407 
00408         /* Any type of file may be re-visited; re-stat and re-turn. */
00409         if (instr == FTS_AGAIN) {
00410                 p->fts_info = fts_stat(sp, p, 0);
00411                 return (p);
00412         }
00413 
00414         /*
00415          * Following a symlink -- SLNONE test allows application to see
00416          * SLNONE and recover.  If indirecting through a symlink, have
00417          * keep a pointer to current location.  If unable to get that
00418          * pointer, follow fails.
00419          */
00420         if (instr == FTS_FOLLOW &&
00421             (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
00422                 p->fts_info = fts_stat(sp, p, 1);
00423                 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
00424                         if ((p->fts_symfd = __open(".", O_RDONLY, 0)) < 0) {
00425                                 p->fts_errno = errno;
00426                                 p->fts_info = FTS_ERR;
00427                         } else
00428                                 p->fts_flags |= FTS_SYMFOLLOW;
00429                 }
00430                 return (p);
00431         }
00432 
00433         /* Directory in pre-order. */
00434         if (p->fts_info == FTS_D) {
00435                 /* If skipped or crossed mount point, do post-order visit. */
00436                 if (instr == FTS_SKIP ||
00437                     (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
00438                         if (p->fts_flags & FTS_SYMFOLLOW)
00439                                 (void)__close(p->fts_symfd);
00440                         if (sp->fts_child) {
00441                                 fts_lfree(sp->fts_child);
00442                                 sp->fts_child = NULL;
00443                         }
00444                         p->fts_info = FTS_DP;
00445                         return (p);
00446                 }
00447 
00448                 /* Rebuild if only read the names and now traversing. */
00449                 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
00450                         CLR(FTS_NAMEONLY);
00451                         fts_lfree(sp->fts_child);
00452                         sp->fts_child = NULL;
00453                 }
00454 
00455                 /*
00456                  * Cd to the subdirectory.
00457                  *
00458                  * If have already read and now fail to chdir, whack the list
00459                  * to make the names come out right, and set the parent errno
00460                  * so the application will eventually get an error condition.
00461                  * Set the FTS_DONTCHDIR flag so that when we logically change
00462                  * directories back to the parent we don't do a chdir.
00463                  *
00464                  * If haven't read do so.  If the read fails, fts_build sets
00465                  * FTS_STOP or the fts_info field of the node.
00466                  */
00467                 if (sp->fts_child != NULL) {
00468                         if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
00469                                 p->fts_errno = errno;
00470                                 p->fts_flags |= FTS_DONTCHDIR;
00471                                 for (p = sp->fts_child; p != NULL;
00472                                      p = p->fts_link)
00473                                         p->fts_accpath =
00474                                             p->fts_parent->fts_accpath;
00475                         }
00476                 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
00477                         if (ISSET(FTS_STOP))
00478                                 return (NULL);
00479                         return (p);
00480                 }
00481                 p = sp->fts_child;
00482                 sp->fts_child = NULL;
00483                 sp->fts_cur = p;
00484                 goto name;
00485         }
00486 
00487         /* Move to the next node on this level. */
00488 /*@-boundswrite@*/
00489 next:   tmp = p;
00490         if ((p = p->fts_link) != NULL) {
00491                 sp->fts_cur = p;
00492                 free(tmp);
00493 
00494                 /*
00495                  * If reached the top, return to the original directory (or
00496                  * the root of the tree), and load the paths for the next root.
00497                  */
00498                 if (p->fts_level == FTS_ROOTLEVEL) {
00499                         if (FCHDIR(sp, sp->fts_rfd)) {
00500                                 SET(FTS_STOP);
00501                                 return (NULL);
00502                         }
00503                         fts_load(sp, p);
00504                         return (p);
00505                 }
00506 
00507                 /*
00508                  * User may have called fts_set on the node.  If skipped,
00509                  * ignore.  If followed, get a file descriptor so we can
00510                  * get back if necessary.
00511                  */
00512                 if (p->fts_instr == FTS_SKIP)
00513                         goto next;
00514                 /*@-branchstate@*/
00515                 if (p->fts_instr == FTS_FOLLOW) {
00516                         p->fts_info = fts_stat(sp, p, 1);
00517                         if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
00518                                 if ((p->fts_symfd =
00519                                     __open(".", O_RDONLY, 0)) < 0) {
00520                                         p->fts_errno = errno;
00521                                         p->fts_info = FTS_ERR;
00522                                 } else
00523                                         p->fts_flags |= FTS_SYMFOLLOW;
00524                         }
00525                         p->fts_instr = FTS_NOINSTR;
00526                 }
00527                 /*@=branchstate@*/
00528 
00529 name:           t = sp->fts_path + NAPPEND(p->fts_parent);
00530                 *t++ = '/';
00531                 memmove(t, p->fts_name, p->fts_namelen + 1);
00532                 return (p);
00533         }
00534 
00535         /* Move up to the parent node. */
00536         p = tmp->fts_parent;
00537         sp->fts_cur = p;
00538         free(tmp);
00539 
00540         if (p->fts_level == FTS_ROOTPARENTLEVEL) {
00541                 /*
00542                  * Done; free everything up and set errno to 0 so the user
00543                  * can distinguish between error and EOF.
00544                  */
00545                 free(p);
00546                 __set_errno (0);
00547                 return (sp->fts_cur = NULL);
00548         }
00549 
00550         /* NUL terminate the pathname. */
00551         sp->fts_path[p->fts_pathlen] = '\0';
00552 /*@=boundswrite@*/
00553 
00554         /*
00555          * Return to the parent directory.  If at a root node or came through
00556          * a symlink, go back through the file descriptor.  Otherwise, cd up
00557          * one directory.
00558          */
00559         if (p->fts_level == FTS_ROOTLEVEL) {
00560                 if (FCHDIR(sp, sp->fts_rfd)) {
00561                         SET(FTS_STOP);
00562                         return (NULL);
00563                 }
00564         } else if (p->fts_flags & FTS_SYMFOLLOW) {
00565                 if (FCHDIR(sp, p->fts_symfd)) {
00566                         saved_errno = errno;
00567                         (void)__close(p->fts_symfd);
00568 /*@-boundswrite@*/
00569                         __set_errno (saved_errno);
00570 /*@=boundswrite@*/
00571                         SET(FTS_STOP);
00572                         return (NULL);
00573                 }
00574                 (void)__close(p->fts_symfd);
00575         } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
00576                    fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
00577                 SET(FTS_STOP);
00578                 return (NULL);
00579         }
00580         p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
00581         return (p);
00582 }
00583 
00584 /*
00585  * Fts_set takes the stream as an argument although it's not used in this
00586  * implementation; it would be necessary if anyone wanted to add global
00587  * semantics to fts using fts_set.  An error return is allowed for similar
00588  * reasons.
00589  */
00590 int
00591 Fts_set(/*@unused@*/ FTS * sp, FTSENT * p, int instr)
00592 {
00593 /*@-modfilesys@*/
00594 if (_fts_debug)
00595 fprintf(stderr, "*** Fts_set(%p, %p, 0x%x)\n", sp, p, instr);
00596 /*@=modfilesys@*/
00597 
00598         if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
00599             instr != FTS_NOINSTR && instr != FTS_SKIP) {
00600 /*@-boundswrite@*/
00601                 __set_errno (EINVAL);
00602 /*@=boundswrite@*/
00603                 return (1);
00604         }
00605         p->fts_instr = instr;
00606         return (0);
00607 }
00608 
00609 FTSENT *
00610 Fts_children(FTS * sp, int instr)
00611 {
00612         register FTSENT *p;
00613         int fd;
00614 
00615 /*@-modfilesys@*/
00616 if (_fts_debug)
00617 fprintf(stderr, "*** Fts_children(%p, 0x%x)\n", sp, instr);
00618 /*@=modfilesys@*/
00619 
00620         if (instr != 0 && instr != FTS_NAMEONLY) {
00621 /*@-boundswrite@*/
00622                 __set_errno (EINVAL);
00623 /*@=boundswrite@*/
00624                 return (NULL);
00625         }
00626 
00627         /* Set current node pointer. */
00628         p = sp->fts_cur;
00629 
00630         /*
00631          * Errno set to 0 so user can distinguish empty directory from
00632          * an error.
00633          */
00634 /*@-boundswrite@*/
00635         __set_errno (0);
00636 /*@=boundswrite@*/
00637 
00638         /* Fatal errors stop here. */
00639         if (ISSET(FTS_STOP))
00640                 return (NULL);
00641 
00642         /* Return logical hierarchy of user's arguments. */
00643         if (p->fts_info == FTS_INIT)
00644                 return (p->fts_link);
00645 
00646         /*
00647          * If not a directory being visited in pre-order, stop here.  Could
00648          * allow FTS_DNR, assuming the user has fixed the problem, but the
00649          * same effect is available with FTS_AGAIN.
00650          */
00651         if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
00652                 return (NULL);
00653 
00654         /* Free up any previous child list. */
00655         if (sp->fts_child != NULL)
00656                 fts_lfree(sp->fts_child);
00657 
00658         if (instr == FTS_NAMEONLY) {
00659                 SET(FTS_NAMEONLY);
00660                 instr = BNAMES;
00661         } else
00662                 instr = BCHILD;
00663 
00664         /*
00665          * If using chdir on a relative path and called BEFORE fts_read does
00666          * its chdir to the root of a traversal, we can lose -- we need to
00667          * chdir into the subdirectory, and we don't know where the current
00668          * directory is, so we can't get back so that the upcoming chdir by
00669          * fts_read will work.
00670          */
00671         if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
00672             ISSET(FTS_NOCHDIR))
00673                 return (sp->fts_child = fts_build(sp, instr));
00674 
00675         if ((fd = __open(".", O_RDONLY, 0)) < 0)
00676                 return (NULL);
00677         sp->fts_child = fts_build(sp, instr);
00678         if (__fchdir(fd))
00679                 return (NULL);
00680         (void)__close(fd);
00681         return (sp->fts_child);
00682 }
00683 
00684 /*
00685  * This is the tricky part -- do not casually change *anything* in here.  The
00686  * idea is to build the linked list of entries that are used by fts_children
00687  * and fts_read.  There are lots of special cases.
00688  *
00689  * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
00690  * set and it's a physical walk (so that symbolic links can't be directories),
00691  * we can do things quickly.  First, if it's a 4.4BSD file system, the type
00692  * of the file is in the directory entry.  Otherwise, we assume that the number
00693  * of subdirectories in a node is equal to the number of links to the parent.
00694  * The former skips all stat calls.  The latter skips stat calls in any leaf
00695  * directories and for any files after the subdirectories in the directory have
00696  * been found, cutting the stat calls by about 2/3.
00697  */
00698 static FTSENT *
00699 fts_build(FTS * sp, int type)
00700 {
00701         register struct dirent *dp;
00702         register FTSENT *p, *head;
00703         register int nitems;
00704         FTSENT *cur, *tail;
00705         DIR *dirp;
00706         void *oldaddr;
00707         int cderrno, descend, len, level, nlinks, saved_errno,
00708             nostat, doadjust;
00709         size_t maxlen;
00710         char *cp;
00711 
00712         /* Set current node pointer. */
00713         cur = sp->fts_cur;
00714 
00715         /*
00716          * Open the directory for reading.  If this fails, we're done.
00717          * If being called from fts_read, set the fts_info field.
00718          */
00719 #if defined FTS_WHITEOUT && 0
00720         if (ISSET(FTS_WHITEOUT))
00721                 oflag = DTF_NODUP|DTF_REWIND;
00722         else
00723                 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
00724 #else
00725 # define __opendir2(path, flag) (*sp->fts_opendir) (path)
00726 #endif
00727        if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
00728                 if (type == BREAD) {
00729                         cur->fts_info = FTS_DNR;
00730                         cur->fts_errno = errno;
00731                 }
00732                 return (NULL);
00733         }
00734 
00735         /*
00736          * Nlinks is the number of possible entries of type directory in the
00737          * directory if we're cheating on stat calls, 0 if we're not doing
00738          * any stat calls at all, -1 if we're doing stats on everything.
00739          */
00740         if (type == BNAMES) {
00741                 nlinks = 0;
00742                 /* Be quiet about nostat, GCC. */
00743                 nostat = 0;
00744         } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
00745                 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
00746                 nostat = 1;
00747         } else {
00748                 nlinks = -1;
00749                 nostat = 0;
00750         }
00751 
00752 #ifdef notdef
00753         (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
00754         (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
00755             ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
00756 #endif
00757         /*
00758          * If we're going to need to stat anything or we want to descend
00759          * and stay in the directory, chdir.  If this fails we keep going,
00760          * but set a flag so we don't chdir after the post-order visit.
00761          * We won't be able to stat anything, but we can still return the
00762          * names themselves.  Note, that since fts_read won't be able to
00763          * chdir into the directory, it will have to return different path
00764          * names than before, i.e. "a/b" instead of "b".  Since the node
00765          * has already been visited in pre-order, have to wait until the
00766          * post-order visit to return the error.  There is a special case
00767          * here, if there was nothing to stat then it's not an error to
00768          * not be able to stat.  This is all fairly nasty.  If a program
00769          * needed sorted entries or stat information, they had better be
00770          * checking FTS_NS on the returned nodes.
00771          */
00772         cderrno = 0;
00773         if (nlinks || type == BREAD) {
00774                 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
00775                         if (nlinks && type == BREAD)
00776                                 cur->fts_errno = errno;
00777                         cur->fts_flags |= FTS_DONTCHDIR;
00778                         descend = 0;
00779                         cderrno = errno;
00780                         (void) (*sp->fts_closedir) (dirp);
00781                         dirp = NULL;
00782                 } else
00783                         descend = 1;
00784         } else
00785                 descend = 0;
00786 
00787         /*
00788          * Figure out the max file name length that can be stored in the
00789          * current path -- the inner loop allocates more path as necessary.
00790          * We really wouldn't have to do the maxlen calculations here, we
00791          * could do them in fts_read before returning the path, but it's a
00792          * lot easier here since the length is part of the dirent structure.
00793          *
00794          * If not changing directories set a pointer so that can just append
00795          * each new name into the path.
00796          */
00797         len = NAPPEND(cur);
00798         if (ISSET(FTS_NOCHDIR)) {
00799                 cp = sp->fts_path + len;
00800 /*@-boundswrite@*/
00801                 *cp++ = '/';
00802 /*@=boundswrite@*/
00803         } else {
00804                 /* GCC, you're too verbose. */
00805                 cp = NULL;
00806         }
00807         len++;
00808         maxlen = sp->fts_pathlen - len;
00809 
00810         level = cur->fts_level + 1;
00811 
00812         /* Read the directory, attaching each entry to the `link' pointer. */
00813         doadjust = 0;
00814         for (head = tail = NULL, nitems = 0;
00815              dirp && (dp = (*sp->fts_readdir) (dirp));)
00816         {
00817                 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
00818                         continue;
00819 
00820                 if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL)
00821                         goto mem1;
00822                 if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
00823                         oldaddr = sp->fts_path;
00824                         if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
00825                                 /*
00826                                  * No more memory for path or structures.  Save
00827                                  * errno, free up the current structure and the
00828                                  * structures already allocated.
00829                                  */
00830 mem1:                           saved_errno = errno;
00831                                 if (p)
00832                                         free(p);
00833                                 fts_lfree(head);
00834                                 (void) (*sp->fts_closedir) (dirp);
00835                                 cur->fts_info = FTS_ERR;
00836                                 SET(FTS_STOP);
00837                                 __set_errno (saved_errno);
00838                                 return (NULL);
00839                         }
00840                         /* Did realloc() change the pointer? */
00841                         if (oldaddr != sp->fts_path) {
00842                                 doadjust = 1;
00843                                 if (ISSET(FTS_NOCHDIR))
00844                                         cp = sp->fts_path + len;
00845                         }
00846                         maxlen = sp->fts_pathlen - len;
00847                 }
00848 
00849                 if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
00850                         /*
00851                          * In an FTSENT, fts_pathlen is a u_short so it is
00852                          * possible to wraparound here.  If we do, free up
00853                          * the current structure and the structures already
00854                          * allocated, then error out with ENAMETOOLONG.
00855                          */
00856                         free(p);
00857                         fts_lfree(head);
00858                         (void) (*sp->fts_closedir) (dirp);
00859                         cur->fts_info = FTS_ERR;
00860                         SET(FTS_STOP);
00861                         __set_errno (ENAMETOOLONG);
00862                         return (NULL);
00863                 }
00864                 p->fts_level = level;
00865                 p->fts_parent = sp->fts_cur;
00866                 p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
00867 
00868 #if defined FTS_WHITEOUT && 0
00869                 if (dp->d_type == DT_WHT)
00870                         p->fts_flags |= FTS_ISW;
00871 #endif
00872 
00873 #if 0
00874                 /*
00875                  * Unreachable code.  cderrno is only ever set to a nonnull
00876                  * value if dirp is closed at the same time.  But then we
00877                  * cannot enter this loop.
00878                  */
00879                 if (cderrno) {
00880                         if (nlinks) {
00881                                 p->fts_info = FTS_NS;
00882                                 p->fts_errno = cderrno;
00883                         } else
00884                                 p->fts_info = FTS_NSOK;
00885                         p->fts_accpath = cur->fts_accpath;
00886                 } else
00887 #endif
00888                 if (nlinks == 0
00889 #if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
00890                            || (nostat &&
00891                                dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
00892 #endif
00893                     ) {
00894                         p->fts_accpath =
00895                             ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
00896                         p->fts_info = FTS_NSOK;
00897                 } else {
00898                         /* Build a file name for fts_stat to stat. */
00899                         if (ISSET(FTS_NOCHDIR)) {
00900                                 p->fts_accpath = p->fts_path;
00901                                 memmove(cp, p->fts_name, p->fts_namelen + 1);
00902                         } else
00903                                 p->fts_accpath = p->fts_name;
00904                         /* Stat it. */
00905                         p->fts_info = fts_stat(sp, p, 0);
00906 
00907                         /* Decrement link count if applicable. */
00908                         if (nlinks > 0 && (p->fts_info == FTS_D ||
00909                             p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
00910                                 --nlinks;
00911                 }
00912 
00913                 /* We walk in directory order so "ls -f" doesn't get upset. */
00914                 p->fts_link = NULL;
00915                 if (head == NULL)
00916                         head = tail = p;
00917                 else {
00918                         tail->fts_link = p;
00919                         tail = p;
00920                 }
00921                 ++nitems;
00922         }
00923         if (dirp)
00924                 (void) (*sp->fts_closedir) (dirp);
00925 
00926         /*
00927          * If realloc() changed the address of the path, adjust the
00928          * addresses for the rest of the tree and the dir list.
00929          */
00930         if (doadjust)
00931                 fts_padjust(sp, head);
00932 
00933         /*
00934          * If not changing directories, reset the path back to original
00935          * state.
00936          */
00937         if (ISSET(FTS_NOCHDIR)) {
00938                 if (len == sp->fts_pathlen || nitems == 0)
00939                         --cp;
00940 /*@-boundswrite@*/
00941                 if (cp != NULL) /* XXX can't happen */
00942                         *cp = '\0';
00943 /*@=boundswrite@*/
00944         }
00945 
00946         /*
00947          * If descended after called from fts_children or after called from
00948          * fts_read and nothing found, get back.  At the root level we use
00949          * the saved fd; if one of fts_open()'s arguments is a relative path
00950          * to an empty directory, we wind up here with no other way back.  If
00951          * can't get back, we're done.
00952          */
00953         if (descend && (type == BCHILD || !nitems) &&
00954             (cur->fts_level == FTS_ROOTLEVEL ?
00955              FCHDIR(sp, sp->fts_rfd) :
00956              fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
00957                 cur->fts_info = FTS_ERR;
00958                 SET(FTS_STOP);
00959                 fts_lfree(head);
00960                 return (NULL);
00961         }
00962 
00963         /* If didn't find anything, return NULL. */
00964         if (!nitems) {
00965                 if (type == BREAD)
00966                         cur->fts_info = FTS_DP;
00967                 fts_lfree(head);
00968                 return (NULL);
00969         }
00970 
00971         /* Sort the entries. */
00972         if (sp->fts_compar && nitems > 1)
00973                 head = fts_sort(sp, head, nitems);
00974         return (head);
00975 }
00976 
00977 static u_short
00978 fts_stat(FTS * sp, FTSENT * p, int follow)
00979 {
00980         register FTSENT *t;
00981         register dev_t dev;
00982         register ino_t ino;
00983         struct stat *sbp, sb;
00984         int saved_errno;
00985 
00986         /* If user needs stat info, stat buffer already allocated. */
00987         sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
00988 
00989 #if defined FTS_WHITEOUT && 0
00990         /* check for whiteout */
00991         if (p->fts_flags & FTS_ISW) {
00992                 if (sbp != &sb) {
00993                         memset(sbp, '\0', sizeof (*sbp));
00994                         sbp->st_mode = S_IFWHT;
00995                 }
00996                 return (FTS_W);
00997        }
00998 #endif
00999 
01000         /*
01001          * If doing a logical walk, or application requested FTS_FOLLOW, do
01002          * a stat(2).  If that fails, check for a non-existent symlink.  If
01003          * fail, set the errno from the stat call.
01004          */
01005         if (ISSET(FTS_LOGICAL) || follow) {
01006                 if ((*sp->fts_stat) (p->fts_accpath, sbp)) {
01007                         saved_errno = errno;
01008                         if (!(*sp->fts_lstat) (p->fts_accpath, sbp)) {
01009 /*@-boundswrite@*/
01010                                 __set_errno (0);
01011 /*@=boundswrite@*/
01012                                 return (FTS_SLNONE);
01013                         }
01014                         p->fts_errno = saved_errno;
01015                         goto err;
01016                 }
01017         } else if ((*sp->fts_lstat) (p->fts_accpath, sbp)) {
01018                 p->fts_errno = errno;
01019 /*@-boundswrite@*/
01020 err:            memset(sbp, 0, sizeof(*sbp));
01021 /*@=boundswrite@*/
01022                 return (FTS_NS);
01023         }
01024 
01025         if (S_ISDIR(sbp->st_mode)) {
01026                 /*
01027                  * Set the device/inode.  Used to find cycles and check for
01028                  * crossing mount points.  Also remember the link count, used
01029                  * in fts_build to limit the number of stat calls.  It is
01030                  * understood that these fields are only referenced if fts_info
01031                  * is set to FTS_D.
01032                  */
01033                 dev = p->fts_dev = sbp->st_dev;
01034                 ino = p->fts_ino = sbp->st_ino;
01035                 p->fts_nlink = sbp->st_nlink;
01036 
01037                 if (ISDOT(p->fts_name))
01038                         return (FTS_DOT);
01039 
01040                 /*
01041                  * Cycle detection is done by brute force when the directory
01042                  * is first encountered.  If the tree gets deep enough or the
01043                  * number of symbolic links to directories is high enough,
01044                  * something faster might be worthwhile.
01045                  */
01046                 for (t = p->fts_parent;
01047                     t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
01048                         if (ino == t->fts_ino && dev == t->fts_dev) {
01049                                 p->fts_cycle = t;
01050                                 return (FTS_DC);
01051                         }
01052                 return (FTS_D);
01053         }
01054         if (S_ISLNK(sbp->st_mode))
01055                 return (FTS_SL);
01056         if (S_ISREG(sbp->st_mode))
01057                 return (FTS_F);
01058         return (FTS_DEFAULT);
01059 }
01060 
01061 static FTSENT *
01062 fts_sort(FTS * sp, FTSENT * head, int nitems)
01063 {
01064         register FTSENT **ap, *p;
01065 
01066         /*
01067          * Construct an array of pointers to the structures and call qsort(3).
01068          * Reassemble the array in the order returned by qsort.  If unable to
01069          * sort for memory reasons, return the directory entries in their
01070          * current order.  Allocate enough space for the current needs plus
01071          * 40 so don't realloc one entry at a time.
01072          */
01073         if (nitems > sp->fts_nitems) {
01074                 struct _ftsent **a;
01075 
01076                 sp->fts_nitems = nitems + 40;
01077                 if ((a = realloc(sp->fts_array,
01078                     (size_t)(sp->fts_nitems * sizeof(*sp->fts_array)))) == NULL)
01079                 {
01080                         free(sp->fts_array);
01081                         sp->fts_array = NULL;
01082                         sp->fts_nitems = 0;
01083                         return (head);
01084                 }
01085                 sp->fts_array = a;
01086         }
01087 /*@-boundswrite@*/
01088         for (ap = sp->fts_array, p = head; p != NULL; p = p->fts_link)
01089                 *ap++ = p;
01090         qsort((void *)sp->fts_array, nitems, sizeof(*sp->fts_array),
01091                 sp->fts_compar);
01092         for (head = *(ap = sp->fts_array); --nitems; ++ap)
01093                 ap[0]->fts_link = ap[1];
01094         ap[0]->fts_link = NULL;
01095 /*@=boundswrite@*/
01096         return (head);
01097 }
01098 
01099 static FTSENT *
01100 fts_alloc(FTS * sp, const char * name, int namelen)
01101 {
01102         register FTSENT *p;
01103         size_t len;
01104 
01105         /*
01106          * The file name is a variable length array and no stat structure is
01107          * necessary if the user has set the nostat bit.  Allocate the FTSENT
01108          * structure, the file name and the stat structure in one chunk, but
01109          * be careful that the stat structure is reasonably aligned.  Since the
01110          * fts_name field is declared to be of size 1, the fts_name pointer is
01111          * namelen + 2 before the first possible address of the stat structure.
01112          */
01113         len = sizeof(*p) + namelen;
01114         if (!ISSET(FTS_NOSTAT))
01115                 len += sizeof(*p->fts_statp) + ALIGNBYTES;
01116         if ((p = malloc(len)) == NULL)
01117                 return (NULL);
01118 
01119         /* Copy the name and guarantee NUL termination. */
01120 /*@-boundswrite@*/
01121         memmove(p->fts_name, name, namelen);
01122         p->fts_name[namelen] = '\0';
01123 /*@=boundswrite@*/
01124 
01125         if (!ISSET(FTS_NOSTAT))
01126                 p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
01127         p->fts_namelen = namelen;
01128         p->fts_path = sp->fts_path;
01129         p->fts_errno = 0;
01130         p->fts_flags = 0;
01131         p->fts_instr = FTS_NOINSTR;
01132         p->fts_number = 0;
01133         p->fts_pointer = NULL;
01134         return (p);
01135 }
01136 
01137 static void
01138 fts_lfree(FTSENT * head)
01139 {
01140         register FTSENT *p;
01141 
01142         /* Free a linked list of structures. */
01143         /*@-branchstate@*/
01144         while ((p = head)) {
01145                 head = head->fts_link;
01146                 free(p);
01147         }
01148         /*@=branchstate@*/
01149 }
01150 
01151 /*
01152  * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
01153  * Most systems will allow creation of paths much longer than MAXPATHLEN, even
01154  * though the kernel won't resolve them.  Add the size (not just what's needed)
01155  * plus 256 bytes so don't realloc the path 2 bytes at a time.
01156  */
01157 static int
01158 fts_palloc(FTS * sp, size_t more)
01159 {
01160         char *p;
01161 
01162         sp->fts_pathlen += more + 256;
01163         /*
01164          * Check for possible wraparound.  In an FTS, fts_pathlen is
01165          * a signed int but in an FTSENT it is an unsigned short.
01166          * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
01167          */
01168         if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
01169                 if (sp->fts_path)
01170                         free(sp->fts_path);
01171                 sp->fts_path = NULL;
01172 /*@-boundswrite@*/
01173                 __set_errno (ENAMETOOLONG);
01174 /*@=boundswrite@*/
01175                 return (1);
01176         }
01177         p = realloc(sp->fts_path, sp->fts_pathlen);
01178         if (p == NULL) {
01179                 free(sp->fts_path);
01180                 sp->fts_path = NULL;
01181                 return 1;
01182         }
01183         sp->fts_path = p;
01184         return 0;
01185 }
01186 
01187 /*
01188  * When the path is realloc'd, have to fix all of the pointers in structures
01189  * already returned.
01190  */
01191 static void
01192 fts_padjust(FTS * sp, FTSENT * head)
01193 {
01194         FTSENT *p;
01195         char *addr = sp->fts_path;
01196 
01197 #define ADJUST(p) do {                                                  \
01198         if ((p)->fts_accpath != (p)->fts_name) {                        \
01199                 (p)->fts_accpath =                                      \
01200                     (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
01201         }                                                               \
01202         (p)->fts_path = addr;                                           \
01203 } while (0)
01204         /* Adjust the current set of children. */
01205         for (p = sp->fts_child; p != NULL; p = p->fts_link)
01206                 ADJUST(p);
01207 
01208         /* Adjust the rest of the tree, including the current level. */
01209         for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
01210                 ADJUST(p);
01211                 p = p->fts_link ? p->fts_link : p->fts_parent;
01212         }
01213 }
01214 
01215 static size_t
01216 fts_maxarglen(char * const * argv)
01217 {
01218         size_t len, max;
01219 
01220         for (max = 0; *argv; ++argv)
01221                 if ((len = strlen(*argv)) > max)
01222                         max = len;
01223         return (max + 1);
01224 }
01225 
01226 /*
01227  * Change to dir specified by fd or p->fts_accpath without getting
01228  * tricked by someone changing the world out from underneath us.
01229  * Assumes p->fts_dev and p->fts_ino are filled in.
01230  */
01231 static int
01232 fts_safe_changedir(FTS * sp, FTSENT * p, int fd, const char * path)
01233 {
01234         int ret, oerrno, newfd;
01235         struct stat64 sb;
01236 
01237         newfd = fd;
01238         if (ISSET(FTS_NOCHDIR))
01239                 return (0);
01240         if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0)
01241                 return (-1);
01242         if (__fxstat64(_STAT_VER, newfd, &sb)) {
01243                 ret = -1;
01244                 goto bail;
01245         }
01246         if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
01247 /*@-boundswrite@*/
01248                 __set_errno (ENOENT);           /* disinformation */
01249 /*@=boundswrite@*/
01250                 ret = -1;
01251                 goto bail;
01252         }
01253         ret = __fchdir(newfd);
01254 bail:
01255         oerrno = errno;
01256         if (fd < 0)
01257                 (void)__close(newfd);
01258 /*@-boundswrite@*/
01259         __set_errno (oerrno);
01260 /*@=boundswrite@*/
01261         return (ret);
01262 }
01263 /*@=compdef =compmempass =dependenttrans =retalias @*/
01264 /*@=sysunrecog =noeffectuncon =nullpass =sizeoftype =unrecog =usereleased @*/
01265 /*@=boundsread@*/

Generated on Sun Aug 18 14:31:23 2013 for rpm by  doxygen 1.4.4