Ignore:
Timestamp:
Nov 1, 2016, 7:26:35 PM (9 years ago)
Author:
bird
Message:

lib/nt: Got fts-nt halfways working, quite a few NT interface changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/nt/fts-nt.c

    r2982 r2985  
     1/* $Id: $ */
     2/** @file
     3 * Source for the NT port of BSD fts.c.
     4 *
     5 * @copyright   1990, 1993, 1994 The Regents of the University of California.  All rights reserved.
     6 * @copyright   NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
     7 * @licenses    BSD3
     8 *
     9 *
     10 * Some hints about how the code works.
     11 *
     12 * The input directories & files are entered into a pseudo root directory and
     13 * processed one after another, depth first.
     14 *
     15 * Directories are completely read into memory first and arranged as linked
     16 * list anchored on FTS::fts_cur.  fts_read does a pop-like operation on that
     17 * list, freeing the nodes after they've been completely processed.
     18 * Subdirectories are returned twice by fts_read, the first time when it
     19 * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP).
     20 *
     21 * In parallel to fts_read, there's the fts_children API that fetches the
     22 * directory content in a similar manner, but for the consumption of the API
     23 * caller rather than FTS itself.  The result hangs on FTS::fts_child so it can
     24 * be freed when the directory changes or used by fts_read when it is called
     25 * upon to enumerate the directory.
     26 *
     27 *
     28 * The NT port of the code does away with the directory changing in favor of
     29 * using directory relative opens (present in NT since for ever, just not
     30 * exposed thru Win32).  A new FTSENT member fts_dirfd has been added to make
     31 * this possible for API users too.
     32 *
     33 * Note! When using Win32 APIs with path input relative to the current
     34 *       directory, the internal DOS <-> NT path converter will expand it to a
     35 *       full path and subject it to the 260 char limit.
     36 *
     37 * The richer NT directory enumeration API allows us to do away with all the
     38 * stat() calls, and not have to do link counting and other interesting things
     39 * to try speed things up.  (You typical stat() implementation on windows is
     40 * actually a directory enum call with the name of the file as filter.)
     41 */
     42
    143/*-
    244 * Copyright (c) 1990, 1993, 1994
     
    3678#endif
    3779
    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>
     80//#include <sys/cdefs.h>
     81//__FBSDID("$FreeBSD$");
     82
     83//#include "namespace.h"
     84//#include <sys/param.h>
     85//#include <sys/mount.h>
     86//#include <sys/stat.h>
     87
     88//#include <dirent.h>
    4789#include <errno.h>
    48 #include <fcntl.h>
    49 #include <fts.h>
     90//#include <fcntl.h>
     91#include "fts-nt.h"
    5092#include <stdlib.h>
    5193#include <string.h>
    52 #include <unistd.h>
    53 #include "un-namespace.h"
    54 
    55 #include "gen-private.h"
     94//#include <unistd.h>
     95//#include "un-namespace.h"
     96//
     97//#include "gen-private.h"
     98#include <assert.h>
     99#include "nthlp.h"
     100#include "ntdir.h"
    56101
    57102static FTSENT   *fts_alloc(FTS *, char *, size_t);
     
    63108static int       fts_palloc(FTS *, size_t);
    64109static FTSENT   *fts_sort(FTS *, FTSENT *, size_t);
    65 static int       fts_stat(FTS *, FTSENT *, int, int);
     110static int       fts_stat(FTS *, FTSENT *, int, HANDLE);
     111static int   fts_process_stats(FTSENT *, BirdStat_T const *);
    66112static int       fts_safe_changedir(FTS *, FTSENT *, int, char *);
    67113static int       fts_ufslinks(FTS *, const FTSENT *);
     
    80126#define BREAD           3               /* fts_read */
    81127
     128/* NT needs these: */
     129#define MAXPATHLEN 260
     130#define MAX(a, b)  ( (a) >= (b) ? (a) : (b) )
     131
     132#define AT_SYMLINK_NOFOLLOW 1
     133#define fstatat(hDir, pszPath, pStat, fFlags) birdStatAt((hDir), (pszPath), (pStat), (fFlags) != 0)
     134#define FTS_NT_DUMMY_SYMFD_VALUE        ((HANDLE)~(intptr_t)(2)) /* current process */
     135#define fchdir(fd) todo_fchdir(fd)
     136extern int todo_fchdir(fts_fd_t fd);
     137
    82138/*
    83139 * Internal representation of an FTS, including extra implementation
     
    87143struct _fts_private {
    88144        FTS             ftsp_fts;
     145#if 0 /* Not needed on NT, see comment on fts_ufslinks */
    89146        struct statfs   ftsp_statfs;
    90147        dev_t           ftsp_dev;
    91148        int             ftsp_linksreliable;
     149#endif
    92150};
    93151
     152#if 0 /* Not needed on NT, see comment on fts_ufslinks */
    94153/*
    95154 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
     
    108167        0
    109168};
    110 
    111 FTS *
     169#endif
     170
     171FTS * FTSCALL
    112172fts_open(char * const *argv, int options,
    113173    int (*compar)(const FTSENT * const *, const FTSENT * const *))
     
    159219        /* Allocate/initialize root(s). */
    160220        for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
     221                /* NT: We need to do some small input transformations to make this and
     222                       the API user code happy.  1. Lone drive letters get a dot
     223                       appended so it won't matter if a slash is appended afterwards.
     224                           2. DOS slashes are converted to UNIX ones. */
     225                char *slash;
    161226                len = strlen(*argv);
    162 
    163                 p = fts_alloc(sp, *argv, len);
     227                if (len == 2 && argv[0][1] == ':') {
     228                        char tmp[4];
     229                        tmp[0] = argv[0][0];
     230                        tmp[1] = ':';
     231                        tmp[2] = '.';
     232                        tmp[3] = '\0';
     233                        p = fts_alloc(sp, tmp, 3);
     234                } else {
     235                        p = fts_alloc(sp, *argv, len);
     236                }
     237#if 1 /* bird */
     238                if (p != NULL) { /* likely */ } else { goto mem3; }
     239#endif
     240                slash = strchr(p->fts_name, '\\');
     241                while (slash != NULL) {
     242                        *slash++ = '/';
     243                        slash = strchr(p->fts_name, '\\');
     244                }
    164245                p->fts_level = FTS_ROOTLEVEL;
    165246                p->fts_parent = parent;
    166247                p->fts_accpath = p->fts_name;
    167                 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
     248                p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE);
    168249
    169250                /* Command-line "." and ".." are real directories. */
     
    201282        sp->fts_cur->fts_info = FTS_INIT;
    202283
    203         /*
    204          * If using chdir(2), grab a file descriptor pointing to dot to ensure
    205          * that we can get back here; this could be avoided for some paths,
    206          * but almost certainly not worth the effort.  Slashes, symbolic links,
    207          * and ".." are all fairly nasty problems.  Note, if we can't get the
    208          * descriptor we run anyway, just more slowly.
    209          */
    210         if (!ISSET(FTS_NOCHDIR) &&
    211             (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
    212                 SET(FTS_NOCHDIR);
    213 
    214284        return (sp);
    215285
     
    221291}
    222292
     293
    223294static void
    224295fts_load(FTS *sp, FTSENT *p)
     
    236307        len = p->fts_pathlen = p->fts_namelen;
    237308        memmove(sp->fts_path, p->fts_name, len + 1);
     309/** @todo check for ':' and '\\'? */
    238310        if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
    239311                len = strlen(++cp);
     
    245317}
    246318
    247 int
     319int FTSCALL
    248320fts_close(FTS *sp)
    249321{
    250322        FTSENT *freep, *p;
    251         int saved_errno;
     323        /*int saved_errno;*/
    252324
    253325        /*
     
    272344        free(sp->fts_path);
    273345
    274         /* Return to original directory, save errno if necessary. */
    275         if (!ISSET(FTS_NOCHDIR)) {
    276                 saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
    277                 (void)_close(sp->fts_rfd);
    278 
    279                 /* Set errno and return. */
    280                 if (saved_errno != 0) {
    281                         /* Free up the stream pointer. */
    282                         free(sp);
    283                         errno = saved_errno;
    284                         return (-1);
    285                 }
    286         }
    287 
    288346        /* Free up the stream pointer. */
    289347        free(sp);
     
    299357            ? p->fts_pathlen - 1 : p->fts_pathlen)
    300358
    301 FTSENT *
     359static void
     360fts_free_entry(FTSENT *tmp)
     361{
     362    if (tmp != NULL) {
     363                if (tmp->fts_dirfd != INVALID_HANDLE_VALUE) {
     364                        birdCloseFile(tmp->fts_dirfd);
     365                        tmp->fts_dirfd = INVALID_HANDLE_VALUE;
     366                }
     367                free(tmp);
     368    }
     369}
     370
     371FTSENT * FTSCALL
    302372fts_read(FTS *sp)
    303373{
     
    305375        int instr;
    306376        char *t;
    307         int saved_errno;
    308377
    309378        /* If finished or unrecoverable error, return NULL. */
     
    320389        /* Any type of file may be re-visited; re-stat and re-turn. */
    321390        if (instr == FTS_AGAIN) {
    322                 p->fts_info = fts_stat(sp, p, 0, -1);
     391                p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE);
    323392                return (p);
    324393        }
     
    329398         * keep a pointer to current location.  If unable to get that
    330399         * pointer, follow fails.
     400         *
     401         * NT: Since we don't change directory, we just set fts_symfd to a
     402         *     placeholder value handle value here in case a API client
     403         *     checks it. Ditto FTS_SYMFOLLOW.
    331404         */
    332405        if (instr == FTS_FOLLOW &&
    333406            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
    334                 p->fts_info = fts_stat(sp, p, 1, -1);
    335                 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    336                         if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
    337                             0)) < 0) {
    338                                 p->fts_errno = errno;
    339                                 p->fts_info = FTS_ERR;
    340                         } else
    341                                 p->fts_flags |= FTS_SYMFOLLOW;
     407                p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
     408                if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
     409                        p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
     410                        p->fts_flags |= FTS_SYMFOLLOW;
    342411                }
    343412                return (p);
     
    349418                if (instr == FTS_SKIP ||
    350419                    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
    351                         if (p->fts_flags & FTS_SYMFOLLOW)
    352                                 (void)_close(p->fts_symfd);
     420                        if (p->fts_flags & FTS_SYMFOLLOW) {
     421                                p->fts_symfd = INVALID_HANDLE_VALUE;
     422                        }
    353423                        if (sp->fts_child) {
    354424                                fts_lfree(sp->fts_child);
     
    405475                 */
    406476                if (p->fts_level == FTS_ROOTLEVEL) {
    407                         if (FCHDIR(sp, sp->fts_rfd)) {
     477                        /*NT: No fchdir: if (FCHDIR(sp, sp->fts_rfd)) {
    408478                                SET(FTS_STOP);
    409479                                return (NULL);
    410                         }
    411                         free(tmp);
     480                        } */
     481                        fts_free_entry(tmp);
    412482                        fts_load(sp, p);
    413483                        return (sp->fts_cur = p);
     
    420490                 */
    421491                if (p->fts_instr == FTS_SKIP) {
    422                         free(tmp);
     492                        fts_free_entry(tmp);
    423493                        goto next;
    424494                }
    425495                if (p->fts_instr == FTS_FOLLOW) {
    426                         p->fts_info = fts_stat(sp, p, 1, -1);
    427                         if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
    428                                 if ((p->fts_symfd =
    429                                     _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
    430                                         p->fts_errno = errno;
    431                                         p->fts_info = FTS_ERR;
    432                                 } else
    433                                         p->fts_flags |= FTS_SYMFOLLOW;
     496                        p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
     497                        /* NT: See above regarding fts_symfd. */
     498                        if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
     499                                p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
     500                                p->fts_flags |= FTS_SYMFOLLOW;
    434501                        }
    435502                        p->fts_instr = FTS_NOINSTR;
    436503                }
    437504
    438                 free(tmp);
     505                fts_free_entry(tmp);
    439506
    440507name:           t = sp->fts_path + NAPPEND(p->fts_parent);
     
    452519                 * can distinguish between error and EOF.
    453520                 */
    454                 free(tmp);
    455                 free(p);
     521                fts_free_entry(tmp);
     522                fts_free_entry(p);
    456523                errno = 0;
    457524                return (sp->fts_cur = NULL);
     
    465532         * a symlink, go back through the file descriptor.  Otherwise, cd up
    466533         * one directory.
    467          */
    468         if (p->fts_level == FTS_ROOTLEVEL) {
    469                 if (FCHDIR(sp, sp->fts_rfd)) {
    470                         SET(FTS_STOP);
    471                         return (NULL);
    472                 }
    473         } else if (p->fts_flags & FTS_SYMFOLLOW) {
    474                 if (FCHDIR(sp, p->fts_symfd)) {
    475                         saved_errno = errno;
    476                         (void)_close(p->fts_symfd);
    477                         errno = saved_errno;
    478                         SET(FTS_STOP);
    479                         return (NULL);
    480                 }
    481                 (void)_close(p->fts_symfd);
    482         } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
    483             fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
    484                 SET(FTS_STOP);
    485                 return (NULL);
    486         }
    487         free(tmp);
     534         *
     535         * NT: We're doing no fchdir, but we need to close the directory handle
     536         *     and clear fts_symfd now.
     537         */
     538        if (p->fts_flags & FTS_SYMFOLLOW) {
     539                p->fts_symfd = INVALID_HANDLE_VALUE;
     540        }
     541    if (p->fts_dirfd != INVALID_HANDLE_VALUE) {
     542                birdCloseFile(p->fts_dirfd);
     543                p->fts_dirfd = INVALID_HANDLE_VALUE;
     544    }
     545    fts_free_entry(tmp);
    488546        p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
    489547        return (sp->fts_cur = p);
     
    497555 */
    498556/* ARGSUSED */
    499 int
     557int FTSCALL
    500558fts_set(FTS *sp, FTSENT *p, int instr)
    501559{
     
    509567}
    510568
    511 FTSENT *
     569#if 0
     570FTSENT * FTSCALL
    512571fts_children(FTS *sp, int instr)
    513572{
     
    579638        return (sp->fts_child);
    580639}
     640#endif /* PORTME */
    581641
    582642#ifndef fts_get_clientptr
     
    585645
    586646void *
    587 (fts_get_clientptr)(FTS *sp)
     647(FTSCALL fts_get_clientptr)(FTS *sp)
    588648{
    589649
     
    596656
    597657FTS *
    598 (fts_get_stream)(FTSENT *p)
     658(FTSCALL fts_get_stream)(FTSENT *p)
    599659{
    600660        return (fts_get_stream(p));
    601661}
    602662
    603 void
     663void FTSCALL
    604664fts_set_clientptr(FTS *sp, void *clientptr)
    605665{
     
    621681 * directories and for any files after the subdirectories in the directory have
    622682 * been found, cutting the stat calls by about 2/3.
     683 *
     684 * NT: We do not do any link counting or stat avoiding, which invalidates the
     685 *     above warnings.  This function is very simple for us.
    623686 */
    624687static FTSENT *
    625688fts_build(FTS *sp, int type)
    626689{
    627         struct dirent *dp;
     690        BirdDirEntry_T *dp;
    628691        FTSENT *p, *head;
    629692        FTSENT *cur, *tail;
     
    631694        void *oldaddr;
    632695        char *cp;
    633         int cderrno, descend, oflag, saved_errno, nostat, doadjust;
     696        int saved_errno, doadjust;
    634697        long level;
    635         long nlinks;    /* has to be signed because -1 is a magic value */
    636698        size_t dnamlen, len, maxlen, nitems;
     699        unsigned fDirOpenFlags;
    637700
    638701        /* Set current node pointer. */
     
    642705         * Open the directory for reading.  If this fails, we're done.
    643706         * 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) {
     707         *
     708         * NT: We do a two stage open so we can keep the directory handle around
     709         *     after we've enumerated the directory.  The dir handle is used by
     710         *     us here and by the API users to more efficiently and safely open
     711         *     members of the directory.
     712         */
     713        fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE;
     714    if (cur->fts_dirfd == INVALID_HANDLE_VALUE) {
     715                if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) {
     716                        /* (This works fine for symlinks too, since we follow them.) */
     717                        cur->fts_dirfd = birdOpenFileEx(cur->fts_parent->fts_dirfd,
     718                                                                                        cur->fts_name,
     719                                                                                        FILE_READ_DATA | SYNCHRONIZE,
     720                                                                                        FILE_ATTRIBUTE_NORMAL,
     721                                                                                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     722                                                                                        FILE_OPEN,
     723                                                                                        FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     724                                                                                        OBJ_CASE_INSENSITIVE);
     725                } else {
     726                        cur->fts_dirfd = birdOpenFile(cur->fts_accpath,
     727                                                                                  FILE_READ_DATA | SYNCHRONIZE,
     728                                                                                  FILE_ATTRIBUTE_NORMAL,
     729                                                                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     730                                                                                  FILE_OPEN,
     731                                                                                  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     732                                                                                  OBJ_CASE_INSENSITIVE);
     733                }
     734    } else {
     735                fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN;
     736        }
     737        dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags);
     738        if (dirp == NULL) {
    654739                if (type == BREAD) {
    655740                        cur->fts_info = FTS_DNR;
     
    658743                return (NULL);
    659744        }
    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;
    713745
    714746        /*
     
    723755         */
    724756        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         }
     757        cp = sp->fts_path + len;
     758        *cp++ = '/';
    732759        len++;
    733760        maxlen = sp->fts_pathlen - len;
     
    737764        /* Read the directory, attaching each entry to the `link' pointer. */
    738765        doadjust = 0;
    739         for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
     766        for (head = tail = NULL, nitems = 0; dirp && (dp = birdDirRead(dirp));) {
    740767                dnamlen = dp->d_namlen;
    741768                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
     
    756783                                        free(p);
    757784                                fts_lfree(head);
    758                                 (void)closedir(dirp);
     785                                birdDirClose(dirp);
     786                                birdCloseFile(cur->fts_dirfd);
     787                                cur->fts_dirfd = INVALID_HANDLE_VALUE;
    759788                                cur->fts_info = FTS_ERR;
    760789                                SET(FTS_STOP);
     
    774803                p->fts_parent = sp->fts_cur;
    775804                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                                 p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp));
    804                         } else {
    805                                 p->fts_accpath = p->fts_name;
    806                                 p->fts_info = fts_stat(sp, p, 0, -1);
    807                         }
    808 
    809                         /* Decrement link count if applicable. */
    810                         if (nlinks > 0 && (p->fts_info == FTS_D ||
    811                             p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
    812                                 --nlinks;
    813                 }
     805                p->fts_accpath = p->fts_path;
     806                p->fts_stat = dp->d_stat;
     807                p->fts_info = fts_process_stats(p, &dp->d_stat);
    814808
    815809                /* We walk in directory order so "ls -f" doesn't get upset. */
     
    823817                ++nitems;
    824818        }
    825         if (dirp)
    826                 (void)closedir(dirp);
     819
     820        birdDirClose(dirp);
    827821
    828822        /*
     
    834828
    835829        /*
    836          * If not changing directories, reset the path back to original
    837          * state.
    838          */
    839         if (ISSET(FTS_NOCHDIR))
    840                 sp->fts_path[cur->fts_pathlen] = '\0';
    841 
    842         /*
    843          * If descended after called from fts_children or after called from
    844          * fts_read and nothing found, get back.  At the root level we use
    845          * the saved fd; if one of fts_open()'s arguments is a relative path
    846          * to an empty directory, we wind up here with no other way back.  If
    847          * can't get back, we're done.
    848          */
    849         if (descend && (type == BCHILD || !nitems) &&
    850             (cur->fts_level == FTS_ROOTLEVEL ?
    851             FCHDIR(sp, sp->fts_rfd) :
    852             fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
    853                 cur->fts_info = FTS_ERR;
    854                 SET(FTS_STOP);
    855                 return (NULL);
    856         }
     830         * Reset the path back to original state.
     831         */
     832        sp->fts_path[cur->fts_pathlen] = '\0';
    857833
    858834        /* If didn't find anything, return NULL. */
     
    869845}
    870846
     847
     848/**
     849 * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs
     850 *       following.  On link information is generally retrieved during directory
     851 *       enumeration on NT, in line with it's DOS/OS2/FAT API heritage.
     852 */
    871853static int
    872 fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
    873 {
    874         FTSENT *t;
    875         dev_t dev;
    876         ino_t ino;
    877         struct stat *sbp, sb;
     854fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd)
     855{
    878856        int saved_errno;
    879857        const char *path;
    880858
    881         if (dfd == -1)
    882                 path = p->fts_accpath, dfd = AT_FDCWD;
    883         else
     859        if (dfd == INVALID_HANDLE_VALUE) {
     860                path = p->fts_accpath;
     861        } else {
    884862                path = p->fts_name;
    885 
    886         /* If user needs stat info, stat buffer already allocated. */
    887         sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
    888 
    889 #ifdef FTS_WHITEOUT
    890         /* Check for whiteout. */
    891         if (p->fts_flags & FTS_ISW) {
    892                 if (sbp != &sb) {
    893                         memset(sbp, '\0', sizeof(*sbp));
    894                         sbp->st_mode = S_IFWHT;
    895                 }
    896                 return (FTS_W);
    897         }
    898 #endif
     863        }
    899864
    900865        /*
     
    904869         */
    905870        if (ISSET(FTS_LOGICAL) || follow) {
    906                 if (fstatat(dfd, path, sbp, 0)) {
     871                if (fstatat(dfd, path, &p->fts_stat, 0)) {
    907872                        saved_errno = errno;
    908                         if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
     873                        if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
    909874                                p->fts_errno = saved_errno;
    910875                                goto err;
    911876                        }
    912877                        errno = 0;
    913                         if (S_ISLNK(sbp->st_mode))
     878                        if (S_ISLNK(p->fts_stat.st_mode))
    914879                                return (FTS_SLNONE);
    915880                }
    916         } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
     881        } else if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
    917882                p->fts_errno = errno;
    918 err:            memset(sbp, 0, sizeof(struct stat));
     883err:            memset(&p->fts_stat, 0, sizeof(struct stat));
    919884                return (FTS_NS);
    920885        }
    921 
     886        return fts_process_stats(p, &p->fts_stat);
     887}
     888
     889/* Shared between fts_stat and fts_build. */
     890static int
     891fts_process_stats(FTSENT *p, BirdStat_T const *sbp)
     892{
    922893        if (S_ISDIR(sbp->st_mode)) {
     894                FTSENT *t;
     895                fts_dev_t dev;
     896                fts_ino_t ino;
     897
    923898                /*
    924899                 * Set the device/inode.  Used to find cycles and check for
     
    984959         */
    985960        if (nitems > sp->fts_nitems) {
     961                void *ptr;
    986962                sp->fts_nitems = nitems + 40;
    987                 if ((sp->fts_array = reallocf(sp->fts_array,
    988                     sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
     963                ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *));
     964                if (ptr != NULL) {
     965                        sp->fts_array = ptr;
     966                } else {
     967                        free(sp->fts_array);
     968                        sp->fts_array = NULL;
    989969                        sp->fts_nitems = 0;
    990970                        return (head);
     
    1012992
    1013993        /*
    1014          * The file name is a variable length array and no stat structure is
    1015          * necessary if the user has set the nostat bit.  Allocate the FTSENT
    1016          * structure, the file name and the stat structure in one chunk, but
    1017          * be careful that the stat structure is reasonably aligned.
    1018          */
    1019         if (ISSET(FTS_NOSTAT))
    1020                 len = sizeof(FTSENT) + namelen + 1;
    1021         else
    1022                 len = sizeof(struct ftsent_withstat) + namelen + 1;
    1023 
     994         * The file name is a variable length array.  Allocate the FTSENT
     995         * structure and the file name.
     996         */
     997        len = sizeof(FTSENT) + namelen + 1;
    1024998        if ((p = malloc(len)) == NULL)
    1025999                return (NULL);
    10261000
    1027         if (ISSET(FTS_NOSTAT)) {
    1028                 p->fts_name = (char *)(p + 1);
    1029                 p->fts_statp = NULL;
    1030         } else {
    1031                 p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
    1032                 p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
    1033         }
     1001        p->fts_name = (char *)(p + 1);
     1002        p->fts_statp = &p->fts_stat;
    10341003
    10351004        /* Copy the name and guarantee NUL termination. */
     
    10441013        p->fts_pointer = NULL;
    10451014        p->fts_fts = sp;
     1015        p->fts_symfd = INVALID_HANDLE_VALUE;
     1016        p->fts_dirfd = INVALID_HANDLE_VALUE;
    10461017        return (p);
    10471018}
     
    10551026        while ((p = head)) {
    10561027                head = head->fts_link;
     1028                assert(p->fts_dirfd == INVALID_HANDLE_VALUE);
    10571029                free(p);
    10581030        }
     
    10681040fts_palloc(FTS *sp, size_t more)
    10691041{
     1042        void *ptr;
    10701043
    10711044        sp->fts_pathlen += more + 256;
    1072         sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
    1073         return (sp->fts_path == NULL);
     1045        ptr = realloc(sp->fts_path, sp->fts_pathlen);
     1046        if (ptr) {
     1047                /*likely */
     1048        } else {
     1049                free(sp->fts_path);
     1050        }
     1051        sp->fts_path = ptr;
     1052        return (ptr == NULL);
    10741053}
    10751054
     
    11211100fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
    11221101{
     1102#if 0
    11231103        int ret, oerrno, newfd;
    11241104        struct stat sb;
    11251105
    11261106        newfd = fd;
     1107#endif
    11271108        if (ISSET(FTS_NOCHDIR))
    11281109                return (0);
     1110        assert(0);
     1111        return -1;
     1112#if 0
    11291113        if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY |
    11301114            O_CLOEXEC, 0)) < 0)
     
    11461130        errno = oerrno;
    11471131        return (ret);
     1132#endif
    11481133}
    11491134
    11501135/*
    11511136 * Check if the filesystem for "ent" has UFS-style links.
     1137 *
     1138 * bird: NT does not, which is why they need this check.
     1139 *       See comment on r129052 (2004-05-08 15:09:02Z).
    11521140 */
    11531141static int
    11541142fts_ufslinks(FTS *sp, const FTSENT *ent)
    11551143{
     1144#if 0
    11561145        struct _fts_private *priv;
    11571146        const char **cpp;
     
    11801169        }
    11811170        return (priv->ftsp_linksreliable);
    1182 }
     1171#else
     1172        (void)sp; (void)ent;
     1173        return 0;
     1174#endif
     1175}
     1176
Note: See TracChangeset for help on using the changeset viewer.