Blame lib/glob.c

Packit 8f70b4
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 8f70b4
   This file is part of the GNU C Library.
Packit 8f70b4
Packit 8f70b4
   The GNU C Library is free software; you can redistribute it and/or
Packit 8f70b4
   modify it under the terms of the GNU General Public
Packit 8f70b4
   License as published by the Free Software Foundation; either
Packit 8f70b4
   version 3 of the License, or (at your option) any later version.
Packit 8f70b4
Packit 8f70b4
   The GNU C Library is distributed in the hope that it will be useful,
Packit 8f70b4
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 8f70b4
   General Public License for more details.
Packit 8f70b4
Packit 8f70b4
   You should have received a copy of the GNU General Public
Packit 8f70b4
   License along with the GNU C Library; if not, see
Packit 8f70b4
   <https://www.gnu.org/licenses/>.  */
Packit 8f70b4
Packit 8f70b4
#include <glob.h>
Packit 8f70b4
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <sys/stat.h>
Packit 8f70b4
#include <stdbool.h>
Packit 8f70b4
#include <stddef.h>
Packit 8f70b4
#include <stdint.h>
Packit 8f70b4
#include <assert.h>
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
Packit 8f70b4
#if defined _WIN32 && ! defined __CYGWIN__
Packit 8f70b4
# define WINDOWS32
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifndef WINDOWS32
Packit 8f70b4
# include <pwd.h>
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <dirent.h>
Packit 8f70b4
#include <stdlib.h>
Packit 8f70b4
#include <string.h>
Packit 8f70b4
#include <alloca.h>
Packit 8f70b4
Packit 8f70b4
#ifdef _LIBC
Packit 8f70b4
# undef strdup
Packit 8f70b4
# define strdup(str) __strdup (str)
Packit 8f70b4
# define sysconf(id) __sysconf (id)
Packit 8f70b4
# define closedir(dir) __closedir (dir)
Packit 8f70b4
# define opendir(name) __opendir (name)
Packit 8f70b4
# define readdir(str) __readdir64 (str)
Packit 8f70b4
# define getpwnam_r(name, bufp, buf, len, res) \
Packit 8f70b4
    __getpwnam_r (name, bufp, buf, len, res)
Packit 8f70b4
# ifndef __lstat64
Packit 8f70b4
#  define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf)
Packit 8f70b4
# endif
Packit 8f70b4
# ifndef __stat64
Packit 8f70b4
#  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
Packit 8f70b4
# endif
Packit 8f70b4
# define struct_stat64          struct stat64
Packit 8f70b4
# define FLEXIBLE_ARRAY_MEMBER
Packit 8f70b4
#else /* !_LIBC */
Packit 8f70b4
# define __getlogin_r(buf, len) getlogin_r (buf, len)
Packit 8f70b4
# define __lstat64(fname, buf)  lstat (fname, buf)
Packit 8f70b4
# define __stat64(fname, buf)   stat (fname, buf)
Packit 8f70b4
# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
Packit 8f70b4
# define struct_stat64          struct stat
Packit 8f70b4
# ifndef __MVS__
Packit 8f70b4
#  define __alloca              alloca
Packit 8f70b4
# endif
Packit 8f70b4
# define __readdir              readdir
Packit 8f70b4
# define COMPILE_GLOB64
Packit 8f70b4
#endif /* _LIBC */
Packit 8f70b4
Packit 8f70b4
#include <fnmatch.h>
Packit 8f70b4
Packit 8f70b4
#include <flexmember.h>
Packit 8f70b4
#include <glob_internal.h>
Packit 8f70b4
#include <scratch_buffer.h>
Packit 8f70b4

Packit 8f70b4
static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
Packit 8f70b4
Packit 8f70b4
/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most
Packit 8f70b4
   platforms, but 'unsigned int' in the mingw from mingw.org.  */
Packit 8f70b4
typedef uint_fast32_t dirent_type;
Packit 8f70b4
Packit 8f70b4
#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
Packit 8f70b4
/* Any distinct values will do here.
Packit 8f70b4
   Undef any existing macros out of the way.  */
Packit 8f70b4
# undef DT_UNKNOWN
Packit 8f70b4
# undef DT_DIR
Packit 8f70b4
# undef DT_LNK
Packit 8f70b4
# define DT_UNKNOWN 0
Packit 8f70b4
# define DT_DIR 1
Packit 8f70b4
# define DT_LNK 2
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* A representation of a directory entry which does not depend on the
Packit 8f70b4
   layout of struct dirent, or the size of ino_t.  */
Packit 8f70b4
struct readdir_result
Packit 8f70b4
{
Packit 8f70b4
  const char *name;
Packit 8f70b4
#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
Packit 8f70b4
  dirent_type type;
Packit 8f70b4
#endif
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
/* Initialize and return type member of struct readdir_result.  */
Packit 8f70b4
static dirent_type
Packit 8f70b4
readdir_result_type (struct readdir_result d)
Packit 8f70b4
{
Packit 8f70b4
#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
Packit 8f70b4
# define D_TYPE_TO_RESULT(source) (source)->d_type,
Packit 8f70b4
  return d.type;
Packit 8f70b4
#else
Packit 8f70b4
# define D_TYPE_TO_RESULT(source)
Packit 8f70b4
  return DT_UNKNOWN;
Packit 8f70b4
#endif
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
/* Construct an initializer for a struct readdir_result object from a
Packit 8f70b4
   struct dirent *.  No copy of the name is made.  */
Packit 8f70b4
#define READDIR_RESULT_INITIALIZER(source) \
Packit 8f70b4
  {                                        \
Packit 8f70b4
    source->d_name,                        \
Packit 8f70b4
    D_TYPE_TO_RESULT (source)              \
Packit 8f70b4
  }
Packit 8f70b4
Packit 8f70b4
/* Call gl_readdir on STREAM.  This macro can be overridden to reduce
Packit 8f70b4
   type safety if an old interface version needs to be supported.  */
Packit 8f70b4
#ifndef GL_READDIR
Packit 8f70b4
# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* Extract name and type from directory entry.  No copy of the name is
Packit 8f70b4
   made.  If SOURCE is NULL, result name is NULL.  Keep in sync with
Packit 8f70b4
   convert_dirent64 below.  */
Packit 8f70b4
static struct readdir_result
Packit 8f70b4
convert_dirent (const struct dirent *source)
Packit 8f70b4
{
Packit 8f70b4
  if (source == NULL)
Packit 8f70b4
    {
Packit 8f70b4
      struct readdir_result result = { NULL, };
Packit 8f70b4
      return result;
Packit 8f70b4
    }
Packit 8f70b4
  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#ifndef COMPILE_GLOB64
Packit 8f70b4
/* Like convert_dirent, but works on struct dirent64 instead.  Keep in
Packit 8f70b4
   sync with convert_dirent above.  */
Packit 8f70b4
static struct readdir_result
Packit 8f70b4
convert_dirent64 (const struct dirent64 *source)
Packit 8f70b4
{
Packit 8f70b4
  if (source == NULL)
Packit 8f70b4
    {
Packit 8f70b4
      struct readdir_result result = { NULL, };
Packit 8f70b4
      return result;
Packit 8f70b4
    }
Packit 8f70b4
  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifndef _LIBC
Packit 8f70b4
/* The results of opendir() in this file are not used with dirfd and fchdir,
Packit 8f70b4
   and we do not leak fds to any single-threaded code that could use stdio,
Packit 8f70b4
   therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
Packit 8f70b4
   FIXME - if the kernel ever adds support for multi-thread safety for
Packit 8f70b4
   avoiding standard fds, then we should use opendir_safer.  */
Packit 8f70b4
# ifdef GNULIB_defined_opendir
Packit 8f70b4
#  undef opendir
Packit 8f70b4
# endif
Packit 8f70b4
# ifdef GNULIB_defined_closedir
Packit 8f70b4
#  undef closedir
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
/* Just use malloc.  */
Packit 8f70b4
# define __libc_use_alloca(n) false
Packit 8f70b4
# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
Packit 8f70b4
# define extend_alloca_account(buf, len, newlen, avar) \
Packit 8f70b4
    ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* Set *R = A + B.  Return true if the answer is mathematically
Packit 8f70b4
   incorrect due to overflow; in this case, *R is the low order
Packit 8f70b4
   bits of the correct answer.  */
Packit 8f70b4
Packit 8f70b4
static bool
Packit 8f70b4
size_add_wrapv (size_t a, size_t b, size_t *r)
Packit 8f70b4
{
Packit 8f70b4
#if 5 <= __GNUC__ && !defined __ICC
Packit 8f70b4
  return __builtin_add_overflow (a, b, r);
Packit 8f70b4
#else
Packit 8f70b4
  *r = a + b;
Packit 8f70b4
  return *r < a;
Packit 8f70b4
#endif
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static bool
Packit 8f70b4
glob_use_alloca (size_t alloca_used, size_t len)
Packit 8f70b4
{
Packit 8f70b4
  size_t size;
Packit 8f70b4
  return (!size_add_wrapv (alloca_used, len, &size)
Packit 8f70b4
          && __libc_use_alloca (size));
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static int glob_in_dir (const char *pattern, const char *directory,
Packit 8f70b4
                        int flags, int (*errfunc) (const char *, int),
Packit 8f70b4
                        glob_t *pglob, size_t alloca_used);
Packit 8f70b4
static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
Packit 8f70b4
static int collated_compare (const void *, const void *) __THROWNL;
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* Return true if FILENAME is a directory or a symbolic link to a directory.
Packit 8f70b4
   Use FLAGS and PGLOB to resolve the filename.  */
Packit 8f70b4
static bool
Packit 8f70b4
is_dir (char const *filename, int flags, glob_t const *pglob)
Packit 8f70b4
{
Packit 8f70b4
  struct stat st;
Packit 8f70b4
  struct_stat64 st64;
Packit 8f70b4
  return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
Packit 8f70b4
          ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode)
Packit 8f70b4
          : __stat64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode));
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
/* Find the end of the sub-pattern in a brace expression.  */
Packit 8f70b4
static const char *
Packit 8f70b4
next_brace_sub (const char *cp, int flags)
Packit 8f70b4
{
Packit 8f70b4
  size_t depth = 0;
Packit 8f70b4
  while (*cp != '\0')
Packit 8f70b4
    if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
Packit 8f70b4
      {
Packit 8f70b4
        if (*++cp == '\0')
Packit 8f70b4
          break;
Packit 8f70b4
        ++cp;
Packit 8f70b4
      }
Packit 8f70b4
    else
Packit 8f70b4
      {
Packit 8f70b4
        if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        if (*cp++ == '{')
Packit 8f70b4
          depth++;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
  return *cp != '\0' ? cp : NULL;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* Do glob searching for PATTERN, placing results in PGLOB.
Packit 8f70b4
   The bits defined above may be set in FLAGS.
Packit 8f70b4
   If a directory cannot be opened or read and ERRFUNC is not nil,
Packit 8f70b4
   it is called with the pathname that caused the error, and the
Packit 8f70b4
   'errno' value from the failing call; if it returns non-zero
Packit 8f70b4
   'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
Packit 8f70b4
   If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
Packit 8f70b4
   Otherwise, 'glob' returns zero.  */
Packit 8f70b4
int
Packit 8f70b4
#ifdef GLOB_ATTRIBUTE
Packit 8f70b4
GLOB_ATTRIBUTE
Packit 8f70b4
#endif
Packit 8f70b4
glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
Packit 8f70b4
      glob_t *pglob)
Packit 8f70b4
{
Packit 8f70b4
  const char *filename;
Packit 8f70b4
  char *dirname = NULL;
Packit 8f70b4
  size_t dirlen;
Packit 8f70b4
  int status;
Packit 8f70b4
  size_t oldcount;
Packit 8f70b4
  int meta;
Packit 8f70b4
  int dirname_modified;
Packit 8f70b4
  int malloc_dirname = 0;
Packit 8f70b4
  glob_t dirs;
Packit 8f70b4
  int retval = 0;
Packit 8f70b4
  size_t alloca_used = 0;
Packit 8f70b4
Packit 8f70b4
  if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
Packit 8f70b4
    {
Packit 8f70b4
      __set_errno (EINVAL);
Packit 8f70b4
      return -1;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* POSIX requires all slashes to be matched.  This means that with
Packit 8f70b4
     a trailing slash we must match only directories.  */
Packit 8f70b4
  if (pattern[0] && pattern[strlen (pattern) - 1] == '/')
Packit 8f70b4
    flags |= GLOB_ONLYDIR;
Packit 8f70b4
Packit 8f70b4
  if (!(flags & GLOB_DOOFFS))
Packit 8f70b4
    /* Have to do this so 'globfree' knows where to start freeing.  It
Packit 8f70b4
       also makes all the code that uses gl_offs simpler. */
Packit 8f70b4
    pglob->gl_offs = 0;
Packit 8f70b4
Packit 8f70b4
  if (!(flags & GLOB_APPEND))
Packit 8f70b4
    {
Packit 8f70b4
      pglob->gl_pathc = 0;
Packit 8f70b4
      if (!(flags & GLOB_DOOFFS))
Packit 8f70b4
        pglob->gl_pathv = NULL;
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          size_t i;
Packit 8f70b4
Packit 8f70b4
          if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
Packit 8f70b4
            return GLOB_NOSPACE;
Packit 8f70b4
Packit 8f70b4
          pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
Packit 8f70b4
                                              * sizeof (char *));
Packit 8f70b4
          if (pglob->gl_pathv == NULL)
Packit 8f70b4
            return GLOB_NOSPACE;
Packit 8f70b4
Packit 8f70b4
          for (i = 0; i <= pglob->gl_offs; ++i)
Packit 8f70b4
            pglob->gl_pathv[i] = NULL;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (flags & GLOB_BRACE)
Packit 8f70b4
    {
Packit 8f70b4
      const char *begin;
Packit 8f70b4
Packit 8f70b4
      if (flags & GLOB_NOESCAPE)
Packit 8f70b4
        begin = strchr (pattern, '{');
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          begin = pattern;
Packit 8f70b4
          while (1)
Packit 8f70b4
            {
Packit 8f70b4
              if (*begin == '\0')
Packit 8f70b4
                {
Packit 8f70b4
                  begin = NULL;
Packit 8f70b4
                  break;
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              if (*begin == '\\' && begin[1] != '\0')
Packit 8f70b4
                ++begin;
Packit 8f70b4
              else if (*begin == '{')
Packit 8f70b4
                break;
Packit 8f70b4
Packit 8f70b4
              ++begin;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (begin != NULL)
Packit 8f70b4
        {
Packit 8f70b4
          /* Allocate working buffer large enough for our work.  Note that
Packit 8f70b4
             we have at least an opening and closing brace.  */
Packit 8f70b4
          size_t firstc;
Packit 8f70b4
          char *alt_start;
Packit 8f70b4
          const char *p;
Packit 8f70b4
          const char *next;
Packit 8f70b4
          const char *rest;
Packit 8f70b4
          size_t rest_len;
Packit 8f70b4
          char *onealt;
Packit 8f70b4
          size_t pattern_len = strlen (pattern) - 1;
Packit 8f70b4
          int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
Packit 8f70b4
          if (alloca_onealt)
Packit 8f70b4
            onealt = alloca_account (pattern_len, alloca_used);
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              onealt = malloc (pattern_len);
Packit 8f70b4
              if (onealt == NULL)
Packit 8f70b4
                return GLOB_NOSPACE;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          /* We know the prefix for all sub-patterns.  */
Packit 8f70b4
          alt_start = mempcpy (onealt, pattern, begin - pattern);
Packit 8f70b4
Packit 8f70b4
          /* Find the first sub-pattern and at the same time find the
Packit 8f70b4
             rest after the closing brace.  */
Packit 8f70b4
          next = next_brace_sub (begin + 1, flags);
Packit 8f70b4
          if (next == NULL)
Packit 8f70b4
            {
Packit 8f70b4
              /* It is an invalid expression.  */
Packit 8f70b4
            illegal_brace:
Packit 8f70b4
              if (__glibc_unlikely (!alloca_onealt))
Packit 8f70b4
                free (onealt);
Packit 8f70b4
              flags &= ~GLOB_BRACE;
Packit 8f70b4
              goto no_brace;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          /* Now find the end of the whole brace expression.  */
Packit 8f70b4
          rest = next;
Packit 8f70b4
          while (*rest != '}')
Packit 8f70b4
            {
Packit 8f70b4
              rest = next_brace_sub (rest + 1, flags);
Packit 8f70b4
              if (rest == NULL)
Packit 8f70b4
                /* It is an illegal expression.  */
Packit 8f70b4
                goto illegal_brace;
Packit 8f70b4
            }
Packit 8f70b4
          /* Please note that we now can be sure the brace expression
Packit 8f70b4
             is well-formed.  */
Packit 8f70b4
          rest_len = strlen (++rest) + 1;
Packit 8f70b4
Packit 8f70b4
          /* We have a brace expression.  BEGIN points to the opening {,
Packit 8f70b4
             NEXT points past the terminator of the first element, and END
Packit 8f70b4
             points past the final }.  We will accumulate result names from
Packit 8f70b4
             recursive runs for each brace alternative in the buffer using
Packit 8f70b4
             GLOB_APPEND.  */
Packit 8f70b4
          firstc = pglob->gl_pathc;
Packit 8f70b4
Packit 8f70b4
          p = begin + 1;
Packit 8f70b4
          while (1)
Packit 8f70b4
            {
Packit 8f70b4
              int result;
Packit 8f70b4
Packit 8f70b4
              /* Construct the new glob expression.  */
Packit 8f70b4
              mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
Packit 8f70b4
Packit 8f70b4
              result = glob (onealt,
Packit 8f70b4
                             ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
Packit 8f70b4
                              | GLOB_APPEND), errfunc, pglob);
Packit 8f70b4
Packit 8f70b4
              /* If we got an error, return it.  */
Packit 8f70b4
              if (result && result != GLOB_NOMATCH)
Packit 8f70b4
                {
Packit 8f70b4
                  if (__glibc_unlikely (!alloca_onealt))
Packit 8f70b4
                    free (onealt);
Packit 8f70b4
                  if (!(flags & GLOB_APPEND))
Packit 8f70b4
                    {
Packit 8f70b4
                      globfree (pglob);
Packit 8f70b4
                      pglob->gl_pathc = 0;
Packit 8f70b4
                    }
Packit 8f70b4
                  return result;
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              if (*next == '}')
Packit 8f70b4
                /* We saw the last entry.  */
Packit 8f70b4
                break;
Packit 8f70b4
Packit 8f70b4
              p = next + 1;
Packit 8f70b4
              next = next_brace_sub (p, flags);
Packit 8f70b4
              assert (next != NULL);
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          if (__glibc_unlikely (!alloca_onealt))
Packit 8f70b4
            free (onealt);
Packit 8f70b4
Packit 8f70b4
          if (pglob->gl_pathc != firstc)
Packit 8f70b4
            /* We found some entries.  */
Packit 8f70b4
            return 0;
Packit 8f70b4
          else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
Packit 8f70b4
            return GLOB_NOMATCH;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
 no_brace:
Packit 8f70b4
  oldcount = pglob->gl_pathc + pglob->gl_offs;
Packit 8f70b4
Packit 8f70b4
  /* Find the filename.  */
Packit 8f70b4
  filename = strrchr (pattern, '/');
Packit 8f70b4
Packit 8f70b4
#if defined __MSDOS__ || defined WINDOWS32
Packit 8f70b4
  /* The case of "d:pattern".  Since ':' is not allowed in
Packit 8f70b4
     file names, we can safely assume that wherever it
Packit 8f70b4
     happens in pattern, it signals the filename part.  This
Packit 8f70b4
     is so we could some day support patterns like "[a-z]:foo".  */
Packit 8f70b4
  if (filename == NULL)
Packit 8f70b4
    filename = strchr (pattern, ':');
Packit 8f70b4
#endif /* __MSDOS__ || WINDOWS32 */
Packit 8f70b4
Packit 8f70b4
  dirname_modified = 0;
Packit 8f70b4
  if (filename == NULL)
Packit 8f70b4
    {
Packit 8f70b4
      /* This can mean two things: a simple name or "~name".  The latter
Packit 8f70b4
         case is nothing but a notation for a directory.  */
Packit 8f70b4
      if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
Packit 8f70b4
        {
Packit 8f70b4
          dirname = (char *) pattern;
Packit 8f70b4
          dirlen = strlen (pattern);
Packit 8f70b4
Packit 8f70b4
          /* Set FILENAME to NULL as a special flag.  This is ugly but
Packit 8f70b4
             other solutions would require much more code.  We test for
Packit 8f70b4
             this special case below.  */
Packit 8f70b4
          filename = NULL;
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          if (__glibc_unlikely (pattern[0] == '\0'))
Packit 8f70b4
            {
Packit 8f70b4
              dirs.gl_pathv = NULL;
Packit 8f70b4
              goto no_matches;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          filename = pattern;
Packit 8f70b4
          dirname = (char *) ".";
Packit 8f70b4
          dirlen = 0;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
  else if (filename == pattern
Packit 8f70b4
           || (filename == pattern + 1 && pattern[0] == '\\'
Packit 8f70b4
               && (flags & GLOB_NOESCAPE) == 0))
Packit 8f70b4
    {
Packit 8f70b4
      /* "/pattern" or "\\/pattern".  */
Packit 8f70b4
      dirname = (char *) "/";
Packit 8f70b4
      dirlen = 1;
Packit 8f70b4
      ++filename;
Packit 8f70b4
    }
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      char *newp;
Packit 8f70b4
      dirlen = filename - pattern;
Packit 8f70b4
Packit 8f70b4
#if defined __MSDOS__ || defined WINDOWS32
Packit 8f70b4
      if (*filename == ':'
Packit 8f70b4
          || (filename > pattern + 1 && filename[-1] == ':'))
Packit 8f70b4
        {
Packit 8f70b4
          char *drive_spec;
Packit 8f70b4
Packit 8f70b4
          ++dirlen;
Packit 8f70b4
          drive_spec = __alloca (dirlen + 1);
Packit 8f70b4
          *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
Packit 8f70b4
          /* For now, disallow wildcards in the drive spec, to
Packit 8f70b4
             prevent infinite recursion in glob.  */
Packit 8f70b4
          if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
Packit 8f70b4
            return GLOB_NOMATCH;
Packit 8f70b4
          /* If this is "d:pattern", we need to copy ':' to DIRNAME
Packit 8f70b4
             as well.  If it's "d:/pattern", don't remove the slash
Packit 8f70b4
             from "d:/", since "d:" and "d:/" are not the same.*/
Packit 8f70b4
        }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
      if (glob_use_alloca (alloca_used, dirlen + 1))
Packit 8f70b4
        newp = alloca_account (dirlen + 1, alloca_used);
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          newp = malloc (dirlen + 1);
Packit 8f70b4
          if (newp == NULL)
Packit 8f70b4
            return GLOB_NOSPACE;
Packit 8f70b4
          malloc_dirname = 1;
Packit 8f70b4
        }
Packit 8f70b4
      *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
Packit 8f70b4
      dirname = newp;
Packit 8f70b4
      ++filename;
Packit 8f70b4
Packit 8f70b4
#if defined __MSDOS__ || defined WINDOWS32
Packit 8f70b4
      bool drive_root = (dirlen > 1
Packit 8f70b4
                         && (dirname[dirlen - 1] == ':'
Packit 8f70b4
                             || (dirlen > 2 && dirname[dirlen - 2] == ':'
Packit 8f70b4
                                 && dirname[dirlen - 1] == '/')));
Packit 8f70b4
#else
Packit 8f70b4
      bool drive_root = false;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
      if (filename[0] == '\0' && dirlen > 1 && !drive_root)
Packit 8f70b4
        /* "pattern/".  Expand "pattern", appending slashes.  */
Packit 8f70b4
        {
Packit 8f70b4
          int orig_flags = flags;
Packit 8f70b4
          if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
Packit 8f70b4
            {
Packit 8f70b4
              /* "pattern\\/".  Remove the final backslash if it hasn't
Packit 8f70b4
                 been quoted.  */
Packit 8f70b4
              char *p = (char *) &dirname[dirlen - 1];
Packit 8f70b4
Packit 8f70b4
              while (p > dirname && p[-1] == '\\') --p;
Packit 8f70b4
              if ((&dirname[dirlen] - p) & 1)
Packit 8f70b4
                {
Packit 8f70b4
                  *(char *) &dirname[--dirlen] = '\0';
Packit 8f70b4
                  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
Packit 8f70b4
                }
Packit 8f70b4
            }
Packit 8f70b4
          int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
Packit 8f70b4
          if (val == 0)
Packit 8f70b4
            pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
Packit 8f70b4
                               | (flags & GLOB_MARK));
Packit 8f70b4
          else if (val == GLOB_NOMATCH && flags != orig_flags)
Packit 8f70b4
            {
Packit 8f70b4
              /* Make sure globfree (&dirs); is a nop.  */
Packit 8f70b4
              dirs.gl_pathv = NULL;
Packit 8f70b4
              flags = orig_flags;
Packit 8f70b4
              oldcount = pglob->gl_pathc + pglob->gl_offs;
Packit 8f70b4
              goto no_matches;
Packit 8f70b4
            }
Packit 8f70b4
          retval = val;
Packit 8f70b4
          goto out;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
Packit 8f70b4
    {
Packit 8f70b4
      if (dirname[1] == '\0' || dirname[1] == '/'
Packit 8f70b4
          || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
Packit 8f70b4
              && (dirname[2] == '\0' || dirname[2] == '/')))
Packit 8f70b4
        {
Packit 8f70b4
          /* Look up home directory.  */
Packit 8f70b4
          char *home_dir = getenv ("HOME");
Packit 8f70b4
          int malloc_home_dir = 0;
Packit 8f70b4
          if (home_dir == NULL || home_dir[0] == '\0')
Packit 8f70b4
            {
Packit 8f70b4
#ifdef WINDOWS32
Packit 8f70b4
              /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give
Packit 8f70b4
                 preference to HOME, because the user can change HOME.  */
Packit 8f70b4
              const char *home_drive = getenv ("HOMEDRIVE");
Packit 8f70b4
              const char *home_path = getenv ("HOMEPATH");
Packit 8f70b4
Packit 8f70b4
              if (home_drive != NULL && home_path != NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  size_t home_drive_len = strlen (home_drive);
Packit 8f70b4
                  size_t home_path_len = strlen (home_path);
Packit 8f70b4
                  char *mem = alloca (home_drive_len + home_path_len + 1);
Packit 8f70b4
Packit 8f70b4
                  memcpy (mem, home_drive, home_drive_len);
Packit 8f70b4
                  memcpy (mem + home_drive_len, home_path, home_path_len + 1);
Packit 8f70b4
                  home_dir = mem;
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                home_dir = "c:/users/default"; /* poor default */
Packit 8f70b4
#else
Packit 8f70b4
              int err;
Packit 8f70b4
              struct passwd *p;
Packit 8f70b4
              struct passwd pwbuf;
Packit 8f70b4
              struct scratch_buffer s;
Packit 8f70b4
              scratch_buffer_init (&s);
Packit 8f70b4
              while (true)
Packit 8f70b4
                {
Packit 8f70b4
                  p = NULL;
Packit 8f70b4
                  err = __getlogin_r (s.data, s.length);
Packit 8f70b4
                  if (err == 0)
Packit 8f70b4
                    {
Packit 8f70b4
# if defined HAVE_GETPWNAM_R || defined _LIBC
Packit 8f70b4
                      size_t ssize = strlen (s.data) + 1;
Packit 8f70b4
                      char *sdata = s.data;
Packit 8f70b4
                      err = getpwnam_r (sdata, &pwbuf, sdata + ssize,
Packit 8f70b4
                                        s.length - ssize, &p);
Packit 8f70b4
# else
Packit 8f70b4
                      p = getpwnam (s.data);
Packit 8f70b4
                      if (p == NULL)
Packit 8f70b4
                        err = errno;
Packit 8f70b4
# endif
Packit 8f70b4
                    }
Packit 8f70b4
                  if (err != ERANGE)
Packit 8f70b4
                    break;
Packit 8f70b4
                  if (!scratch_buffer_grow (&s))
Packit 8f70b4
                    {
Packit 8f70b4
                      retval = GLOB_NOSPACE;
Packit 8f70b4
                      goto out;
Packit 8f70b4
                    }
Packit 8f70b4
                }
Packit 8f70b4
              if (err == 0)
Packit 8f70b4
                {
Packit 8f70b4
                  home_dir = strdup (p->pw_dir);
Packit 8f70b4
                  malloc_home_dir = 1;
Packit 8f70b4
                }
Packit 8f70b4
              scratch_buffer_free (&s);
Packit 8f70b4
              if (err == 0 && home_dir == NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  retval = GLOB_NOSPACE;
Packit 8f70b4
                  goto out;
Packit 8f70b4
                }
Packit 8f70b4
#endif /* WINDOWS32 */
Packit 8f70b4
            }
Packit 8f70b4
          if (home_dir == NULL || home_dir[0] == '\0')
Packit 8f70b4
            {
Packit 8f70b4
              if (__glibc_unlikely (malloc_home_dir))
Packit 8f70b4
                free (home_dir);
Packit 8f70b4
              if (flags & GLOB_TILDE_CHECK)
Packit 8f70b4
                {
Packit 8f70b4
                  retval = GLOB_NOMATCH;
Packit 8f70b4
                  goto out;
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                {
Packit 8f70b4
                  home_dir = (char *) "~"; /* No luck.  */
Packit 8f70b4
                  malloc_home_dir = 0;
Packit 8f70b4
                }
Packit 8f70b4
            }
Packit 8f70b4
          /* Now construct the full directory.  */
Packit 8f70b4
          if (dirname[1] == '\0')
Packit 8f70b4
            {
Packit 8f70b4
              if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
                free (dirname);
Packit 8f70b4
Packit 8f70b4
              dirname = home_dir;
Packit 8f70b4
              dirlen = strlen (dirname);
Packit 8f70b4
              malloc_dirname = malloc_home_dir;
Packit 8f70b4
            }
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              char *newp;
Packit 8f70b4
              size_t home_len = strlen (home_dir);
Packit 8f70b4
              int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
Packit 8f70b4
              if (use_alloca)
Packit 8f70b4
                newp = alloca_account (home_len + dirlen, alloca_used);
Packit 8f70b4
              else
Packit 8f70b4
                {
Packit 8f70b4
                  newp = malloc (home_len + dirlen);
Packit 8f70b4
                  if (newp == NULL)
Packit 8f70b4
                    {
Packit 8f70b4
                      if (__glibc_unlikely (malloc_home_dir))
Packit 8f70b4
                        free (home_dir);
Packit 8f70b4
                      retval = GLOB_NOSPACE;
Packit 8f70b4
                      goto out;
Packit 8f70b4
                    }
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              mempcpy (mempcpy (newp, home_dir, home_len),
Packit 8f70b4
                       &dirname[1], dirlen);
Packit 8f70b4
Packit 8f70b4
              if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
                free (dirname);
Packit 8f70b4
Packit 8f70b4
              dirname = newp;
Packit 8f70b4
              dirlen += home_len - 1;
Packit 8f70b4
              malloc_dirname = !use_alloca;
Packit 8f70b4
Packit 8f70b4
              if (__glibc_unlikely (malloc_home_dir))
Packit 8f70b4
                free (home_dir);
Packit 8f70b4
            }
Packit 8f70b4
          dirname_modified = 1;
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
#ifndef WINDOWS32
Packit 8f70b4
          char *end_name = strchr (dirname, '/');
Packit 8f70b4
          char *user_name;
Packit 8f70b4
          int malloc_user_name = 0;
Packit 8f70b4
          char *unescape = NULL;
Packit 8f70b4
Packit 8f70b4
          if (!(flags & GLOB_NOESCAPE))
Packit 8f70b4
            {
Packit 8f70b4
              if (end_name == NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  unescape = strchr (dirname, '\\');
Packit 8f70b4
                  if (unescape)
Packit 8f70b4
                    end_name = strchr (unescape, '\0');
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                unescape = memchr (dirname, '\\', end_name - dirname);
Packit 8f70b4
            }
Packit 8f70b4
          if (end_name == NULL)
Packit 8f70b4
            user_name = dirname + 1;
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              char *newp;
Packit 8f70b4
              if (glob_use_alloca (alloca_used, end_name - dirname))
Packit 8f70b4
                newp = alloca_account (end_name - dirname, alloca_used);
Packit 8f70b4
              else
Packit 8f70b4
                {
Packit 8f70b4
                  newp = malloc (end_name - dirname);
Packit 8f70b4
                  if (newp == NULL)
Packit 8f70b4
                    {
Packit 8f70b4
                      retval = GLOB_NOSPACE;
Packit 8f70b4
                      goto out;
Packit 8f70b4
                    }
Packit 8f70b4
                  malloc_user_name = 1;
Packit 8f70b4
                }
Packit 8f70b4
              if (unescape != NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  char *p = mempcpy (newp, dirname + 1,
Packit 8f70b4
                                     unescape - dirname - 1);
Packit 8f70b4
                  char *q = unescape;
Packit 8f70b4
                  while (q != end_name)
Packit 8f70b4
                    {
Packit 8f70b4
                      if (*q == '\\')
Packit 8f70b4
                        {
Packit 8f70b4
                          if (q + 1 == end_name)
Packit 8f70b4
                            {
Packit 8f70b4
                              /* "~fo\\o\\" unescape to user_name "foo\\",
Packit 8f70b4
                                 but "~fo\\o\\/" unescape to user_name
Packit 8f70b4
                                 "foo".  */
Packit 8f70b4
                              if (filename == NULL)
Packit 8f70b4
                                *p++ = '\\';
Packit 8f70b4
                              break;
Packit 8f70b4
                            }
Packit 8f70b4
                          ++q;
Packit 8f70b4
                        }
Packit 8f70b4
                      *p++ = *q++;
Packit 8f70b4
                    }
Packit 8f70b4
                  *p = '\0';
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
Packit 8f70b4
                  = '\0';
Packit 8f70b4
              user_name = newp;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          /* Look up specific user's home directory.  */
Packit 8f70b4
          {
Packit 8f70b4
            struct passwd *p;
Packit 8f70b4
            struct scratch_buffer pwtmpbuf;
Packit 8f70b4
            scratch_buffer_init (&pwtmpbuf);
Packit 8f70b4
Packit 8f70b4
#  if defined HAVE_GETPWNAM_R || defined _LIBC
Packit 8f70b4
            struct passwd pwbuf;
Packit 8f70b4
Packit 8f70b4
            while (getpwnam_r (user_name, &pwbuf,
Packit 8f70b4
                               pwtmpbuf.data, pwtmpbuf.length, &p)
Packit 8f70b4
                   == ERANGE)
Packit 8f70b4
              {
Packit 8f70b4
                if (!scratch_buffer_grow (&pwtmpbuf))
Packit 8f70b4
                  {
Packit 8f70b4
                    retval = GLOB_NOSPACE;
Packit 8f70b4
                    goto out;
Packit 8f70b4
                  }
Packit 8f70b4
              }
Packit 8f70b4
#  else
Packit 8f70b4
            p = getpwnam (user_name);
Packit 8f70b4
#  endif
Packit 8f70b4
Packit 8f70b4
            if (__glibc_unlikely (malloc_user_name))
Packit 8f70b4
              free (user_name);
Packit 8f70b4
Packit 8f70b4
            /* If we found a home directory use this.  */
Packit 8f70b4
            if (p != NULL)
Packit 8f70b4
              {
Packit 8f70b4
                size_t home_len = strlen (p->pw_dir);
Packit 8f70b4
                size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
Packit 8f70b4
                char *d;
Packit 8f70b4
Packit 8f70b4
                if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
                  free (dirname);
Packit 8f70b4
                malloc_dirname = 0;
Packit 8f70b4
Packit 8f70b4
                if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
Packit 8f70b4
                  dirname = alloca_account (home_len + rest_len + 1,
Packit 8f70b4
                                            alloca_used);
Packit 8f70b4
                else
Packit 8f70b4
                  {
Packit 8f70b4
                    dirname = malloc (home_len + rest_len + 1);
Packit 8f70b4
                    if (dirname == NULL)
Packit 8f70b4
                      {
Packit 8f70b4
                        scratch_buffer_free (&pwtmpbuf);
Packit 8f70b4
                        retval = GLOB_NOSPACE;
Packit 8f70b4
                        goto out;
Packit 8f70b4
                      }
Packit 8f70b4
                    malloc_dirname = 1;
Packit 8f70b4
                  }
Packit 8f70b4
                d = mempcpy (dirname, p->pw_dir, home_len);
Packit 8f70b4
                if (end_name != NULL)
Packit 8f70b4
                  d = mempcpy (d, end_name, rest_len);
Packit 8f70b4
                *d = '\0';
Packit 8f70b4
Packit 8f70b4
                dirlen = home_len + rest_len;
Packit 8f70b4
                dirname_modified = 1;
Packit 8f70b4
              }
Packit 8f70b4
            else
Packit 8f70b4
              {
Packit 8f70b4
                if (flags & GLOB_TILDE_CHECK)
Packit 8f70b4
                  {
Packit 8f70b4
                    /* We have to regard it as an error if we cannot find the
Packit 8f70b4
                       home directory.  */
Packit 8f70b4
                    retval = GLOB_NOMATCH;
Packit 8f70b4
                    goto out;
Packit 8f70b4
                  }
Packit 8f70b4
              }
Packit 8f70b4
            scratch_buffer_free (&pwtmpbuf);
Packit 8f70b4
          }
Packit 8f70b4
#endif /* !WINDOWS32 */
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* Now test whether we looked for "~" or "~NAME".  In this case we
Packit 8f70b4
     can give the answer now.  */
Packit 8f70b4
  if (filename == NULL)
Packit 8f70b4
    {
Packit 8f70b4
      size_t newcount = pglob->gl_pathc + pglob->gl_offs;
Packit 8f70b4
      char **new_gl_pathv;
Packit 8f70b4
Packit 8f70b4
      if (newcount > SIZE_MAX / sizeof (char *) - 2)
Packit 8f70b4
        {
Packit 8f70b4
        nospace:
Packit 8f70b4
          free (pglob->gl_pathv);
Packit 8f70b4
          pglob->gl_pathv = NULL;
Packit 8f70b4
          pglob->gl_pathc = 0;
Packit 8f70b4
          retval = GLOB_NOSPACE;
Packit 8f70b4
          goto out;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      new_gl_pathv = realloc (pglob->gl_pathv,
Packit 8f70b4
                              (newcount + 2) * sizeof (char *));
Packit 8f70b4
      if (new_gl_pathv == NULL)
Packit 8f70b4
        goto nospace;
Packit 8f70b4
      pglob->gl_pathv = new_gl_pathv;
Packit 8f70b4
Packit 8f70b4
      if (flags & GLOB_MARK && is_dir (dirname, flags, pglob))
Packit 8f70b4
        {
Packit 8f70b4
          char *p;
Packit 8f70b4
          pglob->gl_pathv[newcount] = malloc (dirlen + 2);
Packit 8f70b4
          if (pglob->gl_pathv[newcount] == NULL)
Packit 8f70b4
            goto nospace;
Packit 8f70b4
          p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
Packit 8f70b4
          p[0] = '/';
Packit 8f70b4
          p[1] = '\0';
Packit 8f70b4
          if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
            free (dirname);
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
            pglob->gl_pathv[newcount] = dirname;
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              pglob->gl_pathv[newcount] = strdup (dirname);
Packit 8f70b4
              if (pglob->gl_pathv[newcount] == NULL)
Packit 8f70b4
                goto nospace;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
      pglob->gl_pathv[++newcount] = NULL;
Packit 8f70b4
      ++pglob->gl_pathc;
Packit 8f70b4
      pglob->gl_flags = flags;
Packit 8f70b4
Packit 8f70b4
      return 0;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
Packit 8f70b4
  /* meta is 1 if correct glob pattern containing metacharacters.
Packit 8f70b4
     If meta has bit (1 << 2) set, it means there was an unterminated
Packit 8f70b4
     [ which we handle the same, using fnmatch.  Broken unterminated
Packit 8f70b4
     pattern bracket expressions ought to be rare enough that it is
Packit 8f70b4
     not worth special casing them, fnmatch will do the right thing.  */
Packit 8f70b4
  if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET))
Packit 8f70b4
    {
Packit 8f70b4
      /* The directory name contains metacharacters, so we
Packit 8f70b4
         have to glob for the directory, and then glob for
Packit 8f70b4
         the pattern in each directory found.  */
Packit 8f70b4
      size_t i;
Packit 8f70b4
Packit 8f70b4
      if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
Packit 8f70b4
        {
Packit 8f70b4
          /* "foo\\/bar".  Remove the final backslash from dirname
Packit 8f70b4
             if it has not been quoted.  */
Packit 8f70b4
          char *p = (char *) &dirname[dirlen - 1];
Packit 8f70b4
Packit 8f70b4
          while (p > dirname && p[-1] == '\\') --p;
Packit 8f70b4
          if ((&dirname[dirlen] - p) & 1)
Packit 8f70b4
            *(char *) &dirname[--dirlen] = '\0';
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0))
Packit 8f70b4
        {
Packit 8f70b4
          /* Use the alternative access functions also in the recursive
Packit 8f70b4
             call.  */
Packit 8f70b4
          dirs.gl_opendir = pglob->gl_opendir;
Packit 8f70b4
          dirs.gl_readdir = pglob->gl_readdir;
Packit 8f70b4
          dirs.gl_closedir = pglob->gl_closedir;
Packit 8f70b4
          dirs.gl_stat = pglob->gl_stat;
Packit 8f70b4
          dirs.gl_lstat = pglob->gl_lstat;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      status = glob (dirname,
Packit 8f70b4
                     ((flags & (GLOB_ERR | GLOB_NOESCAPE
Packit 8f70b4
                                | GLOB_ALTDIRFUNC))
Packit 8f70b4
                      | GLOB_NOSORT | GLOB_ONLYDIR),
Packit 8f70b4
                     errfunc, &dirs);
Packit 8f70b4
      if (status != 0)
Packit 8f70b4
        {
Packit 8f70b4
          if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
Packit 8f70b4
            {
Packit 8f70b4
              retval = status;
Packit 8f70b4
              goto out;
Packit 8f70b4
            }
Packit 8f70b4
          goto no_matches;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      /* We have successfully globbed the preceding directory name.
Packit 8f70b4
         For each name we found, call glob_in_dir on it and FILENAME,
Packit 8f70b4
         appending the results to PGLOB.  */
Packit 8f70b4
      for (i = 0; i < dirs.gl_pathc; ++i)
Packit 8f70b4
        {
Packit 8f70b4
          size_t old_pathc;
Packit 8f70b4
Packit 8f70b4
          old_pathc = pglob->gl_pathc;
Packit 8f70b4
          status = glob_in_dir (filename, dirs.gl_pathv[i],
Packit 8f70b4
                                ((flags | GLOB_APPEND)
Packit 8f70b4
                                 & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
Packit 8f70b4
                                errfunc, pglob, alloca_used);
Packit 8f70b4
          if (status == GLOB_NOMATCH)
Packit 8f70b4
            /* No matches in this directory.  Try the next.  */
Packit 8f70b4
            continue;
Packit 8f70b4
Packit 8f70b4
          if (status != 0)
Packit 8f70b4
            {
Packit 8f70b4
              globfree (&dirs);
Packit 8f70b4
              globfree (pglob);
Packit 8f70b4
              pglob->gl_pathc = 0;
Packit 8f70b4
              retval = status;
Packit 8f70b4
              goto out;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          /* Stick the directory on the front of each name.  */
Packit 8f70b4
          if (prefix_array (dirs.gl_pathv[i],
Packit 8f70b4
                            &pglob->gl_pathv[old_pathc + pglob->gl_offs],
Packit 8f70b4
                            pglob->gl_pathc - old_pathc))
Packit 8f70b4
            {
Packit 8f70b4
              globfree (&dirs);
Packit 8f70b4
              globfree (pglob);
Packit 8f70b4
              pglob->gl_pathc = 0;
Packit 8f70b4
              retval = GLOB_NOSPACE;
Packit 8f70b4
              goto out;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      flags |= GLOB_MAGCHAR;
Packit 8f70b4
Packit 8f70b4
      /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
Packit 8f70b4
         But if we have not found any matching entry and the GLOB_NOCHECK
Packit 8f70b4
         flag was set we must return the input pattern itself.  */
Packit 8f70b4
      if (pglob->gl_pathc + pglob->gl_offs == oldcount)
Packit 8f70b4
        {
Packit 8f70b4
        no_matches:
Packit 8f70b4
          /* No matches.  */
Packit 8f70b4
          if (flags & GLOB_NOCHECK)
Packit 8f70b4
            {
Packit 8f70b4
              size_t newcount = pglob->gl_pathc + pglob->gl_offs;
Packit 8f70b4
              char **new_gl_pathv;
Packit 8f70b4
Packit 8f70b4
              if (newcount > SIZE_MAX / sizeof (char *) - 2)
Packit 8f70b4
                {
Packit 8f70b4
                nospace2:
Packit 8f70b4
                  globfree (&dirs);
Packit 8f70b4
                  retval = GLOB_NOSPACE;
Packit 8f70b4
                  goto out;
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              new_gl_pathv = realloc (pglob->gl_pathv,
Packit 8f70b4
                                      (newcount + 2) * sizeof (char *));
Packit 8f70b4
              if (new_gl_pathv == NULL)
Packit 8f70b4
                goto nospace2;
Packit 8f70b4
              pglob->gl_pathv = new_gl_pathv;
Packit 8f70b4
Packit 8f70b4
              pglob->gl_pathv[newcount] = strdup (pattern);
Packit 8f70b4
              if (pglob->gl_pathv[newcount] == NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  globfree (&dirs);
Packit 8f70b4
                  globfree (pglob);
Packit 8f70b4
                  pglob->gl_pathc = 0;
Packit 8f70b4
                  retval = GLOB_NOSPACE;
Packit 8f70b4
                  goto out;
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              ++pglob->gl_pathc;
Packit 8f70b4
              ++newcount;
Packit 8f70b4
Packit 8f70b4
              pglob->gl_pathv[newcount] = NULL;
Packit 8f70b4
              pglob->gl_flags = flags;
Packit 8f70b4
            }
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              globfree (&dirs);
Packit 8f70b4
              retval = GLOB_NOMATCH;
Packit 8f70b4
              goto out;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      globfree (&dirs);
Packit 8f70b4
    }
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      size_t old_pathc = pglob->gl_pathc;
Packit 8f70b4
      int orig_flags = flags;
Packit 8f70b4
Packit 8f70b4
      if (meta & GLOBPAT_BACKSLASH)
Packit 8f70b4
        {
Packit 8f70b4
          char *p = strchr (dirname, '\\'), *q;
Packit 8f70b4
          /* We need to unescape the dirname string.  It is certainly
Packit 8f70b4
             allocated by alloca, as otherwise filename would be NULL
Packit 8f70b4
             or dirname wouldn't contain backslashes.  */
Packit 8f70b4
          q = p;
Packit 8f70b4
          do
Packit 8f70b4
            {
Packit 8f70b4
              if (*p == '\\')
Packit 8f70b4
                {
Packit 8f70b4
                  *q = *++p;
Packit 8f70b4
                  --dirlen;
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                *q = *p;
Packit 8f70b4
              ++q;
Packit 8f70b4
            }
Packit 8f70b4
          while (*p++ != '\0');
Packit 8f70b4
          dirname_modified = 1;
Packit 8f70b4
        }
Packit 8f70b4
      if (dirname_modified)
Packit 8f70b4
        flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
Packit 8f70b4
      status = glob_in_dir (filename, dirname, flags, errfunc, pglob,
Packit 8f70b4
                            alloca_used);
Packit 8f70b4
      if (status != 0)
Packit 8f70b4
        {
Packit 8f70b4
          if (status == GLOB_NOMATCH && flags != orig_flags
Packit 8f70b4
              && pglob->gl_pathc + pglob->gl_offs == oldcount)
Packit 8f70b4
            {
Packit 8f70b4
              /* Make sure globfree (&dirs); is a nop.  */
Packit 8f70b4
              dirs.gl_pathv = NULL;
Packit 8f70b4
              flags = orig_flags;
Packit 8f70b4
              goto no_matches;
Packit 8f70b4
            }
Packit 8f70b4
          retval = status;
Packit 8f70b4
          goto out;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (dirlen > 0)
Packit 8f70b4
        {
Packit 8f70b4
          /* Stick the directory on the front of each name.  */
Packit 8f70b4
          if (prefix_array (dirname,
Packit 8f70b4
                            &pglob->gl_pathv[old_pathc + pglob->gl_offs],
Packit 8f70b4
                            pglob->gl_pathc - old_pathc))
Packit 8f70b4
            {
Packit 8f70b4
              globfree (pglob);
Packit 8f70b4
              pglob->gl_pathc = 0;
Packit 8f70b4
              retval = GLOB_NOSPACE;
Packit 8f70b4
              goto out;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (flags & GLOB_MARK)
Packit 8f70b4
    {
Packit 8f70b4
      /* Append slashes to directory names.  */
Packit 8f70b4
      size_t i;
Packit 8f70b4
Packit 8f70b4
      for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
Packit 8f70b4
        if (is_dir (pglob->gl_pathv[i], flags, pglob))
Packit 8f70b4
          {
Packit 8f70b4
            size_t len = strlen (pglob->gl_pathv[i]) + 2;
Packit 8f70b4
            char *new = realloc (pglob->gl_pathv[i], len);
Packit 8f70b4
            if (new == NULL)
Packit 8f70b4
              {
Packit 8f70b4
                globfree (pglob);
Packit 8f70b4
                pglob->gl_pathc = 0;
Packit 8f70b4
                retval = GLOB_NOSPACE;
Packit 8f70b4
                goto out;
Packit 8f70b4
              }
Packit 8f70b4
            strcpy (&new[len - 2], "/");
Packit 8f70b4
            pglob->gl_pathv[i] = new;
Packit 8f70b4
          }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (!(flags & GLOB_NOSORT))
Packit 8f70b4
    {
Packit 8f70b4
      /* Sort the vector.  */
Packit 8f70b4
      qsort (&pglob->gl_pathv[oldcount],
Packit 8f70b4
             pglob->gl_pathc + pglob->gl_offs - oldcount,
Packit 8f70b4
             sizeof (char *), collated_compare);
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
 out:
Packit 8f70b4
  if (__glibc_unlikely (malloc_dirname))
Packit 8f70b4
    free (dirname);
Packit 8f70b4
Packit 8f70b4
  return retval;
Packit 8f70b4
}
Packit 8f70b4
#if defined _LIBC && !defined glob
Packit 8f70b4
libc_hidden_def (glob)
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* Do a collated comparison of A and B.  */
Packit 8f70b4
static int
Packit 8f70b4
collated_compare (const void *a, const void *b)
Packit 8f70b4
{
Packit 8f70b4
  char *const *ps1 = a; char *s1 = *ps1;
Packit 8f70b4
  char *const *ps2 = b; char *s2 = *ps2;
Packit 8f70b4
Packit 8f70b4
  if (s1 == s2)
Packit 8f70b4
    return 0;
Packit 8f70b4
  if (s1 == NULL)
Packit 8f70b4
    return 1;
Packit 8f70b4
  if (s2 == NULL)
Packit 8f70b4
    return -1;
Packit 8f70b4
  return strcoll (s1, s2);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
Packit 8f70b4
   elements in place.  Return nonzero if out of memory, zero if successful.
Packit 8f70b4
   A slash is inserted between DIRNAME and each elt of ARRAY,
Packit 8f70b4
   unless DIRNAME is just "/".  Each old element of ARRAY is freed.  */
Packit 8f70b4
static int
Packit 8f70b4
prefix_array (const char *dirname, char **array, size_t n)
Packit 8f70b4
{
Packit 8f70b4
  size_t i;
Packit 8f70b4
  size_t dirlen = strlen (dirname);
Packit 8f70b4
  char dirsep_char = '/';
Packit 8f70b4
Packit 8f70b4
  if (dirlen == 1 && dirname[0] == '/')
Packit 8f70b4
    /* DIRNAME is just "/", so normal prepending would get us "//foo".
Packit 8f70b4
       We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
Packit 8f70b4
    dirlen = 0;
Packit 8f70b4
Packit 8f70b4
#if defined __MSDOS__ || defined WINDOWS32
Packit 8f70b4
  if (dirlen > 1)
Packit 8f70b4
    {
Packit 8f70b4
      if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
Packit 8f70b4
        /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
Packit 8f70b4
        --dirlen;
Packit 8f70b4
      else if (dirname[dirlen - 1] == ':')
Packit 8f70b4
        {
Packit 8f70b4
          /* DIRNAME is "d:".  Use ':' instead of '/'.  */
Packit 8f70b4
          --dirlen;
Packit 8f70b4
          dirsep_char = ':';
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
  for (i = 0; i < n; ++i)
Packit 8f70b4
    {
Packit 8f70b4
      size_t eltlen = strlen (array[i]) + 1;
Packit 8f70b4
      char *new = malloc (dirlen + 1 + eltlen);
Packit 8f70b4
      if (new == NULL)
Packit 8f70b4
        {
Packit 8f70b4
          while (i > 0)
Packit 8f70b4
            free (array[--i]);
Packit 8f70b4
          return 1;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      {
Packit 8f70b4
        char *endp = mempcpy (new, dirname, dirlen);
Packit 8f70b4
        *endp++ = dirsep_char;
Packit 8f70b4
        mempcpy (endp, array[i], eltlen);
Packit 8f70b4
      }
Packit 8f70b4
      free (array[i]);
Packit 8f70b4
      array[i] = new;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
/* Like 'glob', but PATTERN is a final pathname component,
Packit 8f70b4
   and matches are searched for in DIRECTORY.
Packit 8f70b4
   The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
Packit 8f70b4
   The GLOB_APPEND flag is assumed to be set (always appends).  */
Packit 8f70b4
static int
Packit 8f70b4
glob_in_dir (const char *pattern, const char *directory, int flags,
Packit 8f70b4
             int (*errfunc) (const char *, int),
Packit 8f70b4
             glob_t *pglob, size_t alloca_used)
Packit 8f70b4
{
Packit 8f70b4
  size_t dirlen = strlen (directory);
Packit 8f70b4
  void *stream = NULL;
Packit 8f70b4
# define GLOBNAMES_MEMBERS(nnames) \
Packit 8f70b4
    struct globnames *next; size_t count; char *name[nnames];
Packit 8f70b4
  struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
Packit 8f70b4
  struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
Packit 8f70b4
  struct globnames *init_names = (struct globnames *) &init_names_buf;
Packit 8f70b4
  struct globnames *names = init_names;
Packit 8f70b4
  struct globnames *names_alloca = init_names;
Packit 8f70b4
  size_t nfound = 0;
Packit 8f70b4
  size_t cur = 0;
Packit 8f70b4
  int meta;
Packit 8f70b4
  int save;
Packit 8f70b4
  int result;
Packit 8f70b4
Packit 8f70b4
  alloca_used += sizeof init_names_buf;
Packit 8f70b4
Packit 8f70b4
  init_names->next = NULL;
Packit 8f70b4
  init_names->count = ((sizeof init_names_buf
Packit 8f70b4
                        - offsetof (struct globnames, name))
Packit 8f70b4
                       / sizeof init_names->name[0]);
Packit 8f70b4
Packit 8f70b4
  meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
Packit 8f70b4
  if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
Packit 8f70b4
    {
Packit 8f70b4
      /* We need not do any tests.  The PATTERN contains no meta
Packit 8f70b4
         characters and we must not return an error therefore the
Packit 8f70b4
         result will always contain exactly one name.  */
Packit 8f70b4
      flags |= GLOB_NOCHECK;
Packit 8f70b4
    }
Packit 8f70b4
  else if (meta == GLOBPAT_NONE)
Packit 8f70b4
    {
Packit 8f70b4
      union
Packit 8f70b4
      {
Packit 8f70b4
        struct stat st;
Packit 8f70b4
        struct_stat64 st64;
Packit 8f70b4
      } ust;
Packit 8f70b4
      size_t patlen = strlen (pattern);
Packit 8f70b4
      size_t fullsize;
Packit 8f70b4
      bool alloca_fullname
Packit 8f70b4
        = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
Packit 8f70b4
           && glob_use_alloca (alloca_used, fullsize));
Packit 8f70b4
      char *fullname;
Packit 8f70b4
      if (alloca_fullname)
Packit 8f70b4
        fullname = alloca_account (fullsize, alloca_used);
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          fullname = malloc (fullsize);
Packit 8f70b4
          if (fullname == NULL)
Packit 8f70b4
            return GLOB_NOSPACE;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
Packit 8f70b4
                        "/", 1),
Packit 8f70b4
               pattern, patlen + 1);
Packit 8f70b4
      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
Packit 8f70b4
            ? (*pglob->gl_lstat) (fullname, &ust.st)
Packit 8f70b4
            : __lstat64 (fullname, &ust.st64))
Packit 8f70b4
           == 0)
Packit 8f70b4
          || errno == EOVERFLOW)
Packit 8f70b4
        /* We found this file to be existing.  Now tell the rest
Packit 8f70b4
           of the function to copy this name into the result.  */
Packit 8f70b4
        flags |= GLOB_NOCHECK;
Packit 8f70b4
Packit 8f70b4
      if (__glibc_unlikely (!alloca_fullname))
Packit 8f70b4
        free (fullname);
Packit 8f70b4
    }
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
Packit 8f70b4
                ? (*pglob->gl_opendir) (directory)
Packit 8f70b4
                : opendir (directory));
Packit 8f70b4
      if (stream == NULL)
Packit 8f70b4
        {
Packit 8f70b4
          if (errno != ENOTDIR
Packit 8f70b4
              && ((errfunc != NULL && (*errfunc) (directory, errno))
Packit 8f70b4
                  || (flags & GLOB_ERR)))
Packit 8f70b4
            return GLOB_ABORTED;
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
Packit 8f70b4
                           | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
Packit 8f70b4
          flags |= GLOB_MAGCHAR;
Packit 8f70b4
Packit 8f70b4
          while (1)
Packit 8f70b4
            {
Packit 8f70b4
              struct readdir_result d;
Packit 8f70b4
              {
Packit 8f70b4
                if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
Packit 8f70b4
                  d = convert_dirent (GL_READDIR (pglob, stream));
Packit 8f70b4
                else
Packit 8f70b4
                  {
Packit 8f70b4
#ifdef COMPILE_GLOB64
Packit 8f70b4
                    d = convert_dirent (__readdir (stream));
Packit 8f70b4
#else
Packit 8f70b4
                    d = convert_dirent64 (__readdir64 (stream));
Packit 8f70b4
#endif
Packit 8f70b4
                  }
Packit 8f70b4
              }
Packit 8f70b4
              if (d.name == NULL)
Packit 8f70b4
                break;
Packit 8f70b4
Packit 8f70b4
              /* If we shall match only directories use the information
Packit 8f70b4
                 provided by the dirent call if possible.  */
Packit 8f70b4
              if (flags & GLOB_ONLYDIR)
Packit 8f70b4
                switch (readdir_result_type (d))
Packit 8f70b4
                  {
Packit 8f70b4
                  case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
Packit 8f70b4
                  default: continue;
Packit 8f70b4
                  }
Packit 8f70b4
Packit 8f70b4
              if (fnmatch (pattern, d.name, fnm_flags) == 0)
Packit 8f70b4
                {
Packit 8f70b4
                  if (cur == names->count)
Packit 8f70b4
                    {
Packit 8f70b4
                      struct globnames *newnames;
Packit 8f70b4
                      size_t count = names->count * 2;
Packit 8f70b4
                      size_t nameoff = offsetof (struct globnames, name);
Packit 8f70b4
                      size_t size = FLEXSIZEOF (struct globnames, name,
Packit 8f70b4
                                                count * sizeof (char *));
Packit 8f70b4
                      if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
Packit 8f70b4
                          < names->count)
Packit 8f70b4
                        goto memory_error;
Packit 8f70b4
                      if (glob_use_alloca (alloca_used, size))
Packit 8f70b4
                        newnames = names_alloca
Packit 8f70b4
                          = alloca_account (size, alloca_used);
Packit 8f70b4
                      else if ((newnames = malloc (size))
Packit 8f70b4
                               == NULL)
Packit 8f70b4
                        goto memory_error;
Packit 8f70b4
                      newnames->count = count;
Packit 8f70b4
                      newnames->next = names;
Packit 8f70b4
                      names = newnames;
Packit 8f70b4
                      cur = 0;
Packit 8f70b4
                    }
Packit 8f70b4
                  names->name[cur] = strdup (d.name);
Packit 8f70b4
                  if (names->name[cur] == NULL)
Packit 8f70b4
                    goto memory_error;
Packit 8f70b4
                  ++cur;
Packit 8f70b4
                  ++nfound;
Packit 8f70b4
                  if (SIZE_MAX - pglob->gl_offs <= nfound)
Packit 8f70b4
                    goto memory_error;
Packit 8f70b4
                }
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (nfound == 0 && (flags & GLOB_NOCHECK))
Packit 8f70b4
    {
Packit 8f70b4
      size_t len = strlen (pattern);
Packit 8f70b4
      nfound = 1;
Packit 8f70b4
      names->name[cur] = malloc (len + 1);
Packit 8f70b4
      if (names->name[cur] == NULL)
Packit 8f70b4
        goto memory_error;
Packit 8f70b4
      *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  result = GLOB_NOMATCH;
Packit 8f70b4
  if (nfound != 0)
Packit 8f70b4
    {
Packit 8f70b4
      char **new_gl_pathv;
Packit 8f70b4
      result = 0;
Packit 8f70b4
Packit 8f70b4
      if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
Packit 8f70b4
          < pglob->gl_offs + nfound + 1)
Packit 8f70b4
        goto memory_error;
Packit 8f70b4
Packit 8f70b4
      new_gl_pathv
Packit 8f70b4
        = realloc (pglob->gl_pathv,
Packit 8f70b4
                   (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
Packit 8f70b4
                    * sizeof (char *));
Packit 8f70b4
Packit 8f70b4
      if (new_gl_pathv == NULL)
Packit 8f70b4
        {
Packit 8f70b4
        memory_error:
Packit 8f70b4
          while (1)
Packit 8f70b4
            {
Packit 8f70b4
              struct globnames *old = names;
Packit 8f70b4
              for (size_t i = 0; i < cur; ++i)
Packit 8f70b4
                free (names->name[i]);
Packit 8f70b4
              names = names->next;
Packit 8f70b4
              /* NB: we will not leak memory here if we exit without
Packit 8f70b4
                 freeing the current block assigned to OLD.  At least
Packit 8f70b4
                 the very first block is always allocated on the stack
Packit 8f70b4
                 and this is the block assigned to OLD here.  */
Packit 8f70b4
              if (names == NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  assert (old == init_names);
Packit 8f70b4
                  break;
Packit 8f70b4
                }
Packit 8f70b4
              cur = names->count;
Packit 8f70b4
              if (old == names_alloca)
Packit 8f70b4
                names_alloca = names;
Packit 8f70b4
              else
Packit 8f70b4
                free (old);
Packit 8f70b4
            }
Packit 8f70b4
          result = GLOB_NOSPACE;
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          while (1)
Packit 8f70b4
            {
Packit 8f70b4
              struct globnames *old = names;
Packit 8f70b4
              for (size_t i = 0; i < cur; ++i)
Packit 8f70b4
                new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
Packit 8f70b4
                  = names->name[i];
Packit 8f70b4
              names = names->next;
Packit 8f70b4
              /* NB: we will not leak memory here if we exit without
Packit 8f70b4
                 freeing the current block assigned to OLD.  At least
Packit 8f70b4
                 the very first block is always allocated on the stack
Packit 8f70b4
                 and this is the block assigned to OLD here.  */
Packit 8f70b4
              if (names == NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  assert (old == init_names);
Packit 8f70b4
                  break;
Packit 8f70b4
                }
Packit 8f70b4
              cur = names->count;
Packit 8f70b4
              if (old == names_alloca)
Packit 8f70b4
                names_alloca = names;
Packit 8f70b4
              else
Packit 8f70b4
                free (old);
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          pglob->gl_pathv = new_gl_pathv;
Packit 8f70b4
Packit 8f70b4
          pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
Packit 8f70b4
Packit 8f70b4
          pglob->gl_flags = flags;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (stream != NULL)
Packit 8f70b4
    {
Packit 8f70b4
      save = errno;
Packit 8f70b4
      if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
Packit 8f70b4
        (*pglob->gl_closedir) (stream);
Packit 8f70b4
      else
Packit 8f70b4
        closedir (stream);
Packit 8f70b4
      __set_errno (save);
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  return result;
Packit 8f70b4
}