Ticket #9337: ftw_fts.patch

File ftw_fts.patch, 55.9 KB (added by landonf, 11 years ago)

ftw(3), nftw(3), and fts(3) implementation

  • new file headers/posix/fts.h

    From fa09e0549812347c591e09ed73976c16e3300627 Mon Sep 17 00:00:00 2001
    From: Landon Fuller <landonf@bikemonkey.org>
    Date: Sat, 5 Jan 2013 17:19:51 -0500
    Subject: [PATCH 1/2] Drop in unmodified fts/ftw implementations from FreeBSD
     HEAD (r245067).
    
    ---
     headers/posix/fts.h              |  134 +++++
     headers/posix/ftw.h              |   62 ++
     src/system/libroot/posix/Jamfile |    3 +
     src/system/libroot/posix/fts.c   | 1174 ++++++++++++++++++++++++++++++++++++++
     src/system/libroot/posix/ftw.c   |   91 +++
     src/system/libroot/posix/nftw.c  |  109 ++++
     6 files changed, 1573 insertions(+)
     create mode 100644 headers/posix/fts.h
     create mode 100644 headers/posix/ftw.h
     create mode 100644 src/system/libroot/posix/fts.c
     create mode 100644 src/system/libroot/posix/ftw.c
     create mode 100644 src/system/libroot/posix/nftw.c
    
    diff --git a/headers/posix/fts.h b/headers/posix/fts.h
    new file mode 100644
    index 0000000..a679ea6
    - +  
     1/*
     2 * Copyright (c) 1989, 1993
     3 *  The Regents of the University of California.  All rights reserved.
     4 *
     5 * Redistribution and use in source and binary forms, with or without
     6 * modification, are permitted provided that the following conditions
     7 * are met:
     8 * 1. Redistributions of source code must retain the above copyright
     9 *    notice, this list of conditions and the following disclaimer.
     10 * 2. Redistributions in binary form must reproduce the above copyright
     11 *    notice, this list of conditions and the following disclaimer in the
     12 *    documentation and/or other materials provided with the distribution.
     13 * 3. Neither the name of the University nor the names of its contributors
     14 *    may be used to endorse or promote products derived from this software
     15 *    without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27 * SUCH DAMAGE.
     28 *
     29 *  @(#)fts.h   8.3 (Berkeley) 8/14/94
     30 * $FreeBSD$
     31 */
     32
     33#ifndef _FTS_H_
     34#define _FTS_H_
     35
     36typedef struct {
     37    struct _ftsent *fts_cur;    /* current node */
     38    struct _ftsent *fts_child;  /* linked list of children */
     39    struct _ftsent **fts_array; /* sort array */
     40    dev_t fts_dev;          /* starting device # */
     41    char *fts_path;         /* path for this descent */
     42    int fts_rfd;            /* fd for root */
     43    size_t fts_pathlen;     /* sizeof(path) */
     44    size_t fts_nitems;      /* elements in the sort array */
     45    int (*fts_compar)       /* compare function */
     46        (const struct _ftsent * const *, const struct _ftsent * const *);
     47
     48#define FTS_COMFOLLOW   0x001       /* follow command line symlinks */
     49#define FTS_LOGICAL 0x002       /* logical walk */
     50#define FTS_NOCHDIR 0x004       /* don't change directories */
     51#define FTS_NOSTAT  0x008       /* don't get stat info */
     52#define FTS_PHYSICAL    0x010       /* physical walk */
     53#define FTS_SEEDOT  0x020       /* return dot and dot-dot */
     54#define FTS_XDEV    0x040       /* don't cross devices */
     55#define FTS_WHITEOUT    0x080       /* return whiteout information */
     56#define FTS_OPTIONMASK  0x0ff       /* valid user option mask */
     57
     58#define FTS_NAMEONLY    0x100       /* (private) child names only */
     59#define FTS_STOP    0x200       /* (private) unrecoverable error */
     60    int fts_options;        /* fts_open options, global flags */
     61    void *fts_clientptr;        /* thunk for sort function */
     62} FTS;
     63
     64typedef struct _ftsent {
     65    struct _ftsent *fts_cycle;  /* cycle node */
     66    struct _ftsent *fts_parent; /* parent directory */
     67    struct _ftsent *fts_link;   /* next file in directory */
     68    long long fts_number;       /* local numeric value */
     69#define fts_bignum  fts_number  /* XXX non-std, should go away */
     70    void *fts_pointer;      /* local address value */
     71    char *fts_accpath;      /* access path */
     72    char *fts_path;         /* root path */
     73    int fts_errno;          /* errno for this node */
     74    int fts_symfd;          /* fd for symlink */
     75    size_t fts_pathlen;     /* strlen(fts_path) */
     76    size_t fts_namelen;     /* strlen(fts_name) */
     77
     78    ino_t fts_ino;          /* inode */
     79    dev_t fts_dev;          /* device */
     80    nlink_t fts_nlink;      /* link count */
     81
     82#define FTS_ROOTPARENTLEVEL -1
     83#define FTS_ROOTLEVEL        0
     84    long fts_level;         /* depth (-1 to N) */
     85
     86#define FTS_D        1      /* preorder directory */
     87#define FTS_DC       2      /* directory that causes cycles */
     88#define FTS_DEFAULT  3      /* none of the above */
     89#define FTS_DNR      4      /* unreadable directory */
     90#define FTS_DOT      5      /* dot or dot-dot */
     91#define FTS_DP       6      /* postorder directory */
     92#define FTS_ERR      7      /* error; errno is set */
     93#define FTS_F        8      /* regular file */
     94#define FTS_INIT     9      /* initialized only */
     95#define FTS_NS      10      /* stat(2) failed */
     96#define FTS_NSOK    11      /* no stat(2) requested */
     97#define FTS_SL      12      /* symbolic link */
     98#define FTS_SLNONE  13      /* symbolic link without target */
     99#define FTS_W       14      /* whiteout object */
     100    int fts_info;           /* user status for FTSENT structure */
     101
     102#define FTS_DONTCHDIR    0x01       /* don't chdir .. to the parent */
     103#define FTS_SYMFOLLOW    0x02       /* followed a symlink to get here */
     104#define FTS_ISW      0x04       /* this is a whiteout object */
     105    unsigned fts_flags;     /* private flags for FTSENT structure */
     106
     107#define FTS_AGAIN    1      /* read node again */
     108#define FTS_FOLLOW   2      /* follow symbolic link */
     109#define FTS_NOINSTR  3      /* no instructions */
     110#define FTS_SKIP     4      /* discard node */
     111    int fts_instr;          /* fts_set() instructions */
     112
     113    struct stat *fts_statp;     /* stat(2) information */
     114    char *fts_name;         /* file name */
     115    FTS *fts_fts;           /* back pointer to main FTS */
     116} FTSENT;
     117
     118#include <sys/cdefs.h>
     119
     120__BEGIN_DECLS
     121FTSENT  *fts_children(FTS *, int);
     122int  fts_close(FTS *);
     123void    *fts_get_clientptr(FTS *);
     124#define  fts_get_clientptr(fts) ((fts)->fts_clientptr)
     125FTS *fts_get_stream(FTSENT *);
     126#define  fts_get_stream(ftsent) ((ftsent)->fts_fts)
     127FTS *fts_open(char * const *, int,
     128        int (*)(const FTSENT * const *, const FTSENT * const *));
     129FTSENT  *fts_read(FTS *);
     130int  fts_set(FTS *, FTSENT *, int);
     131void     fts_set_clientptr(FTS *, void *);
     132__END_DECLS
     133
     134#endif /* !_FTS_H_ */
  • new file headers/posix/ftw.h

    diff --git a/headers/posix/ftw.h b/headers/posix/ftw.h
    new file mode 100644
    index 0000000..f01fda2
    - +  
     1/*  $OpenBSD: ftw.h,v 1.1 2003/07/21 21:13:18 millert Exp $ */
     2
     3/*
     4 * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
     5 *
     6 * Permission to use, copy, modify, and distribute this software for any
     7 * purpose with or without fee is hereby granted, provided that the above
     8 * copyright notice and this permission notice appear in all copies.
     9 *
     10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17 *
     18 * Sponsored in part by the Defense Advanced Research Projects
     19 * Agency (DARPA) and Air Force Research Laboratory, Air Force
     20 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
     21 *
     22 * $FreeBSD$
     23 */
     24
     25#ifndef _FTW_H
     26#define _FTW_H
     27
     28#include <sys/types.h>
     29#include <sys/stat.h>
     30
     31/*
     32 * Valid flags for the 3rd argument to the function that is passed as the
     33 * second argument to ftw(3) and nftw(3).  Say it three times fast!
     34 */
     35#define FTW_F       0   /* File.  */
     36#define FTW_D       1   /* Directory.  */
     37#define FTW_DNR     2   /* Directory without read permission.  */
     38#define FTW_DP      3   /* Directory with subdirectories visited.  */
     39#define FTW_NS      4   /* Unknown type; stat() failed.  */
     40#define FTW_SL      5   /* Symbolic link.  */
     41#define FTW_SLN     6   /* Sym link that names a nonexistent file.  */
     42
     43/*
     44 * Flags for use as the 4th argument to nftw(3).  These may be ORed together.
     45 */
     46#define FTW_PHYS    0x01    /* Physical walk, don't follow sym links.  */
     47#define FTW_MOUNT   0x02    /* The walk does not cross a mount point.  */
     48#define FTW_DEPTH   0x04    /* Subdirs visited before the dir itself. */
     49#define FTW_CHDIR   0x08    /* Change to a directory before reading it. */
     50
     51struct FTW {
     52    int base;
     53    int level;
     54};
     55
     56__BEGIN_DECLS
     57int ftw(const char *, int (*)(const char *, const struct stat *, int), int);
     58int nftw(const char *, int (*)(const char *, const struct stat *, int,
     59        struct FTW *), int, int);
     60__END_DECLS
     61
     62#endif  /* !_FTW_H */
  • src/system/libroot/posix/Jamfile

    diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile
    index b796810..b6b720a 100644
    a b MergeObject posix_main.o :  
    1818    errno.c
    1919    fcntl.cpp
    2020    fnmatch.c
     21    fts.c
     22    ftw.c
    2123    glob.c
    2224    inttypes.c
    2325    libgen.cpp
     26    nftw.c
    2427    poll.c
    2528    $(PWD_BACKEND)
    2629    scheduler.cpp
  • new file src/system/libroot/posix/fts.c

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

    diff --git a/src/system/libroot/posix/ftw.c b/src/system/libroot/posix/ftw.c
    new file mode 100644
    index 0000000..253a295
    - +  
     1/*  $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $   */
     2
     3/*
     4 * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
     5 *
     6 * Permission to use, copy, modify, and distribute this software for any
     7 * purpose with or without fee is hereby granted, provided that the above
     8 * copyright notice and this permission notice appear in all copies.
     9 *
     10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17 *
     18 * Sponsored in part by the Defense Advanced Research Projects
     19 * Agency (DARPA) and Air Force Research Laboratory, Air Force
     20 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
     21 */
     22
     23#include <sys/cdefs.h>
     24__FBSDID("$FreeBSD$");
     25
     26#include <sys/types.h>
     27#include <sys/stat.h>
     28#include <errno.h>
     29#include <fts.h>
     30#include <ftw.h>
     31
     32int
     33ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
     34    int nfds)
     35{
     36    char * const paths[2] = { (char *)path, NULL };
     37    FTSENT *cur;
     38    FTS *ftsp;
     39    int error = 0, fnflag, sverrno;
     40
     41    /* XXX - nfds is currently unused */
     42    if (nfds < 1) {
     43        errno = EINVAL;
     44        return (-1);
     45    }
     46
     47    ftsp = fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
     48    if (ftsp == NULL)
     49        return (-1);
     50    while ((cur = fts_read(ftsp)) != NULL) {
     51        switch (cur->fts_info) {
     52        case FTS_D:
     53            fnflag = FTW_D;
     54            break;
     55        case FTS_DNR:
     56            fnflag = FTW_DNR;
     57            break;
     58        case FTS_DP:
     59            /* we only visit in preorder */
     60            continue;
     61        case FTS_F:
     62        case FTS_DEFAULT:
     63            fnflag = FTW_F;
     64            break;
     65        case FTS_NS:
     66        case FTS_NSOK:
     67        case FTS_SLNONE:
     68            fnflag = FTW_NS;
     69            break;
     70        case FTS_SL:
     71            fnflag = FTW_SL;
     72            break;
     73        case FTS_DC:
     74            errno = ELOOP;
     75            /* FALLTHROUGH */
     76        default:
     77            error = -1;
     78            goto done;
     79        }
     80        error = fn(cur->fts_path, cur->fts_statp, fnflag);
     81        if (error != 0)
     82            break;
     83    }
     84done:
     85    sverrno = errno;
     86    if (fts_close(ftsp) != 0 && error == 0)
     87        error = -1;
     88    else
     89        errno = sverrno;
     90    return (error);
     91}
  • new file src/system/libroot/posix/nftw.c

    diff --git a/src/system/libroot/posix/nftw.c b/src/system/libroot/posix/nftw.c
    new file mode 100644
    index 0000000..a338e5a
    - +  
     1/*  $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $    */
     2
     3/*
     4 * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
     5 *
     6 * Permission to use, copy, modify, and distribute this software for any
     7 * purpose with or without fee is hereby granted, provided that the above
     8 * copyright notice and this permission notice appear in all copies.
     9 *
     10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17 *
     18 * Sponsored in part by the Defense Advanced Research Projects
     19 * Agency (DARPA) and Air Force Research Laboratory, Air Force
     20 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
     21 */
     22
     23#include <sys/cdefs.h>
     24__FBSDID("$FreeBSD$");
     25
     26#include <sys/types.h>
     27#include <sys/stat.h>
     28#include <errno.h>
     29#include <fts.h>
     30#include <ftw.h>
     31
     32int
     33nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
     34     struct FTW *), int nfds, int ftwflags)
     35{
     36    char * const paths[2] = { (char *)path, NULL };
     37    struct FTW ftw;
     38    FTSENT *cur;
     39    FTS *ftsp;
     40    int error = 0, ftsflags, fnflag, postorder, sverrno;
     41
     42    /* XXX - nfds is currently unused */
     43    if (nfds < 1) {
     44        errno = EINVAL;
     45        return (-1);
     46    }
     47
     48    ftsflags = FTS_COMFOLLOW;
     49    if (!(ftwflags & FTW_CHDIR))
     50        ftsflags |= FTS_NOCHDIR;
     51    if (ftwflags & FTW_MOUNT)
     52        ftsflags |= FTS_XDEV;
     53    if (ftwflags & FTW_PHYS)
     54        ftsflags |= FTS_PHYSICAL;
     55    else
     56        ftsflags |= FTS_LOGICAL;
     57    postorder = (ftwflags & FTW_DEPTH) != 0;
     58    ftsp = fts_open(paths, ftsflags, NULL);
     59    if (ftsp == NULL)
     60        return (-1);
     61    while ((cur = fts_read(ftsp)) != NULL) {
     62        switch (cur->fts_info) {
     63        case FTS_D:
     64            if (postorder)
     65                continue;
     66            fnflag = FTW_D;
     67            break;
     68        case FTS_DC:
     69            continue;
     70        case FTS_DNR:
     71            fnflag = FTW_DNR;
     72            break;
     73        case FTS_DP:
     74            if (!postorder)
     75                continue;
     76            fnflag = FTW_DP;
     77            break;
     78        case FTS_F:
     79        case FTS_DEFAULT:
     80            fnflag = FTW_F;
     81            break;
     82        case FTS_NS:
     83        case FTS_NSOK:
     84            fnflag = FTW_NS;
     85            break;
     86        case FTS_SL:
     87            fnflag = FTW_SL;
     88            break;
     89        case FTS_SLNONE:
     90            fnflag = FTW_SLN;
     91            break;
     92        default:
     93            error = -1;
     94            goto done;
     95        }
     96        ftw.base = cur->fts_pathlen - cur->fts_namelen;
     97        ftw.level = cur->fts_level;
     98        error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
     99        if (error != 0)
     100            break;
     101    }
     102done:
     103    sverrno = errno;
     104    if (fts_close(ftsp) != 0 && error == 0)
     105        error = -1;
     106    else
     107        errno = sverrno;
     108    return (error);
     109}
  • headers/posix/fts.h

    -- 
    1.8.0.3
    
    
    From b6ed1e1835c2099f9d3a6f9fba3bf8964e059282 Mon Sep 17 00:00:00 2001
    From: Landon Fuller <landonf@bikemonkey.org>
    Date: Sat, 5 Jan 2013 21:13:39 -0500
    Subject: [PATCH 2/2] Add Haiku support.
    
    This replaces the use of a few BSD-specific functions, as well
    as the direct references to _open/_close et-al.
    
    BFS doesn't support the FTS_NOSTAT directory link count optimization,
    and no statfs() function is available, so we simply turn that off.
    ---
     headers/posix/fts.h             |  3 +-
     headers/posix/ftw.h             |  1 +
     src/system/libroot/posix/fts.c  | 73 ++++++++++++++++++++++++++++++-----------
     src/system/libroot/posix/ftw.c  |  2 +-
     src/system/libroot/posix/nftw.c |  2 +-
     5 files changed, 59 insertions(+), 22 deletions(-)
    
    diff --git a/headers/posix/fts.h b/headers/posix/fts.h
    index a679ea6..53e900d 100644
    a b  
    3333#ifndef _FTS_H_
    3434#define _FTS_H_
    3535
     36#include <sys/cdefs.h>
     37
    3638typedef struct {
    3739    struct _ftsent *fts_cur;    /* current node */
    3840    struct _ftsent *fts_child;  /* linked list of children */
    typedef struct {  
    5254#define FTS_PHYSICAL    0x010       /* physical walk */
    5355#define FTS_SEEDOT  0x020       /* return dot and dot-dot */
    5456#define FTS_XDEV    0x040       /* don't cross devices */
    55 #define FTS_WHITEOUT    0x080       /* return whiteout information */
    5657#define FTS_OPTIONMASK  0x0ff       /* valid user option mask */
    5758
    5859#define FTS_NAMEONLY    0x100       /* (private) child names only */
  • headers/posix/ftw.h

    diff --git a/headers/posix/ftw.h b/headers/posix/ftw.h
    index f01fda2..a42f74d 100644
    a b  
    2525#ifndef _FTW_H
    2626#define _FTW_H
    2727
     28#include <sys/cdefs.h>
    2829#include <sys/types.h>
    2930#include <sys/stat.h>
    3031
  • src/system/libroot/posix/fts.c

    diff --git a/src/system/libroot/posix/fts.c b/src/system/libroot/posix/fts.c
    index 243320c..ce7ac95 100644
    a b static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";  
    3636#endif
    3737
    3838#include <sys/cdefs.h>
     39
     40#ifdef __HAIKU__
     41#include <sys/param.h>
     42#include <sys/stat.h>
     43
     44#include <dirent.h>
     45#include <errno.h>
     46#include <fcntl.h>
     47#include <fts.h>
     48#include <stdlib.h>
     49#include <string.h>
     50#include <unistd.h>
     51#else
    3952__FBSDID("$FreeBSD$");
    4053
    4154#include "namespace.h"
    __FBSDID("$FreeBSD$");  
    5366#include "un-namespace.h"
    5467
    5568#include "gen-private.h"
     69#endif
    5670
    5771static FTSENT   *fts_alloc(FTS *, char *, size_t);
    5872static FTSENT   *fts_build(FTS *, int);
    static int fts_ufslinks(FTS *, const FTSENT *);  
    86100 */
    87101struct _fts_private {
    88102    FTS     ftsp_fts;
     103#ifndef __HAIKU__
    89104    struct statfs   ftsp_statfs;
     105#endif
    90106    dev_t       ftsp_dev;
    91107    int     ftsp_linksreliable;
    92108};
    93109
     110#ifndef __HAIKU__
    94111/*
    95112 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
    96113 * knows that a directory could not possibly have subdirectories.  This
    static const char *ufslike_filesystems[] = {  
    108125    "ext2fs",
    109126    0
    110127};
     128#endif /* !__HAIKU__ */
    111129
    112130FTS *
    113131fts_open(argv, options, compar)
    fts_open(argv, options, compar)  
    215233     * descriptor we run anyway, just more slowly.
    216234     */
    217235    if (!ISSET(FTS_NOCHDIR) &&
    218         (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
     236        (sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
    219237        SET(FTS_NOCHDIR);
    220238
    221239    return (sp);
    fts_close(FTS *sp)  
    281299    /* Return to original directory, save errno if necessary. */
    282300    if (!ISSET(FTS_NOCHDIR)) {
    283301        saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
    284         (void)_close(sp->fts_rfd);
     302        (void)close(sp->fts_rfd);
    285303
    286304        /* Set errno and return. */
    287305        if (saved_errno != 0) {
    fts_read(FTS *sp)  
    340358        (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
    341359        p->fts_info = fts_stat(sp, p, 1);
    342360        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    343             if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
     361            if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC,
    344362                0)) < 0) {
    345363                p->fts_errno = errno;
    346364                p->fts_info = FTS_ERR;
    fts_read(FTS *sp)  
    356374        if (instr == FTS_SKIP ||
    357375            (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
    358376            if (p->fts_flags & FTS_SYMFOLLOW)
    359                 (void)_close(p->fts_symfd);
     377                (void)close(p->fts_symfd);
    360378            if (sp->fts_child) {
    361379                fts_lfree(sp->fts_child);
    362380                sp->fts_child = NULL;
    next: tmp = p;  
    432450            p->fts_info = fts_stat(sp, p, 1);
    433451            if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    434452                if ((p->fts_symfd =
    435                     _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
     453                    open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
    436454                    p->fts_errno = errno;
    437455                    p->fts_info = FTS_ERR;
    438456                } else
    name: t = sp->fts_path + NAPPEND(p->fts_parent);  
    477495    } else if (p->fts_flags & FTS_SYMFOLLOW) {
    478496        if (FCHDIR(sp, p->fts_symfd)) {
    479497            saved_errno = errno;
    480             (void)_close(p->fts_symfd);
     498            (void)close(p->fts_symfd);
    481499            errno = saved_errno;
    482500            SET(FTS_STOP);
    483501            return (NULL);
    484502        }
    485         (void)_close(p->fts_symfd);
     503        (void)close(p->fts_symfd);
    486504    } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
    487505        fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
    488506        SET(FTS_STOP);
    fts_children(FTS *sp, int instr)  
    568586        ISSET(FTS_NOCHDIR))
    569587        return (sp->fts_child = fts_build(sp, instr));
    570588
    571     if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
     589    if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
    572590        return (NULL);
    573591    sp->fts_child = fts_build(sp, instr);
    574592    if (fchdir(fd)) {
    575         (void)_close(fd);
     593        (void)close(fd);
    576594        return (NULL);
    577595    }
    578     (void)_close(fd);
     596    (void)close(fd);
    579597    return (sp->fts_child);
    580598}
    581599
    fts_build(FTS *sp, int type)  
    630648    DIR *dirp;
    631649    void *oldaddr;
    632650    char *cp;
    633     int cderrno, descend, oflag, saved_errno, nostat, doadjust;
     651    int cderrno, descend, saved_errno, nostat, doadjust;
     652#ifdef FTS_WHITEOUT
     653    int oflag;
     654#endif
    634655    long level;
    635656    long nlinks;    /* has to be signed because -1 is a magic value */
    636657    size_t dnamlen, len, maxlen, nitems;
    fts_build(FTS *sp, int type)  
    700721     */
    701722    cderrno = 0;
    702723    if (nlinks || type == BREAD) {
    703         if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
     724        if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
    704725            if (nlinks && type == BREAD)
    705726                cur->fts_errno = errno;
    706727            cur->fts_flags |= FTS_DONTCHDIR;
    fts_build(FTS *sp, int type)  
    737758    /* Read the directory, attaching each entry to the `link' pointer. */
    738759    doadjust = 0;
    739760    for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
    740         dnamlen = dp->d_namlen;
     761        dnamlen = strlen(dp->d_name);
    741762        if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
    742763            continue;
    743764
    static FTSENT *  
    966987fts_sort(FTS *sp, FTSENT *head, size_t nitems)
    967988{
    968989    FTSENT **ap, *p;
     990    FTSENT **old_array;
    969991
    970992    /*
    971993     * Construct an array of pointers to the structures and call qsort(3).
    fts_sort(FTS *sp, FTSENT *head, size_t nitems)  
    976998     */
    977999    if (nitems > sp->fts_nitems) {
    9781000        sp->fts_nitems = nitems + 40;
    979         if ((sp->fts_array = reallocf(sp->fts_array,
     1001        old_array = sp->fts_array;
     1002        if ((sp->fts_array = realloc(old_array,
    9801003            sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
     1004            free(old_array);
    9811005            sp->fts_nitems = 0;
    9821006            return (head);
    9831007        }
    fts_lfree(FTSENT *head)  
    10591083static int
    10601084fts_palloc(FTS *sp, size_t more)
    10611085{
    1062 
     1086    char *old_path;
    10631087    sp->fts_pathlen += more + 256;
    1064     sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
     1088
     1089    old_path = sp->fts_path;
     1090    sp->fts_path = realloc(old_path, sp->fts_pathlen);
     1091    if (sp->fts_path == NULL)
     1092        free(old_path);
     1093
    10651094    return (sp->fts_path == NULL);
    10661095}
    10671096
    fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)  
    11191148    newfd = fd;
    11201149    if (ISSET(FTS_NOCHDIR))
    11211150        return (0);
    1122     if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
     1151    if (fd < 0 && (newfd = open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
    11231152        return (-1);
    1124     if (_fstat(newfd, &sb)) {
     1153    if (fstat(newfd, &sb)) {
    11251154        ret = -1;
    11261155        goto bail;
    11271156    }
    fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)  
    11341163bail:
    11351164    oerrno = errno;
    11361165    if (fd < 0)
    1137         (void)_close(newfd);
     1166        (void)close(newfd);
    11381167    errno = oerrno;
    11391168    return (ret);
    11401169}
    static int  
    11461175fts_ufslinks(FTS *sp, const FTSENT *ent)
    11471176{
    11481177    struct _fts_private *priv;
     1178#ifndef __HAIKU__
    11491179    const char **cpp;
     1180#endif
    11501181
    11511182    priv = (struct _fts_private *)sp;
    11521183    /*
    fts_ufslinks(FTS *sp, const FTSENT *ent)  
    11561187     * avoidance.
    11571188     */
    11581189    if (priv->ftsp_dev != ent->fts_dev) {
     1190#ifndef __HAIKU__
    11591191        if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
    11601192            priv->ftsp_dev = ent->fts_dev;
    11611193            priv->ftsp_linksreliable = 0;
    fts_ufslinks(FTS *sp, const FTSENT *ent)  
    11691201        } else {
    11701202            priv->ftsp_linksreliable = 0;
    11711203        }
     1204#else
     1205        priv->ftsp_linksreliable = 0;
     1206#endif
    11721207    }
    11731208    return (priv->ftsp_linksreliable);
    11741209}
  • src/system/libroot/posix/ftw.c

    diff --git a/src/system/libroot/posix/ftw.c b/src/system/libroot/posix/ftw.c
    index 253a295..67ff8c2 100644
    a b  
    2121 */
    2222
    2323#include <sys/cdefs.h>
    24 __FBSDID("$FreeBSD$");
     24// __FBSDID("$FreeBSD$");
    2525
    2626#include <sys/types.h>
    2727#include <sys/stat.h>
  • src/system/libroot/posix/nftw.c

    diff --git a/src/system/libroot/posix/nftw.c b/src/system/libroot/posix/nftw.c
    index a338e5a..88e8c09 100644
    a b  
    2121 */
    2222
    2323#include <sys/cdefs.h>
    24 __FBSDID("$FreeBSD$");
     24//__FBSDID("$FreeBSD$");
    2525
    2626#include <sys/types.h>
    2727#include <sys/stat.h>