Blame lib/glob.c

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