Changeset 619


Ignore:
Timestamp:
Nov 26, 2006, 7:53:00 AM (19 years ago)
Author:
bird
Message:

NetBSD: /fts13.c/1.44/Wed Jan 19 00:59:48 2005

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gmake/kmkbuiltin/fts.c

    r370 r619  
     1/*      $NetBSD: __fts13.c,v 1.44 2005/01/19 00:59:48 mycroft Exp $     */
     2
    13/*-
    24 * Copyright (c) 1990, 1993, 1994
     
    1113 *    notice, this list of conditions and the following disclaimer in the
    1214 *    documentation and/or other materials provided with the distribution.
    13  * 3. All advertising materials mentioning features or use of this software
    14  *    must display the following acknowledgement:
    15  *      This product includes software developed by the University of
    16  *      California, Berkeley and its contributors.
    17  * 4. Neither the name of the University nor the names of its contributors
     15 * 3. Neither the name of the University nor the names of its contributors
    1816 *    may be used to endorse or promote products derived from this software
    1917 *    without specific prior written permission.
     
    3028 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    3129 * SUCH DAMAGE.
    32  *
    33  * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
    3430 */
    3531
     32#if HAVE_NBTOOL_CONFIG_H
     33#include "nbtool_config.h"
     34#endif
     35
     36#include <sys/cdefs.h>
     37#if defined(LIBC_SCCS) && !defined(lint)
    3638#if 0
    37 #if defined(LIBC_SCCS) && !defined(lint)
    3839static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
     40#else
     41__RCSID("$NetBSD: __fts13.c,v 1.44 2005/01/19 00:59:48 mycroft Exp $");
     42#endif
    3943#endif /* LIBC_SCCS and not lint */
    4044
    41 #include <sys/cdefs.h>
    42 __FBSDID("$FreeBSD: src/lib/libc/gen/fts.c,v 1.27 2004/06/08 06:23:23 das Exp $");
    43 #endif
    44 
    45 //#include "namespace.h"
    46 #ifndef _MSC_VER
     45#include "namespace.h"
    4746#include <sys/param.h>
    48 #include <sys/mount.h>
    49 #endif
    5047#include <sys/stat.h>
    5148
     49#include <assert.h>
    5250#include <dirent.h>
    5351#include <errno.h>
    5452#include <fcntl.h>
     53#include <fts.h>
    5554#include <stdlib.h>
    5655#include <string.h>
    57 #ifndef _MSC_VER
    5856#include <unistd.h>
     57
     58#if ! HAVE_NBTOOL_CONFIG_H
     59#define HAVE_STRUCT_DIRENT_D_NAMLEN 1
     60#endif
     61
     62#ifdef __weak_alias
     63#ifdef __LIBC12_SOURCE__
     64__weak_alias(fts_children,_fts_children)
     65__weak_alias(fts_close,_fts_close)
     66__weak_alias(fts_open,_fts_open)
     67__weak_alias(fts_read,_fts_read)
     68__weak_alias(fts_set,_fts_set)
     69#endif /* __LIBC12_SOURCE__ */
     70#endif /* __weak_alias */
     71
     72#ifdef __LIBC12_SOURCE__
     73#define STAT    stat12
    5974#else
    60 #include "mscfakes.h"
    61 #define dirfd(dir) -1
    62 #endif
    63 #include "ftsfake.h"
    64 //#include "un-namespace.h"
    65 
    66 static FTSENT   *fts_alloc(FTS *, char *, int);
    67 static FTSENT   *fts_build(FTS *, int);
    68 static void      fts_lfree(FTSENT *);
    69 static void      fts_load(FTS *, FTSENT *);
    70 static size_t    fts_maxarglen(char * const *);
    71 static void      fts_padjust(FTS *, FTSENT *);
    72 static int       fts_palloc(FTS *, size_t);
    73 static FTSENT   *fts_sort(FTS *, FTSENT *, int);
    74 static u_short   fts_stat(FTS *, FTSENT *, int);
    75 static int       fts_safe_changedir(FTS *, FTSENT *, int, char *);
    76 static int       fts_ufslinks(FTS *, const FTSENT *);
    77 
    78 #if defined(__EMX__) || defined(_MSC_VER)
    79 # define NEED_STRRSLASH
    80 # define IS_SLASH(ch)   ( (ch) == '/' || (ch) == '\\' )
    81 #else
    82 # define HAVE_FCHDIR
    83 # define IS_SLASH(ch)   ( (ch) == '/' )
    84 #endif
     75#define STAT    stat
     76#endif
     77
     78#ifdef __LIBC12_SOURCE__
     79__warn_references(fts_children,
     80    "warning: reference to compatibility fts_children();"
     81    " include <fts.h> for correct reference")
     82__warn_references(fts_close,
     83    "warning: reference to compatibility fts_close();"
     84    " include <fts.h> for correct reference")
     85__warn_references(fts_open,
     86    "warning: reference to compatibility fts_open();"
     87    " include <fts.h> for correct reference")
     88__warn_references(fts_read,
     89    "warning: reference to compatibility fts_read();"
     90    " include <fts.h> for correct reference")
     91__warn_references(fts_set,
     92    "warning: reference to compatibility fts_set();"
     93    " include <fts.h> for correct reference")
     94#endif
     95
     96static FTSENT   *fts_alloc __P((FTS *, const char *, size_t));
     97static FTSENT   *fts_build __P((FTS *, int));
     98static void      fts_lfree __P((FTSENT *));
     99static void      fts_load __P((FTS *, FTSENT *));
     100static size_t    fts_maxarglen __P((char * const *));
     101static size_t    fts_pow2 __P((size_t));
     102static int       fts_palloc __P((FTS *, size_t));
     103static void      fts_padjust __P((FTS *, FTSENT *));
     104static FTSENT   *fts_sort __P((FTS *, FTSENT *, size_t));
     105static u_short   fts_stat __P((FTS *, FTSENT *, int));
     106static int       fts_safe_changedir __P((const FTS *, const FTSENT *, int,
     107    const char *));
    85108
    86109#define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
     
    90113#define SET(opt)        (sp->fts_options |= (opt))
    91114
    92 #ifdef HAVE_FCHDIR
     115#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path))
    93116#define FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))
    94 #else
    95 #define FCHDIR(sp, rdir) (!ISSET(FTS_NOCHDIR) && chdir(rdir))
    96 #endif
    97117
    98118/* fts_build flags */
     
    101121#define BREAD           3               /* fts_read */
    102122
    103 /*
    104  * Internal representation of an FTS, including extra implementation
    105  * details.  The FTS returned from fts_open points to this structure's
    106  * ftsp_fts member (and can be cast to an _fts_private as required)
    107  */
    108 struct _fts_private {
    109         FTS             ftsp_fts;
    110 #ifndef _MSC_VER
    111         struct statfs   ftsp_statfs;
    112 #endif
    113         dev_t           ftsp_dev;
    114         int             ftsp_linksreliable;
    115 };
    116 
    117 #if !defined(__EMX__) && !defined(_MSC_VER)
    118 /*
    119  * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
    120  * knows that a directory could not possibly have subdirectories.  This
    121  * is decided by looking at the link count: a subdirectory would
    122  * increment its parent's link count by virtue of its own ".." entry.
    123  * This assumption only holds for UFS-like filesystems that implement
    124  * links and directories this way, so we must punt for others.
    125  */
    126 
    127 static const char *ufslike_filesystems[] = {
    128         "ufs",
    129         "nfs",
    130         "nfs4",
    131         "ext2fs",
    132         0
    133 };
    134 #endif /* !__EMX__ && !_MSC_VER */
     123#ifndef DTF_HIDEW
     124#undef FTS_WHITEOUT
     125#endif
    135126
    136127FTS *
     
    138129        char * const *argv;
    139130        int options;
    140         int (*compar)(const FTSENT * const *, const FTSENT * const *);
    141 {
    142         struct _fts_private *priv;
     131        int (*compar) __P((const FTSENT **, const FTSENT **));
     132{
    143133        FTS *sp;
    144134        FTSENT *p, *root;
    145         int nitems;
    146         FTSENT *parent, *tmp;
    147         int len;
     135        size_t nitems;
     136        FTSENT *parent, *tmp = NULL;    /* pacify gcc */
     137        size_t len;
     138
     139        _DIAGASSERT(argv != NULL);
    148140
    149141        /* Options check. */
     
    153145        }
    154146
    155         /* Allocate/initialize the stream. */
    156         if ((priv = malloc(sizeof(*priv))) == NULL)
     147        /* Allocate/initialize the stream */
     148        if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
    157149                return (NULL);
    158         memset(priv, 0, sizeof(*priv));
    159         sp = &priv->ftsp_fts;
     150        memset(sp, 0, sizeof(FTS));
    160151        sp->fts_compar = compar;
    161152        sp->fts_options = options;
    162 
    163         /* Shush, GCC. */
    164         tmp = NULL;
    165153
    166154        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
     
    181169
    182170        /* Allocate/initialize root(s). */
    183         for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
     171        for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
    184172                /* Don't allow zero-length paths. */
    185173                if ((len = strlen(*argv)) == 0) {
     
    188176                }
    189177
    190                 p = fts_alloc(sp, *argv, len);
     178                if ((p = fts_alloc(sp, *argv, len)) == NULL)
     179                        goto mem3;
    191180                p->fts_level = FTS_ROOTLEVEL;
    192181                p->fts_parent = parent;
     
    229218
    230219        /*
    231          * If using chdir(2), grab a file descriptor pointing to dot to ensure
     220         * If using chdir(2), grab a file descriptor pointing to dot to insure
    232221         * that we can get back here; this could be avoided for some paths,
    233222         * but almost certainly not worth the effort.  Slashes, symbolic links,
     
    235224         * descriptor we run anyway, just more slowly.
    236225         */
    237 #ifdef HAVE_FCHDIR
    238         if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = _open(".", O_RDONLY, 0)) < 0)
    239 #else
    240         if (!ISSET(FTS_NOCHDIR) && (sp->fts_rdir = getcwd(NULL, 0)) != NULL)
    241 #endif
    242             SET(FTS_NOCHDIR);
     226        if (!ISSET(FTS_NOCHDIR)) {
     227                if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1)
     228                        SET(FTS_NOCHDIR);
     229                else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) {
     230                        close(sp->fts_rfd);
     231                        SET(FTS_NOCHDIR);
     232                }
     233        }
    243234
    244235        return (sp);
     
    251242}
    252243
    253 #ifdef NEED_STRRSLASH
    254 static char *strrslash(register char *psz)
    255 {
    256     register char ch;
    257     char *pszLast = NULL;
    258     for (; (ch = *psz); psz++)
    259         switch (ch)
    260         {
    261             case '/':
    262             case '\\':
    263             case ':':
    264                 pszLast = psz;
    265                 break;
    266         }
    267     return pszLast;
    268 }
    269 #endif
    270 
    271244static void
    272245fts_load(sp, p)
     
    274247        FTSENT *p;
    275248{
    276         int len;
     249        size_t len;
    277250        char *cp;
     251
     252        _DIAGASSERT(sp != NULL);
     253        _DIAGASSERT(p != NULL);
    278254
    279255        /*
     
    286262        len = p->fts_pathlen = p->fts_namelen;
    287263        memmove(sp->fts_path, p->fts_name, len + 1);
    288 #ifdef NEED_STRRSLASH
    289         if ((cp = strrslash(p->fts_name)) && (cp != p->fts_name || cp[1])) {
    290 #else
    291264        if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
    292 #endif
    293265                len = strlen(++cp);
    294266                memmove(p->fts_name, cp, len + 1);
     
    304276{
    305277        FTSENT *freep, *p;
    306         int saved_errno;
     278        int saved_errno = 0;
     279
     280        _DIAGASSERT(sp != NULL);
    307281
    308282        /*
     
    312286         */
    313287        if (sp->fts_cur) {
     288                if (ISSET(FTS_SYMFOLLOW))
     289                        (void)close(sp->fts_cur->fts_symfd);
    314290                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
    315291                        freep = p;
    316                         p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
     292                        p = p->fts_link ? p->fts_link : p->fts_parent;
    317293                        free(freep);
    318294                }
     
    329305        /* Return to original directory, save errno if necessary. */
    330306        if (!ISSET(FTS_NOCHDIR)) {
    331 #ifdef HAVE_FCHDIR
    332                 saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
    333                 (void)_close(sp->fts_rfd);
    334 #else
    335                 saved_errno = chdir(sp->fts_rdir) ? errno : 0;
    336                 free(sp->fts_rdir); sp->fts_rdir = NULL;
    337 #endif
    338 
    339                 /* Set errno and return. */
    340                 if (saved_errno != 0) {
    341                         /* Free up the stream pointer. */
    342                         free(sp);
    343                         errno = saved_errno;
    344                         return (-1);
    345                 }
     307                if (fchdir(sp->fts_rfd))
     308                        saved_errno = errno;
     309                (void)close(sp->fts_rfd);
    346310        }
    347311
    348312        /* Free up the stream pointer. */
    349313        free(sp);
     314        /* ISSET() is illegal after this, since the macro touches sp */
     315
     316        /* Set errno and return. */
     317        if (saved_errno) {
     318                errno = saved_errno;
     319                return (-1);
     320        }
    350321        return (0);
    351322}
    352323
    353 
    354324/*
    355  * Special case of "/" at the end of the path so that slashes aren't
    356  * appended which would cause paths to be written as "....//foo".
     325 * Special case a root of "/" so that slashes aren't appended which would
     326 * cause paths to be written as "//foo".
    357327 */
    358328#define NAPPEND(p)                                                      \
    359         (IS_SLASH(p->fts_path[p->fts_pathlen - 1])                      \
    360             ? p->fts_pathlen - 1 : p->fts_pathlen)
     329        (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 &&        \
     330            p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
    361331
    362332FTSENT *
     
    369339        int saved_errno;
    370340
     341        _DIAGASSERT(sp != NULL);
     342
    371343        /* If finished or unrecoverable error, return NULL. */
    372344        if (sp->fts_cur == NULL || ISSET(FTS_STOP))
     
    396368                p->fts_info = fts_stat(sp, p, 1);
    397369                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    398 #ifdef HAVE_FCHDIR
    399                         if ((p->fts_symfd = _open(".", O_RDONLY, 0)) < 0) {
     370                        if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) {
    400371                                p->fts_errno = errno;
    401372                                p->fts_info = FTS_ERR;
     373                        } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
     374                                p->fts_errno = errno;
     375                                p->fts_info = FTS_ERR;
     376                                close(p->fts_symfd);
    402377                        } else
    403378                                p->fts_flags |= FTS_SYMFOLLOW;
    404 #endif
    405379                }
    406380                return (p);
     
    412386                if (instr == FTS_SKIP ||
    413387                    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
    414 #ifdef HAVE_FCHDIR
    415388                        if (p->fts_flags & FTS_SYMFOLLOW)
    416                                 (void)_close(p->fts_symfd);
    417 #endif
     389                                (void)close(p->fts_symfd);
    418390                        if (sp->fts_child) {
    419391                                fts_lfree(sp->fts_child);
     
    422394                        p->fts_info = FTS_DP;
    423395                        return (p);
    424                 }
     396                } 
    425397
    426398                /* Rebuild if only read the names and now traversing. */
    427                 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
     399                if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
    428400                        CLR(FTS_NAMEONLY);
    429401                        fts_lfree(sp->fts_child);
     
    443415                 * FTS_STOP or the fts_info field of the node.
    444416                 */
    445                 if (sp->fts_child != NULL) {
     417                if (sp->fts_child) {
    446418                        if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
    447419                                p->fts_errno = errno;
    448420                                p->fts_flags |= FTS_DONTCHDIR;
    449                                 for (p = sp->fts_child; p != NULL;
    450                                     p = p->fts_link)
     421                                for (p = sp->fts_child; p; p = p->fts_link)
    451422                                        p->fts_accpath =
    452423                                            p->fts_parent->fts_accpath;
     
    468439
    469440                /*
    470                  * If reached the top, return to the original directory (or
    471                  * the root of the tree), and load the paths for the next root.
     441                 * If reached the top, return to the original directory, and
     442                 * load the paths for the next root.
    472443                 */
    473444                if (p->fts_level == FTS_ROOTLEVEL) {
    474 #ifdef HAVE_FCHDIR
    475445                        if (FCHDIR(sp, sp->fts_rfd)) {
    476 #else
    477                         if (FCHDIR(sp, sp->fts_rdir)) {
    478 #endif
    479446                                SET(FTS_STOP);
    480447                                return (NULL);
     
    494461                        p->fts_info = fts_stat(sp, p, 1);
    495462                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    496 #ifdef HAVE_FCHDIR
    497463                                if ((p->fts_symfd =
    498                                     _open(".", O_RDONLY, 0)) < 0) {
     464                                    open(".", O_RDONLY, 0)) == -1) {
    499465                                        p->fts_errno = errno;
    500466                                        p->fts_info = FTS_ERR;
     467                                } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
     468                                        p->fts_errno = errno;
     469                                        p->fts_info = FTS_ERR;
     470                                        close(p->fts_symfd);
    501471                                } else
    502472                                        p->fts_flags |= FTS_SYMFOLLOW;
    503 #endif
    504473                        }
    505474                        p->fts_instr = FTS_NOINSTR;
     
    508477name:           t = sp->fts_path + NAPPEND(p->fts_parent);
    509478                *t++ = '/';
    510                 memmove(t, p->fts_name, p->fts_namelen + 1);
     479                memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1));
    511480                return (sp->fts_cur = p);
    512481        }
     
    526495        }
    527496
    528         /* NUL terminate the pathname. */
     497        /* Nul terminate the pathname. */
    529498        sp->fts_path[p->fts_pathlen] = '\0';
    530499
     
    535504         */
    536505        if (p->fts_level == FTS_ROOTLEVEL) {
    537 #ifdef HAVE_FCHDIR
    538506                if (FCHDIR(sp, sp->fts_rfd)) {
    539 #else
    540                 if (FCHDIR(sp, sp->fts_rdir)) {
    541 #endif
    542507                        SET(FTS_STOP);
    543508                        return (NULL);
    544509                }
    545 #ifdef HAVE_FCHDIR
    546510        } else if (p->fts_flags & FTS_SYMFOLLOW) {
    547511                if (FCHDIR(sp, p->fts_symfd)) {
    548512                        saved_errno = errno;
    549                         (void)_close(p->fts_symfd);
     513                        (void)close(p->fts_symfd);
    550514                        errno = saved_errno;
    551515                        SET(FTS_STOP);
    552516                        return (NULL);
    553517                }
    554                 (void)_close(p->fts_symfd);
    555 #else
    556         (void)saved_errno;
    557 #endif
     518                (void)close(p->fts_symfd);
    558519        } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
    559520            fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
     
    578539        int instr;
    579540{
    580         if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
     541
     542        _DIAGASSERT(sp != NULL);
     543        _DIAGASSERT(p != NULL);
     544
     545        if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
    581546            instr != FTS_NOINSTR && instr != FTS_SKIP) {
    582547                errno = EINVAL;
     
    593558{
    594559        FTSENT *p;
    595 #ifdef HAVE_FCHDIR
    596560        int fd;
    597 #else
    598         char *pszRoot;
    599         int rc;
    600 #endif
    601         if (instr != 0 && instr != FTS_NAMEONLY) {
     561
     562        _DIAGASSERT(sp != NULL);
     563
     564        if (instr && instr != FTS_NAMEONLY) {
    602565                errno = EINVAL;
    603566                return (NULL);
     
    630593
    631594        /* Free up any previous child list. */
    632         if (sp->fts_child != NULL)
     595        if (sp->fts_child)
    633596                fts_lfree(sp->fts_child);
    634597
     
    636599                SET(FTS_NAMEONLY);
    637600                instr = BNAMES;
    638         } else
     601        } else 
    639602                instr = BCHILD;
    640603
     
    646609         * fts_read will work.
    647610         */
    648         if (p->fts_level != FTS_ROOTLEVEL || IS_SLASH(p->fts_accpath[0]) ||
     611        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
    649612            ISSET(FTS_NOCHDIR))
    650613                return (sp->fts_child = fts_build(sp, instr));
    651614
    652 #ifdef HAVE_FCHDIR
    653         if ((fd = _open(".", O_RDONLY, 0)) < 0)
    654 #else
    655         if ((pszRoot = getcwd(NULL, 0)) == NULL)
    656 #endif
     615        if ((fd = open(".", O_RDONLY, 0)) == -1)
     616                return (sp->fts_child = NULL);
     617        sp->fts_child = fts_build(sp, instr);
     618        if (fchdir(fd)) {
     619                (void)close(fd);
    657620                return (NULL);
    658         sp->fts_child = fts_build(sp, instr);
    659 #ifdef HAVE_FCHDIR
    660         if (fchdir(fd))
    661                 return (NULL);
    662         (void)_close(fd);
    663 #else
    664         rc = chdir(pszRoot);
    665         free(pszRoot);
    666         if (rc)
    667             return NULL;
    668 #endif
     621        }
     622        (void)close(fd);
    669623        return (sp->fts_child);
    670 }
    671 
    672 #ifndef fts_get_clientptr
    673 #error "fts_get_clientptr not defined"
    674 #endif
    675 
    676 void *
    677 (fts_get_clientptr)(FTS *sp)
    678 {
    679 
    680         return (fts_get_clientptr(sp));
    681 }
    682 
    683 #ifndef fts_get_stream
    684 #error "fts_get_stream not defined"
    685 #endif
    686 
    687 FTS *
    688 (fts_get_stream)(FTSENT *p)
    689 {
    690         return (fts_get_stream(p));
    691 }
    692 
    693 void
    694 fts_set_clientptr(FTS *sp, void *clientptr)
    695 {
    696 
    697         sp->fts_clientptr = clientptr;
    698624}
    699625
     
    719645        struct dirent *dp;
    720646        FTSENT *p, *head;
    721         int nitems;
     647        size_t nitems;
    722648        FTSENT *cur, *tail;
    723649        DIR *dirp;
    724         void *oldaddr;
    725         int dnamlen;
    726         int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno,
    727             nostat, doadjust;
    728         char *cp;
     650        int adjust, cderrno, descend, len, level, nlinks, saved_errno, nostat;
     651        size_t maxlen;
     652#ifdef FTS_WHITEOUT
     653        int oflag;
     654#endif
     655        char *cp = NULL;        /* pacify gcc */
     656
     657        _DIAGASSERT(sp != NULL);
    729658
    730659        /* Set current node pointer. */
     
    737666#ifdef FTS_WHITEOUT
    738667        if (ISSET(FTS_WHITEOUT))
    739                 oflag = DTF_NODUP | DTF_REWIND;
     668                oflag = DTF_NODUP|DTF_REWIND;
    740669        else
    741                 oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND;
     670                oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
    742671#else
    743         (void)(oflag);
    744672#define __opendir2(path, flag) opendir(path)
    745673#endif
     
    759687        if (type == BNAMES) {
    760688                nlinks = 0;
    761                 /* Be quiet about nostat, GCC. */
    762                 nostat = 0;
     689                nostat = 1;
    763690        } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
    764                 if (fts_ufslinks(sp, cur))
    765                         nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
    766                 else
    767                         nlinks = -1;
     691                nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
    768692                nostat = 1;
    769693        } else {
     
    794718        cderrno = 0;
    795719        if (nlinks || type == BREAD) {
    796 #ifdef HAVE_FCHDIR
    797720                if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
    798 #else
    799                 if (fts_safe_changedir(sp, cur, dirfd(dirp), cur->fts_accpath)) {
    800 #endif
    801721                        if (nlinks && type == BREAD)
    802722                                cur->fts_errno = errno;
     
    823743                cp = sp->fts_path + len;
    824744                *cp++ = '/';
    825         } else {
    826                 /* GCC, you're too verbose. */
    827                 cp = NULL;
    828745        }
    829746        len++;
     
    833750
    834751        /* Read the directory, attaching each entry to the `link' pointer. */
    835         doadjust = 0;
    836         for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
    837 #ifdef _MSC_VER
    838                 dnamlen = strlen(dp->d_name);
    839 #else
    840                 dnamlen = dp->d_namlen;
    841 #endif
     752        adjust = 0;
     753        for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) {
     754                size_t dlen;
     755
    842756                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
    843757                        continue;
    844758
    845                 if ((p = fts_alloc(sp, dp->d_name, (int)dnamlen)) == NULL)
     759#if HAVE_STRUCT_DIRENT_D_NAMLEN
     760                dlen = dp->d_namlen;
     761#else
     762                dlen = strlen(dp->d_name);
     763#endif
     764                if ((p = fts_alloc(sp, dp->d_name, dlen)) == NULL)
    846765                        goto mem1;
    847                 if (dnamlen >= maxlen) {        /* include space for NUL */
    848                         oldaddr = sp->fts_path;
    849                         if (fts_palloc(sp, dnamlen + len + 1)) {
     766                if (dlen >= maxlen) {   /* include space for NUL */
     767                        if (fts_palloc(sp, len + dlen + 1)) {
    850768                                /*
    851769                                 * No more memory for path or structures.  Save
     
    858776                                fts_lfree(head);
    859777                                (void)closedir(dirp);
     778                                errno = saved_errno;
    860779                                cur->fts_info = FTS_ERR;
    861780                                SET(FTS_STOP);
    862                                 errno = saved_errno;
    863781                                return (NULL);
    864782                        }
    865                         /* Did realloc() change the pointer? */
    866                         if (oldaddr != sp->fts_path) {
    867                                 doadjust = 1;
    868                                 if (ISSET(FTS_NOCHDIR))
    869                                         cp = sp->fts_path + len;
    870                         }
     783                        adjust = 1;
     784                        if (ISSET(FTS_NOCHDIR))
     785                                cp = sp->fts_path + len;
    871786                        maxlen = sp->fts_pathlen - len;
    872787                }
    873788
    874                 if (len + dnamlen >= USHRT_MAX) {
    875                         /*
    876                          * In an FTSENT, fts_pathlen is a u_short so it is
    877                          * possible to wraparound here.  If we do, free up
    878                          * the current structure and the structures already
    879                          * allocated, then error out with ENAMETOOLONG.
    880                          */
    881                         free(p);
    882                         fts_lfree(head);
    883                         (void)closedir(dirp);
    884                         cur->fts_info = FTS_ERR;
    885                         SET(FTS_STOP);
    886                         errno = ENAMETOOLONG;
    887                         return (NULL);
    888                 }
     789                p->fts_pathlen = len + dlen;
     790                p->fts_parent = sp->fts_cur;
    889791                p->fts_level = level;
    890                 p->fts_parent = sp->fts_cur;
    891                 p->fts_pathlen = len + dnamlen;
    892792
    893793#ifdef FTS_WHITEOUT
     
    905805                } else if (nlinks == 0
    906806#ifdef DT_DIR
    907                     || (nostat &&
     807                    || (nostat && 
    908808                    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
    909809#endif
     
    916816                        if (ISSET(FTS_NOCHDIR)) {
    917817                                p->fts_accpath = p->fts_path;
    918                                 memmove(cp, p->fts_name, p->fts_namelen + 1);
     818                                memmove(cp, p->fts_name,
     819                                        (size_t)(p->fts_namelen + 1));
    919820                        } else
    920821                                p->fts_accpath = p->fts_name;
     
    938839                ++nitems;
    939840        }
    940         if (dirp)
    941                 (void)closedir(dirp);
    942 
    943         /*
    944          * If realloc() changed the address of the path, adjust the
    945          * addresses for the rest of the tree and the dir list.
    946          */
    947         if (doadjust)
     841        (void)closedir(dirp);
     842
     843        /*
     844         * If had to realloc the path, adjust the addresses for the rest
     845         * of the tree.
     846         */
     847        if (adjust)
    948848                fts_padjust(sp, head);
    949849
     
    953853         */
    954854        if (ISSET(FTS_NOCHDIR)) {
    955                 if (len == sp->fts_pathlen || nitems == 0)
     855                if (cp - 1 > sp->fts_path)
    956856                        --cp;
    957857                *cp = '\0';
     
    967867        if (descend && (type == BCHILD || !nitems) &&
    968868            (cur->fts_level == FTS_ROOTLEVEL ?
    969 #ifdef HAVE_FCHDIR
    970869            FCHDIR(sp, sp->fts_rfd) :
    971 #else
    972             FCHDIR(sp, sp->fts_rdir) :
    973 #endif
    974870            fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
    975871                cur->fts_info = FTS_ERR;
     
    1000896        dev_t dev;
    1001897        ino_t ino;
    1002         struct stat *sbp, sb;
     898        struct STAT *sbp, sb;
    1003899        int saved_errno;
     900
     901        _DIAGASSERT(sp != NULL);
     902        _DIAGASSERT(p != NULL);
    1004903
    1005904        /* If user needs stat info, stat buffer already allocated. */
     
    1007906
    1008907#ifdef FTS_WHITEOUT
    1009         /* Check for whiteout. */
     908        /* check for whiteout */
    1010909        if (p->fts_flags & FTS_ISW) {
    1011910                if (sbp != &sb) {
    1012                         memset(sbp, '\0', sizeof(*sbp));
     911                        memset(sbp, '\0', sizeof (*sbp));
    1013912                        sbp->st_mode = S_IFWHT;
    1014913                }
     
    1028927                                errno = 0;
    1029928                                return (FTS_SLNONE);
    1030                         }
     929                        } 
    1031930                        p->fts_errno = saved_errno;
    1032931                        goto err;
     
    1034933        } else if (lstat(p->fts_accpath, sbp)) {
    1035934                p->fts_errno = errno;
    1036 err:            memset(sbp, 0, sizeof(struct stat));
     935err:            memset(sbp, 0, sizeof(struct STAT));
    1037936                return (FTS_NS);
    1038937        }
     
    1074973}
    1075974
    1076 /*
    1077  * The comparison function takes pointers to pointers to FTSENT structures.
    1078  * Qsort wants a comparison function that takes pointers to void.
    1079  * (Both with appropriate levels of const-poisoning, of course!)
    1080  * Use a trampoline function to deal with the difference.
    1081  */
    1082 static int
    1083 fts_compar(const void *a, const void *b)
    1084 {
    1085         FTS *parent;
    1086 
    1087         parent = (*(const FTSENT * const *)a)->fts_fts;
    1088         return (*parent->fts_compar)(a, b);
    1089 }
    1090 
    1091975static FTSENT *
    1092976fts_sort(sp, head, nitems)
    1093977        FTS *sp;
    1094978        FTSENT *head;
    1095         int nitems;
     979        size_t nitems;
    1096980{
    1097981        FTSENT **ap, *p;
     982
     983        _DIAGASSERT(sp != NULL);
     984        _DIAGASSERT(head != NULL);
    1098985
    1099986        /*
     
    1105992         */
    1106993        if (nitems > sp->fts_nitems) {
     994                FTSENT **new;
     995
     996                new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40));
     997                if (new == 0)
     998                        return (head);
     999                sp->fts_array = new;
    11071000                sp->fts_nitems = nitems + 40;
    1108                 if ((sp->fts_array = reallocf(sp->fts_array,
    1109                     sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
    1110                         sp->fts_nitems = 0;
    1111                         return (head);
    1112                 }
    11131001        }
    11141002        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
    11151003                *ap++ = p;
    1116         qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
     1004        qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *),
     1005                (int (*) __P((const void *, const void *)))sp->fts_compar);
    11171006        for (head = *(ap = sp->fts_array); --nitems; ++ap)
    11181007                ap[0]->fts_link = ap[1];
     
    11241013fts_alloc(sp, name, namelen)
    11251014        FTS *sp;
    1126         char *name;
    1127         int namelen;
     1015        const char *name;
     1016        size_t namelen;
    11281017{
    11291018        FTSENT *p;
    11301019        size_t len;
    11311020
    1132         struct ftsent_withstat {
    1133                 FTSENT  ent;
    1134                 struct  stat statbuf;
    1135         };
    1136 
     1021        _DIAGASSERT(sp != NULL);
     1022        _DIAGASSERT(name != NULL);
     1023
     1024#if defined(ALIGNBYTES) && defined(ALIGN)
    11371025        /*
    11381026         * The file name is a variable length array and no stat structure is
    11391027         * necessary if the user has set the nostat bit.  Allocate the FTSENT
    11401028         * structure, the file name and the stat structure in one chunk, but
    1141          * be careful that the stat structure is reasonably aligned.
    1142          */
    1143         if (ISSET(FTS_NOSTAT))
    1144                 len = sizeof(FTSENT) + namelen + 1;
    1145         else
    1146                 len = sizeof(struct ftsent_withstat) + namelen + 1;
    1147 
     1029         * be careful that the stat structure is reasonably aligned.  Since the
     1030         * fts_name field is declared to be of size 1, the fts_name pointer is
     1031         * namelen + 2 before the first possible address of the stat structure.
     1032         */
     1033        len = sizeof(FTSENT) + namelen;
     1034        if (!ISSET(FTS_NOSTAT))
     1035                len += sizeof(struct STAT) + ALIGNBYTES;
    11481036        if ((p = malloc(len)) == NULL)
    11491037                return (NULL);
    11501038
    1151         if (ISSET(FTS_NOSTAT)) {
    1152                 p->fts_name = (char *)(p + 1);
    1153                 p->fts_statp = NULL;
    1154         } else {
    1155                 p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
    1156                 p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
    1157         }
    1158 
    1159         /* Copy the name and guarantee NUL termination. */
    1160         memcpy(p->fts_name, name, namelen);
    1161         p->fts_name[namelen] = '\0';
     1039        if (!ISSET(FTS_NOSTAT))
     1040                p->fts_statp =
     1041                    (struct STAT *)ALIGN((u_long)(p->fts_name + namelen + 2));
     1042#else
     1043        if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL)
     1044                return (NULL);
     1045
     1046        if (!ISSET(FTS_NOSTAT))
     1047                if ((p->fts_statp = malloc(sizeof(struct STAT))) == NULL) {
     1048                        free(p);
     1049                        return (NULL);
     1050                }
     1051#endif
     1052
     1053        /* Copy the name plus the trailing NULL. */
     1054        memmove(p->fts_name, name, namelen + 1);
     1055
    11621056        p->fts_namelen = namelen;
    11631057        p->fts_path = sp->fts_path;
     
    11671061        p->fts_number = 0;
    11681062        p->fts_pointer = NULL;
    1169         p->fts_fts = sp;
    11701063        return (p);
    11711064}
     
    11771070        FTSENT *p;
    11781071
     1072        /* XXX: head may be NULL ? */
     1073
    11791074        /* Free a linked list of structures. */
    1180         while ((p = head)) {
     1075        while ((p = head) != NULL) {
    11811076                head = head->fts_link;
     1077
     1078#if !defined(ALIGNBYTES) || !defined(ALIGN)
     1079                if (p->fts_statp)
     1080                        free(p->fts_statp);
     1081#endif
    11821082                free(p);
    11831083        }
     1084}
     1085
     1086static size_t
     1087fts_pow2(x)
     1088        size_t x;
     1089{
     1090
     1091        x--;
     1092        x |= x>>1;
     1093        x |= x>>2;
     1094        x |= x>>4;
     1095        x |= x>>8;
     1096        x |= x>>16;
     1097#if LONG_BIT > 32
     1098        x |= x>>32;
     1099#endif
     1100#if LONG_BIT > 64
     1101        x |= x>>64;
     1102#endif
     1103        x++;
     1104        return (x);
    11841105}
    11851106
     
    11871108 * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
    11881109 * Most systems will allow creation of paths much longer than MAXPATHLEN, even
    1189  * though the kernel won't resolve them.  Add the size (not just what's needed)
    1190  * plus 256 bytes so don't realloc the path 2 bytes at a time.
     1110 * though the kernel won't resolve them.  Round up the new size to a power of 2,
     1111 * so we don't realloc the path 2 bytes at a time.
    11911112 */
    11921113static int
    1193 fts_palloc(sp, more)
     1114fts_palloc(sp, size)
    11941115        FTS *sp;
    1195         size_t more;
    1196 {
    1197 
    1198         sp->fts_pathlen += more + 256;
    1199         /*
    1200          * Check for possible wraparound.  In an FTS, fts_pathlen is
    1201          * a signed int but in an FTSENT it is an unsigned short.
    1202          * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
    1203          */
    1204         if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
    1205                 if (sp->fts_path)
    1206                         free(sp->fts_path);
    1207                 sp->fts_path = NULL;
    1208                 errno = ENAMETOOLONG;
     1116        size_t size;
     1117{
     1118        char *new;
     1119
     1120        _DIAGASSERT(sp != NULL);
     1121
     1122#if 1
     1123        /* Protect against fts_pathlen overflow. */
     1124        if (size > USHRT_MAX + 1) {
     1125                errno = ENOMEM;
    12091126                return (1);
    12101127        }
    1211         sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
    1212         return (sp->fts_path == NULL);
     1128#endif
     1129        size = fts_pow2(size);
     1130        new = realloc(sp->fts_path, size);
     1131        if (new == 0)
     1132                return (1);
     1133        sp->fts_path = new;
     1134        sp->fts_pathlen = size;
     1135        return (0);
    12131136}
    12141137
     
    12231146{
    12241147        FTSENT *p;
    1225         char *addr = sp->fts_path;
     1148        char *addr;
     1149
     1150        _DIAGASSERT(sp != NULL);
    12261151
    12271152#define ADJUST(p) do {                                                  \
    1228         if ((p)->fts_accpath != (p)->fts_name) {                        \
     1153        if ((p)->fts_accpath != (p)->fts_name)                          \
    12291154                (p)->fts_accpath =                                      \
    1230                     (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
    1231         }                                                               \
     1155                    addr + ((p)->fts_accpath - (p)->fts_path);          \
    12321156        (p)->fts_path = addr;                                           \
    1233 } while (0)
     1157} while (/*CONSTCOND*/0)
     1158
     1159        addr = sp->fts_path;
     1160
    12341161        /* Adjust the current set of children. */
    12351162        for (p = sp->fts_child; p; p = p->fts_link)
     
    12481175{
    12491176        size_t len, max;
     1177
     1178        _DIAGASSERT(argv != NULL);
    12501179
    12511180        for (max = 0; *argv; ++argv)
     
    12621191static int
    12631192fts_safe_changedir(sp, p, fd, path)
    1264         FTS *sp;
    1265         FTSENT *p;
     1193        const FTS *sp;
     1194        const FTSENT *p;
    12661195        int fd;
    1267         char *path;
    1268 {
    1269         int ret, oerrno, newfd;
    1270         struct stat sb;
    1271 
    1272         newfd = fd;
     1196        const char *path;
     1197{
     1198        int oldfd = fd, ret = -1;
     1199        struct STAT sb;
     1200
    12731201        if (ISSET(FTS_NOCHDIR))
    1274                 return (0);
    1275 #ifdef HAVE_FCHDIR
    1276         if (fd < 0 && (newfd = _open(path, O_RDONLY, 0)) < 0)
    1277                 return (-1);
    1278         if (_fstat(newfd, &sb)) {
    1279 #else
    1280         (void)newfd;
    1281         if (stat(path, &sb)) {
    1282 #endif
    1283                 ret = -1;
     1202                return 0;
     1203
     1204        if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1)
     1205                return -1;
     1206
     1207        if (fstat(fd, &sb) == -1)
    12841208                goto bail;
    1285         }
    1286         if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
    1287                 errno = ENOENT;         /* disinformation */
    1288                 ret = -1;
     1209
     1210        if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) {
     1211                errno = ENOENT;
    12891212                goto bail;
    12901213        }
    1291 #ifdef HAVE_FCHDIR
    1292         ret = fchdir(newfd);
    1293 #else
    1294         ret = chdir(path);
    1295 #endif
     1214
     1215        ret = fchdir(fd);
     1216
    12961217bail:
    1297 #ifdef HAVE_FCHDIR
    1298         oerrno = errno;
    1299         if (fd < 0)
    1300                 (void)_close(newfd);
    1301         errno = oerrno;
    1302 #else
    1303         (void)oerrno;
    1304 #endif
    1305         return (ret);
    1306 }
    1307 
    1308 /*
    1309  * Check if the filesystem for "ent" has UFS-style links.
    1310  */
    1311 static int
    1312 fts_ufslinks(FTS *sp, const FTSENT *ent)
    1313 {
    1314         struct _fts_private *priv;
    1315         const char **cpp;
    1316 
    1317         priv = (struct _fts_private *)sp;
    1318 #if defined(__EMX__) || defined(_MSC_VER)
    1319         /* we don't have reliable links */
    1320         priv->ftsp_linksreliable = 0;
    1321         (void)cpp;
    1322 #else
    1323         /*
    1324          * If this node's device is different from the previous, grab
    1325          * the filesystem information, and decide on the reliability
    1326          * of the link information from this filesystem for stat(2)
    1327          * avoidance.
    1328          */
    1329         if (priv->ftsp_dev != ent->fts_dev) {
    1330                 if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
    1331                         priv->ftsp_dev = ent->fts_dev;
    1332                         priv->ftsp_linksreliable = 0;
    1333                         for (cpp = ufslike_filesystems; *cpp; cpp++) {
    1334                                 if (strcmp(priv->ftsp_statfs.f_fstypename,
    1335                                     *cpp) == 0) {
    1336                                         priv->ftsp_linksreliable = 1;
    1337                                         break;
    1338                                 }
    1339                         }
    1340                 } else {
    1341                         priv->ftsp_linksreliable = 0;
    1342                 }
    1343         }
    1344 #endif
    1345         return (priv->ftsp_linksreliable);
    1346 }
    1347 
     1218        if (oldfd < 0) {
     1219                int save_errno = errno;
     1220                (void)close(fd);
     1221                errno = save_errno;
     1222        }
     1223        return ret;
     1224}
Note: See TracChangeset for help on using the changeset viewer.