maint: update copyright
[gnulib.git] / lib / glob.c
index a0af922..fcdee0b 100644 (file)
@@ -1,22 +1,23 @@
-/* Copyright (C) 1991-2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2014 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    This file is part of the GNU C Library.
 
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
 
-   The GNU C Library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
 
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifndef _LIBC
 
 #ifndef _LIBC
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   optimizes away the pattern == NULL || pglob == NULL tests below.  */
+# define _GL_ARG_NONNULL(params)
 # include <config.h>
 #endif
 
 # include <config.h>
 #endif
 
@@ -31,7 +32,9 @@
 /* #define NDEBUG 1 */
 #include <assert.h>
 
 /* #define NDEBUG 1 */
 #include <assert.h>
 
-#include <stdio.h>             /* Needed on stupid SunOS for assert.  */
+#include <stdbool.h>
+
+#include <stdio.h>              /* Needed on stupid SunOS for assert.  */
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
 
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
 
 # define POSIX
 #endif
 
 # define POSIX
 #endif
 
-#include <pwd.h>
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS32
+#endif
+
+#ifndef WINDOWS32
+# include <pwd.h>
+#endif
 
 #include <errno.h>
 #ifndef __set_errno
 
 #include <errno.h>
 #ifndef __set_errno
 #endif
 
 /* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
 #endif
 
 /* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
-   if the `d_type' member for `struct dirent' is available.
+   if the 'd_type' member for 'struct dirent' is available.
    HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB.  */
 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
 /* True if the directory entry D must be of type T.  */
    HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB.  */
 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
 /* True if the directory entry D must be of type T.  */
-# define DIRENT_MUST_BE(d, t)  ((d)->d_type == (t))
+# define DIRENT_MUST_BE(d, t)   ((d)->d_type == (t))
 
 /* True if the directory entry D might be a symbolic link.  */
 # define DIRENT_MIGHT_BE_SYMLINK(d) \
     ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
 
 /* True if the directory entry D might be a directory.  */
 
 /* True if the directory entry D might be a symbolic link.  */
 # define DIRENT_MIGHT_BE_SYMLINK(d) \
     ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
 
 /* True if the directory entry D might be a directory.  */
-# define DIRENT_MIGHT_BE_DIR(d)         \
+# define DIRENT_MIGHT_BE_DIR(d)  \
     ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
 
 #else /* !HAVE_D_TYPE */
     ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
 
 #else /* !HAVE_D_TYPE */
-# define DIRENT_MUST_BE(d, t)          false
-# define DIRENT_MIGHT_BE_SYMLINK(d)    true
-# define DIRENT_MIGHT_BE_DIR(d)                true
+# define DIRENT_MUST_BE(d, t)           false
+# define DIRENT_MIGHT_BE_SYMLINK(d)     true
+# define DIRENT_MIGHT_BE_DIR(d)         true
 #endif /* HAVE_D_TYPE */
 
 #endif /* HAVE_D_TYPE */
 
-/* If the system has the `struct dirent64' type we use it internally.  */
+/* If the system has the 'struct dirent64' type we use it internally.  */
 #if defined _LIBC && !defined COMPILE_GLOB64
 # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
 #  define CONVERT_D_INO(d64, d32)
 #if defined _LIBC && !defined COMPILE_GLOB64
 # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
 #  define CONVERT_D_INO(d64, d32)
 # endif
 
 # define CONVERT_DIRENT_DIRENT64(d64, d32) \
 # endif
 
 # define CONVERT_DIRENT_DIRENT64(d64, d32) \
-  memcpy ((d64)->d_name, (d32)->d_name, _D_EXACT_NAMLEN (d32) + 1);          \
-  CONVERT_D_INO (d64, d32)                                                   \
+  memcpy ((d64)->d_name, (d32)->d_name, _D_EXACT_NAMLEN (d32) + 1);           \
+  CONVERT_D_INO (d64, d32)                                                    \
   CONVERT_D_TYPE (d64, d32)
 #endif
 
   CONVERT_D_TYPE (d64, d32)
 #endif
 
 # ifndef __stat64
 #  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
 # endif
 # ifndef __stat64
 #  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
 # endif
-# define struct_stat64         struct stat64
+# define struct_stat64          struct stat64
 #else /* !_LIBC */
 #else /* !_LIBC */
-# define __stat64(fname, buf)  stat (fname, buf)
-# define struct_stat64         struct stat
-# define __stat(fname, buf)    stat (fname, buf)
-# define __alloca              alloca
-# define __readdir             readdir
-# define __readdir64           readdir64
-# define __glob_pattern_p      glob_pattern_p
+# define __stat64(fname, buf)   stat (fname, buf)
+# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
+# define struct_stat64          struct stat
+# define __alloca               alloca
+# define __readdir              readdir
+# define __glob_pattern_p       glob_pattern_p
 #endif /* _LIBC */
 
 #endif /* _LIBC */
 
-#include <stdbool.h>
 #include <fnmatch.h>
 
 #ifdef _SC_GETPW_R_SIZE_MAX
 #include <fnmatch.h>
 
 #ifdef _SC_GETPW_R_SIZE_MAX
-# define GETPW_R_SIZE_MAX()    sysconf (_SC_GETPW_R_SIZE_MAX)
+# define GETPW_R_SIZE_MAX()     sysconf (_SC_GETPW_R_SIZE_MAX)
 #else
 #else
-# define GETPW_R_SIZE_MAX()    (-1)
+# define GETPW_R_SIZE_MAX()     (-1)
 #endif
 #ifdef _SC_LOGIN_NAME_MAX
 #endif
 #ifdef _SC_LOGIN_NAME_MAX
-# define GET_LOGIN_NAME_MAX()  sysconf (_SC_LOGIN_NAME_MAX)
+# define GET_LOGIN_NAME_MAX()   sysconf (_SC_LOGIN_NAME_MAX)
 #else
 #else
-# define GET_LOGIN_NAME_MAX()  (-1)
+# define GET_LOGIN_NAME_MAX()   (-1)
 #endif
 \f
 #endif
 \f
-static const char *next_brace_sub (const char *begin, int flags) __THROW;
+static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
 #endif /* !defined _LIBC || !defined GLOB_ONLY_P */
 
 
 #endif /* !defined _LIBC || !defined GLOB_ONLY_P */
 
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+#ifndef __attribute_noinline__
+# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1)
+#  define __attribute_noinline__ /* Ignore */
+#else
+#  define __attribute_noinline__ __attribute__ ((__noinline__))
+# endif
+#endif
+
+#if ! defined __builtin_expect && __GNUC__ < 3
+# define __builtin_expect(expr, expected) (expr)
+#endif
+
+#ifndef _LIBC
 /* The results of opendir() in this file are not used with dirfd and fchdir,
 /* The results of opendir() in this file are not used with dirfd and fchdir,
-   therefore save some unnecessary work in fchdir.c.  */
-#undef opendir
-#undef closedir
+   and we do not leak fds to any single-threaded code that could use stdio,
+   therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
+   FIXME - if the kernel ever adds support for multi-thread safety for
+   avoiding standard fds, then we should use opendir_safer.  */
+# undef opendir
+# undef closedir
+
+# if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+   and a page size can be as small as 4096 bytes.  So we cannot safely
+   allocate anything larger than 4096 bytes.  Also care for the possibility
+   of a few compiler-allocated temporary stack slots.  */
+#  define __libc_use_alloca(n) ((n) < 4032)
+# else
+/* alloca is implemented with malloc, so just use malloc.  */
+#  define __libc_use_alloca(n) 0
+# endif
+#endif
 
 static int glob_in_dir (const char *pattern, const char *directory,
 
 static int glob_in_dir (const char *pattern, const char *directory,
-                       int flags, int (*errfunc) (const char *, int),
-                       glob_t *pglob);
+                        int flags, int (*errfunc) (const char *, int),
+                        glob_t *pglob);
+extern int __glob_pattern_type (const char *pattern, int quote)
+    attribute_hidden;
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
-static int prefix_array (const char *prefix, char **array, size_t n) __THROW;
-static int collated_compare (const void *, const void *) __THROW;
+static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
+static int collated_compare (const void *, const void *) __THROWNL;
 
 
 /* Find the end of the sub-pattern in a brace expression.  */
 
 
 /* Find the end of the sub-pattern in a brace expression.  */
@@ -181,17 +222,17 @@ next_brace_sub (const char *cp, int flags)
   while (*cp != '\0')
     if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
       {
   while (*cp != '\0')
     if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
       {
-       if (*++cp == '\0')
-         break;
-       ++cp;
+        if (*++cp == '\0')
+          break;
+        ++cp;
       }
     else
       {
       }
     else
       {
-       if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
-         break;
+        if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+          break;
 
 
-       if (*cp++ == '{')
-         depth++;
+        if (*cp++ == '{')
+          depth++;
       }
 
   return *cp != '\0' ? cp : NULL;
       }
 
   return *cp != '\0' ? cp : NULL;
@@ -203,25 +244,28 @@ next_brace_sub (const char *cp, int flags)
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
    it is called with the pathname that caused the error, and the
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
    it is called with the pathname that caused the error, and the
-   `errno' value from the failing call; if it returns non-zero
-   `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+   'errno' value from the failing call; if it returns non-zero
+   'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
-   Otherwise, `glob' returns zero.  */
+   Otherwise, 'glob' returns zero.  */
 int
 #ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
 #endif
 glob (pattern, flags, errfunc, pglob)
 int
 #ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
 #endif
 glob (pattern, flags, errfunc, pglob)
-     const char *pattern;
+     const char * restrict pattern;
      int flags;
      int (*errfunc) (const char *, int);
      int flags;
      int (*errfunc) (const char *, int);
-     glob_t *pglob;
+     glob_t * restrict pglob;
 {
   const char *filename;
   const char *dirname;
   size_t dirlen;
   int status;
   size_t oldcount;
 {
   const char *filename;
   const char *dirname;
   size_t dirlen;
   int status;
   size_t oldcount;
+  int meta;
+  int dirname_modified;
+  glob_t dirs;
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
@@ -230,7 +274,7 @@ glob (pattern, flags, errfunc, pglob)
     }
 
   if (!(flags & GLOB_DOOFFS))
     }
 
   if (!(flags & GLOB_DOOFFS))
-    /* Have to do this so `globfree' knows where to start freeing.  It
+    /* Have to do this so 'globfree' knows where to start freeing.  It
        also makes all the code that uses gl_offs simpler. */
     pglob->gl_offs = 0;
 
        also makes all the code that uses gl_offs simpler. */
     pglob->gl_offs = 0;
 
@@ -239,185 +283,188 @@ glob (pattern, flags, errfunc, pglob)
       const char *begin;
 
       if (flags & GLOB_NOESCAPE)
       const char *begin;
 
       if (flags & GLOB_NOESCAPE)
-       begin = strchr (pattern, '{');
+        begin = strchr (pattern, '{');
       else
       else
-       {
-         begin = pattern;
-         while (1)
-           {
-             if (*begin == '\0')
-               {
-                 begin = NULL;
-                 break;
-               }
-
-             if (*begin == '\\' && begin[1] != '\0')
-               ++begin;
-             else if (*begin == '{')
-               break;
-
-             ++begin;
-           }
-       }
+        {
+          begin = pattern;
+          while (1)
+            {
+              if (*begin == '\0')
+                {
+                  begin = NULL;
+                  break;
+                }
+
+              if (*begin == '\\' && begin[1] != '\0')
+                ++begin;
+              else if (*begin == '{')
+                break;
+
+              ++begin;
+            }
+        }
 
       if (begin != NULL)
 
       if (begin != NULL)
-       {
-         /* Allocate working buffer large enough for our work.  Note that
-           we have at least an opening and closing brace.  */
-         size_t firstc;
-         char *alt_start;
-         const char *p;
-         const char *next;
-         const char *rest;
-         size_t rest_len;
+        {
+          /* Allocate working buffer large enough for our work.  Note that
+            we have at least an opening and closing brace.  */
+          size_t firstc;
+          char *alt_start;
+          const char *p;
+          const char *next;
+          const char *rest;
+          size_t rest_len;
 #ifdef __GNUC__
 #ifdef __GNUC__
-         char onealt[strlen (pattern) - 1];
+          char onealt[strlen (pattern) - 1];
 #else
 #else
-         char *onealt = malloc (strlen (pattern) - 1);
-         if (onealt == NULL)
-           {
-             if (!(flags & GLOB_APPEND))
-               {
-                 pglob->gl_pathc = 0;
-                 pglob->gl_pathv = NULL;
-               }
-             return GLOB_NOSPACE;
-           }
+          char *onealt = malloc (strlen (pattern) - 1);
+          if (onealt == NULL)
+            {
+              if (!(flags & GLOB_APPEND))
+                {
+                  pglob->gl_pathc = 0;
+                  pglob->gl_pathv = NULL;
+                }
+              return GLOB_NOSPACE;
+            }
 #endif
 
 #endif
 
-         /* We know the prefix for all sub-patterns.  */
-         alt_start = mempcpy (onealt, pattern, begin - pattern);
+          /* We know the prefix for all sub-patterns.  */
+          alt_start = mempcpy (onealt, pattern, begin - pattern);
 
 
-         /* Find the first sub-pattern and at the same time find the
-            rest after the closing brace.  */
-         next = next_brace_sub (begin + 1, flags);
-         if (next == NULL)
-           {
-             /* It is an invalid expression.  */
+          /* Find the first sub-pattern and at the same time find the
+             rest after the closing brace.  */
+          next = next_brace_sub (begin + 1, flags);
+          if (next == NULL)
+            {
+              /* It is an invalid expression.  */
 #ifndef __GNUC__
 #ifndef __GNUC__
-             free (onealt);
+              free (onealt);
 #endif
 #endif
-             return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
-           }
-
-         /* Now find the end of the whole brace expression.  */
-         rest = next;
-         while (*rest != '}')
-           {
-             rest = next_brace_sub (rest + 1, flags);
-             if (rest == NULL)
-               {
-                 /* It is an invalid expression.  */
+              return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+            }
+
+          /* Now find the end of the whole brace expression.  */
+          rest = next;
+          while (*rest != '}')
+            {
+              rest = next_brace_sub (rest + 1, flags);
+              if (rest == NULL)
+                {
+                  /* It is an invalid expression.  */
 #ifndef __GNUC__
 #ifndef __GNUC__
-                 free (onealt);
+                  free (onealt);
 #endif
 #endif
-                 return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
-               }
-           }
-         /* Please note that we now can be sure the brace expression
-            is well-formed.  */
-         rest_len = strlen (++rest) + 1;
-
-         /* We have a brace expression.  BEGIN points to the opening {,
-            NEXT points past the terminator of the first element, and END
-            points past the final }.  We will accumulate result names from
-            recursive runs for each brace alternative in the buffer using
-            GLOB_APPEND.  */
-
-         if (!(flags & GLOB_APPEND))
-           {
-             /* This call is to set a new vector, so clear out the
-                vector so we can append to it.  */
-             pglob->gl_pathc = 0;
-             pglob->gl_pathv = NULL;
-           }
-         firstc = pglob->gl_pathc;
-
-         p = begin + 1;
-         while (1)
-           {
-             int result;
-
-             /* Construct the new glob expression.  */
-             mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
-
-             result = glob (onealt,
-                            ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
-                             | GLOB_APPEND), errfunc, pglob);
-
-             /* If we got an error, return it.  */
-             if (result && result != GLOB_NOMATCH)
-               {
+                  return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+                }
+            }
+          /* Please note that we now can be sure the brace expression
+             is well-formed.  */
+          rest_len = strlen (++rest) + 1;
+
+          /* We have a brace expression.  BEGIN points to the opening {,
+             NEXT points past the terminator of the first element, and END
+             points past the final }.  We will accumulate result names from
+             recursive runs for each brace alternative in the buffer using
+             GLOB_APPEND.  */
+
+          if (!(flags & GLOB_APPEND))
+            {
+              /* This call is to set a new vector, so clear out the
+                 vector so we can append to it.  */
+              pglob->gl_pathc = 0;
+              pglob->gl_pathv = NULL;
+            }
+          firstc = pglob->gl_pathc;
+
+          p = begin + 1;
+          while (1)
+            {
+              int result;
+
+              /* Construct the new glob expression.  */
+              mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+              result = glob (onealt,
+                             ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+                              | GLOB_APPEND), errfunc, pglob);
+
+              /* If we got an error, return it.  */
+              if (result && result != GLOB_NOMATCH)
+                {
 #ifndef __GNUC__
 #ifndef __GNUC__
-                 free (onealt);
+                  free (onealt);
 #endif
 #endif
-                 if (!(flags & GLOB_APPEND))
-                   {
-                     globfree (pglob);
-                     pglob->gl_pathc = 0;
-                   }
-                 return result;
-               }
-
-             if (*next == '}')
-               /* We saw the last entry.  */
-               break;
-
-             p = next + 1;
-             next = next_brace_sub (p, flags);
-             assert (next != NULL);
-           }
+                  if (!(flags & GLOB_APPEND))
+                    {
+                      globfree (pglob);
+                      pglob->gl_pathc = 0;
+                    }
+                  return result;
+                }
+
+              if (*next == '}')
+                /* We saw the last entry.  */
+                break;
+
+              p = next + 1;
+              next = next_brace_sub (p, flags);
+              assert (next != NULL);
+            }
 
 #ifndef __GNUC__
 
 #ifndef __GNUC__
-         free (onealt);
+          free (onealt);
 #endif
 
 #endif
 
-         if (pglob->gl_pathc != firstc)
-           /* We found some entries.  */
-           return 0;
-         else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
-           return GLOB_NOMATCH;
-       }
+          if (pglob->gl_pathc != firstc)
+            /* We found some entries.  */
+            return 0;
+          else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+            return GLOB_NOMATCH;
+        }
     }
 
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
 #if defined __MSDOS__ || defined WINDOWS32
     }
 
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
 #if defined __MSDOS__ || defined WINDOWS32
-  /* The case of "d:pattern".  Since `:' is not allowed in
+  /* The case of "d:pattern".  Since ':' is not allowed in
      file names, we can safely assume that wherever it
      happens in pattern, it signals the filename part.  This
      is so we could some day support patterns like "[a-z]:foo".  */
   if (filename == NULL)
     filename = strchr (pattern, ':');
 #endif /* __MSDOS__ || WINDOWS32 */
      file names, we can safely assume that wherever it
      happens in pattern, it signals the filename part.  This
      is so we could some day support patterns like "[a-z]:foo".  */
   if (filename == NULL)
     filename = strchr (pattern, ':');
 #endif /* __MSDOS__ || WINDOWS32 */
+  dirname_modified = 0;
   if (filename == NULL)
     {
       /* This can mean two things: a simple name or "~name".  The latter
   if (filename == NULL)
     {
       /* This can mean two things: a simple name or "~name".  The latter
-        case is nothing but a notation for a directory.  */
+         case is nothing but a notation for a directory.  */
       if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
       if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
-       {
-         dirname = pattern;
-         dirlen = strlen (pattern);
-
-         /* Set FILENAME to NULL as a special flag.  This is ugly but
-            other solutions would require much more code.  We test for
-            this special case below.  */
-         filename = NULL;
-       }
+        {
+          dirname = pattern;
+          dirlen = strlen (pattern);
+
+          /* Set FILENAME to NULL as a special flag.  This is ugly but
+             other solutions would require much more code.  We test for
+             this special case below.  */
+          filename = NULL;
+        }
       else
       else
-       {
-         filename = pattern;
+        {
+          filename = pattern;
 #ifdef _AMIGA
 #ifdef _AMIGA
-         dirname = "";
+          dirname = "";
 #else
 #else
-         dirname = ".";
+          dirname = ".";
 #endif
 #endif
-         dirlen = 0;
-       }
+          dirlen = 0;
+        }
     }
     }
-  else if (filename == pattern)
+  else if (filename == pattern
+           || (filename == pattern + 1 && pattern[0] == '\\'
+               && (flags & GLOB_NOESCAPE) == 0))
     {
     {
-      /* "/pattern".  */
+      /* "/pattern" or "\\/pattern".  */
       dirname = "/";
       dirlen = 1;
       ++filename;
       dirname = "/";
       dirlen = 1;
       ++filename;
@@ -428,21 +475,21 @@ glob (pattern, flags, errfunc, pglob)
       dirlen = filename - pattern;
 #if defined __MSDOS__ || defined WINDOWS32
       if (*filename == ':'
       dirlen = filename - pattern;
 #if defined __MSDOS__ || defined WINDOWS32
       if (*filename == ':'
-         || (filename > pattern + 1 && filename[-1] == ':'))
-       {
-         char *drive_spec;
-
-         ++dirlen;
-         drive_spec = __alloca (dirlen + 1);
-         *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
-         /* For now, disallow wildcards in the drive spec, to
-            prevent infinite recursion in glob.  */
-         if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
-           return GLOB_NOMATCH;
-         /* If this is "d:pattern", we need to copy `:' to DIRNAME
-            as well.  If it's "d:/pattern", don't remove the slash
-            from "d:/", since "d:" and "d:/" are not the same.*/
-       }
+          || (filename > pattern + 1 && filename[-1] == ':'))
+        {
+          char *drive_spec;
+
+          ++dirlen;
+          drive_spec = __alloca (dirlen + 1);
+          *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+          /* For now, disallow wildcards in the drive spec, to
+             prevent infinite recursion in glob.  */
+          if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+            return GLOB_NOMATCH;
+          /* If this is "d:pattern", we need to copy ':' to DIRNAME
+             as well.  If it's "d:/pattern", don't remove the slash
+             from "d:/", since "d:" and "d:/" are not the same.*/
+        }
 #endif
       newp = __alloca (dirlen + 1);
       *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
 #endif
       newp = __alloca (dirlen + 1);
       *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
@@ -452,18 +499,41 @@ glob (pattern, flags, errfunc, pglob)
       if (filename[0] == '\0'
 #if defined __MSDOS__ || defined WINDOWS32
           && dirname[dirlen - 1] != ':'
       if (filename[0] == '\0'
 #if defined __MSDOS__ || defined WINDOWS32
           && dirname[dirlen - 1] != ':'
-         && (dirlen < 3 || dirname[dirlen - 2] != ':'
-             || dirname[dirlen - 1] != '/')
+          && (dirlen < 3 || dirname[dirlen - 2] != ':'
+              || dirname[dirlen - 1] != '/')
 #endif
 #endif
-         && dirlen > 1)
-       /* "pattern/".  Expand "pattern", appending slashes.  */
-       {
-         int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
-         if (val == 0)
-           pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
-                              | (flags & GLOB_MARK));
-         return val;
-       }
+          && dirlen > 1)
+        /* "pattern/".  Expand "pattern", appending slashes.  */
+        {
+          int orig_flags = flags;
+          int val;
+          if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
+            {
+              /* "pattern\\/".  Remove the final backslash if it hasn't
+                 been quoted.  */
+              char *p = (char *) &dirname[dirlen - 1];
+
+              while (p > dirname && p[-1] == '\\') --p;
+              if ((&dirname[dirlen] - p) & 1)
+                {
+                  *(char *) &dirname[--dirlen] = '\0';
+                  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
+                }
+            }
+          val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+          if (val == 0)
+            pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+                               | (flags & GLOB_MARK));
+          else if (val == GLOB_NOMATCH && flags != orig_flags)
+            {
+              /* Make sure globfree (&dirs); is a nop.  */
+              dirs.gl_pathv = NULL;
+              flags = orig_flags;
+              oldcount = pglob->gl_pathc + pglob->gl_offs;
+              goto no_matches;
+            }
+          return val;
+        }
     }
 
   if (!(flags & GLOB_APPEND))
     }
 
   if (!(flags & GLOB_APPEND))
@@ -472,185 +542,251 @@ glob (pattern, flags, errfunc, pglob)
       if (!(flags & GLOB_DOOFFS))
         pglob->gl_pathv = NULL;
       else
       if (!(flags & GLOB_DOOFFS))
         pglob->gl_pathv = NULL;
       else
-       {
-         size_t i;
-         pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
-         if (pglob->gl_pathv == NULL)
-           return GLOB_NOSPACE;
-
-         for (i = 0; i <= pglob->gl_offs; ++i)
-           pglob->gl_pathv[i] = NULL;
-       }
+        {
+          size_t i;
+          pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
+          if (pglob->gl_pathv == NULL)
+            return GLOB_NOSPACE;
+
+          for (i = 0; i <= pglob->gl_offs; ++i)
+            pglob->gl_pathv[i] = NULL;
+        }
     }
 
   oldcount = pglob->gl_pathc + pglob->gl_offs;
 
   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
     {
     }
 
   oldcount = pglob->gl_pathc + pglob->gl_offs;
 
   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
     {
-      if (dirname[1] == '\0' || dirname[1] == '/')
-       {
-         /* Look up home directory.  */
-         const char *home_dir = getenv ("HOME");
+      if (dirname[1] == '\0' || dirname[1] == '/'
+          || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
+              && (dirname[2] == '\0' || dirname[2] == '/')))
+        {
+          /* Look up home directory.  */
+          const char *home_dir = getenv ("HOME");
 # ifdef _AMIGA
 # ifdef _AMIGA
-         if (home_dir == NULL || home_dir[0] == '\0')
-           home_dir = "SYS:";
+          if (home_dir == NULL || home_dir[0] == '\0')
+            home_dir = "SYS:";
 # else
 #  ifdef WINDOWS32
 # else
 #  ifdef WINDOWS32
-         if (home_dir == NULL || home_dir[0] == '\0')
-            home_dir = "c:/users/default"; /* poor default */
+          /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give preference
+             to HOME, because the user can change HOME.  */
+          if (home_dir == NULL || home_dir[0] == '\0')
+            {
+              const char *home_drive = getenv ("HOMEDRIVE");
+              const char *home_path = getenv ("HOMEPATH");
+
+              if (home_drive != NULL && home_path != NULL)
+                {
+                  size_t home_drive_len = strlen (home_drive);
+                  size_t home_path_len = strlen (home_path);
+                  char *mem = alloca (home_drive_len + home_path_len + 1);
+
+                  memcpy (mem, home_drive, home_drive_len);
+                  memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+                  home_dir = mem;
+                }
+              else
+                home_dir = "c:/users/default"; /* poor default */
+            }
 #  else
 #  else
-         if (home_dir == NULL || home_dir[0] == '\0')
-           {
-             int success;
-             char *name;
-             size_t buflen = GET_LOGIN_NAME_MAX () + 1;
-
-             if (buflen == 0)
-               /* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
-                  a moderate value.  */
-               buflen = 20;
-             name = __alloca (buflen);
-
-             success = getlogin_r (name, buflen) == 0;
-             if (success)
-               {
-                 struct passwd *p;
+          if (home_dir == NULL || home_dir[0] == '\0')
+            {
+              int success;
+              char *name;
+              size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+
+              if (buflen == 0)
+                /* 'sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
+                   a moderate value.  */
+                buflen = 20;
+              name = __alloca (buflen);
+
+              success = getlogin_r (name, buflen) == 0;
+              if (success)
+                {
+                  struct passwd *p;
 #   if defined HAVE_GETPWNAM_R || defined _LIBC
 #   if defined HAVE_GETPWNAM_R || defined _LIBC
-                 long int pwbuflen = GETPW_R_SIZE_MAX ();
-                 char *pwtmpbuf;
-                 struct passwd pwbuf;
-                 int save = errno;
+                  long int pwbuflen = GETPW_R_SIZE_MAX ();
+                  char *pwtmpbuf;
+                  struct passwd pwbuf;
+                  int save = errno;
 
 #    ifndef _LIBC
 
 #    ifndef _LIBC
-                 if (pwbuflen == -1)
-                   /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
-                      Try a moderate value.  */
-                   pwbuflen = 1024;
+                  if (pwbuflen == -1)
+                    /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+                       Try a moderate value.  */
+                    pwbuflen = 1024;
 #    endif
 #    endif
-                 pwtmpbuf = __alloca (pwbuflen);
-
-                 while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
-                        != 0)
-                   {
-                     if (errno != ERANGE)
-                       {
-                         p = NULL;
-                         break;
-                       }
+                  pwtmpbuf = __alloca (pwbuflen);
+
+                  while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+                         != 0)
+                    {
+                      if (errno != ERANGE)
+                        {
+                          p = NULL;
+                          break;
+                        }
 #    ifdef _LIBC
 #    ifdef _LIBC
-                     pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
-                                               2 * pwbuflen);
+                      pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+                                                2 * pwbuflen);
 #    else
 #    else
-                     pwbuflen *= 2;
-                     pwtmpbuf = __alloca (pwbuflen);
+                      pwbuflen *= 2;
+                      pwtmpbuf = __alloca (pwbuflen);
 #    endif
 #    endif
-                     __set_errno (save);
-                   }
+                      __set_errno (save);
+                    }
 #   else
 #   else
-                 p = getpwnam (name);
+                  p = getpwnam (name);
 #   endif
 #   endif
-                 if (p != NULL)
-                   home_dir = p->pw_dir;
-               }
-           }
-         if (home_dir == NULL || home_dir[0] == '\0')
-           {
-             if (flags & GLOB_TILDE_CHECK)
-               return GLOB_NOMATCH;
-             else
-               home_dir = "~"; /* No luck.  */
-           }
+                  if (p != NULL)
+                    home_dir = p->pw_dir;
+                }
+            }
+          if (home_dir == NULL || home_dir[0] == '\0')
+            {
+              if (flags & GLOB_TILDE_CHECK)
+                return GLOB_NOMATCH;
+              else
+                home_dir = "~"; /* No luck.  */
+            }
 #  endif /* WINDOWS32 */
 # endif
 #  endif /* WINDOWS32 */
 # endif
-         /* Now construct the full directory.  */
-         if (dirname[1] == '\0')
-           dirname = home_dir;
-         else
-           {
-             char *newp;
-             size_t home_len = strlen (home_dir);
-             newp = __alloca (home_len + dirlen);
-             mempcpy (mempcpy (newp, home_dir, home_len),
-                      &dirname[1], dirlen);
-             dirname = newp;
-           }
-       }
+          /* Now construct the full directory.  */
+          if (dirname[1] == '\0')
+            {
+              dirname = home_dir;
+              dirlen = strlen (dirname);
+            }
+          else
+            {
+              char *newp;
+              size_t home_len = strlen (home_dir);
+              newp = __alloca (home_len + dirlen);
+              mempcpy (mempcpy (newp, home_dir, home_len),
+                       &dirname[1], dirlen);
+              dirname = newp;
+              dirlen += home_len - 1;
+            }
+          dirname_modified = 1;
+        }
 # if !defined _AMIGA && !defined WINDOWS32
       else
 # if !defined _AMIGA && !defined WINDOWS32
       else
-       {
-         char *end_name = strchr (dirname, '/');
-         const char *user_name;
-         const char *home_dir;
-
-         if (end_name == NULL)
-           user_name = dirname + 1;
-         else
-           {
-             char *newp;
-             newp = __alloca (end_name - dirname);
-             *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
-               = '\0';
-             user_name = newp;
-           }
-
-         /* Look up specific user's home directory.  */
-         {
-           struct passwd *p;
+        {
+          char *end_name = strchr (dirname, '/');
+          const char *user_name;
+          const char *home_dir;
+          char *unescape = NULL;
+
+          if (!(flags & GLOB_NOESCAPE))
+            {
+              if (end_name == NULL)
+                {
+                  unescape = strchr (dirname, '\\');
+                  if (unescape)
+                    end_name = strchr (unescape, '\0');
+                }
+              else
+                unescape = memchr (dirname, '\\', end_name - dirname);
+            }
+          if (end_name == NULL)
+            user_name = dirname + 1;
+          else
+            {
+              char *newp;
+              newp = __alloca (end_name - dirname);
+              *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+                = '\0';
+              if (unescape != NULL)
+                {
+                  char *p = mempcpy (newp, dirname + 1,
+                                     unescape - dirname - 1);
+                  char *q = unescape;
+                  while (*q != '\0')
+                    {
+                      if (*q == '\\')
+                        {
+                          if (q[1] == '\0')
+                            {
+                              /* "~fo\\o\\" unescape to user_name "foo\\",
+                                 but "~fo\\o\\/" unescape to user_name
+                                 "foo".  */
+                              if (filename == NULL)
+                                *p++ = '\\';
+                              break;
+                            }
+                          ++q;
+                        }
+                      *p++ = *q++;
+                    }
+                  *p = '\0';
+                }
+              else
+                *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+                  = '\0';
+              user_name = newp;
+            }
+
+          /* Look up specific user's home directory.  */
+          {
+            struct passwd *p;
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
-           long int buflen = GETPW_R_SIZE_MAX ();
-           char *pwtmpbuf;
-           struct passwd pwbuf;
-           int save = errno;
+            long int buflen = GETPW_R_SIZE_MAX ();
+            char *pwtmpbuf;
+            struct passwd pwbuf;
+            int save = errno;
 
 #   ifndef _LIBC
 
 #   ifndef _LIBC
-           if (buflen == -1)
-             /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
-                moderate value.  */
-             buflen = 1024;
+            if (buflen == -1)
+              /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
+                 moderate value.  */
+              buflen = 1024;
 #   endif
 #   endif
-           pwtmpbuf = __alloca (buflen);
-
-           while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
-             {
-               if (errno != ERANGE)
-                 {
-                   p = NULL;
-                   break;
-                 }
+            pwtmpbuf = __alloca (buflen);
+
+            while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+              {
+                if (errno != ERANGE)
+                  {
+                    p = NULL;
+                    break;
+                  }
 #   ifdef _LIBC
 #   ifdef _LIBC
-               pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+                pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
 #   else
 #   else
-               buflen *= 2;
-               pwtmpbuf = __alloca (buflen);
+                buflen *= 2;
+                pwtmpbuf = __alloca (buflen);
 #   endif
 #   endif
-               __set_errno (save);
-             }
+                __set_errno (save);
+              }
 #  else
 #  else
-           p = getpwnam (user_name);
+            p = getpwnam (user_name);
 #  endif
 #  endif
-           if (p != NULL)
-             home_dir = p->pw_dir;
-           else
-             home_dir = NULL;
-         }
-         /* If we found a home directory use this.  */
-         if (home_dir != NULL)
-           {
-             char *newp;
-             size_t home_len = strlen (home_dir);
-             size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
-             newp = __alloca (home_len + rest_len + 1);
-             *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
-                                 end_name, rest_len)) = '\0';
-             dirname = newp;
-           }
-         else
-           if (flags & GLOB_TILDE_CHECK)
-             /* We have to regard it as an error if we cannot find the
-                home directory.  */
-             return GLOB_NOMATCH;
-       }
-# endif        /* Not Amiga && not WINDOWS32.  */
+            if (p != NULL)
+              home_dir = p->pw_dir;
+            else
+              home_dir = NULL;
+          }
+          /* If we found a home directory use this.  */
+          if (home_dir != NULL)
+            {
+              char *newp;
+              size_t home_len = strlen (home_dir);
+              size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+              newp = __alloca (home_len + rest_len + 1);
+              *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+                                  end_name, rest_len)) = '\0';
+              dirname = newp;
+              dirlen = home_len + rest_len;
+              dirname_modified = 1;
+            }
+          else
+            if (flags & GLOB_TILDE_CHECK)
+              /* We have to regard it as an error if we cannot find the
+                 home directory.  */
+              return GLOB_NOMATCH;
+        }
+# endif /* Not Amiga && not WINDOWS32.  */
     }
 
   /* Now test whether we looked for "~" or "~NAME".  In this case we
     }
 
   /* Now test whether we looked for "~" or "~NAME".  In this case we
@@ -662,190 +798,285 @@ glob (pattern, flags, errfunc, pglob)
 
       /* Return the directory if we don't check for error or if it exists.  */
       if ((flags & GLOB_NOCHECK)
 
       /* Return the directory if we don't check for error or if it exists.  */
       if ((flags & GLOB_NOCHECK)
-         || (((flags & GLOB_ALTDIRFUNC)
-              ? ((*pglob->gl_stat) (dirname, &st) == 0
-                 && S_ISDIR (st.st_mode))
-              : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
-       {
-         int newcount = pglob->gl_pathc + pglob->gl_offs;
-         char **new_gl_pathv;
-
-         new_gl_pathv
-           = realloc (pglob->gl_pathv, (newcount + 1 + 1) * sizeof (char *));
-         if (new_gl_pathv == NULL)
-           {
-           nospace:
-             free (pglob->gl_pathv);
-             pglob->gl_pathv = NULL;
-             pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
-           }
-         pglob->gl_pathv = new_gl_pathv;
-
-          pglob->gl_pathv[newcount] = strdup (dirname);
-         if (pglob->gl_pathv[newcount] == NULL)
-           goto nospace;
-         pglob->gl_pathv[++newcount] = NULL;
-         ++pglob->gl_pathc;
-         pglob->gl_flags = flags;
-
-         return 0;
-       }
+          || (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+               ? ((*pglob->gl_stat) (dirname, &st) == 0
+                  && S_ISDIR (st.st_mode))
+               : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+        {
+          int newcount = pglob->gl_pathc + pglob->gl_offs;
+          char **new_gl_pathv;
+
+          new_gl_pathv
+            = realloc (pglob->gl_pathv, (newcount + 1 + 1) * sizeof (char *));
+          if (new_gl_pathv == NULL)
+            {
+            nospace:
+              free (pglob->gl_pathv);
+              pglob->gl_pathv = NULL;
+              pglob->gl_pathc = 0;
+              return GLOB_NOSPACE;
+            }
+          pglob->gl_pathv = new_gl_pathv;
+
+          if (flags & GLOB_MARK)
+            {
+              char *p;
+              pglob->gl_pathv[newcount] = malloc (dirlen + 2);
+              if (pglob->gl_pathv[newcount] == NULL)
+                goto nospace;
+              p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
+              p[0] = '/';
+              p[1] = '\0';
+            }
+          else
+            {
+              pglob->gl_pathv[newcount] = strdup (dirname);
+              if (pglob->gl_pathv[newcount] == NULL)
+                goto nospace;
+            }
+          pglob->gl_pathv[++newcount] = NULL;
+          ++pglob->gl_pathc;
+          pglob->gl_flags = flags;
+
+          return 0;
+        }
 
       /* Not found.  */
       return GLOB_NOMATCH;
     }
 
 
       /* Not found.  */
       return GLOB_NOMATCH;
     }
 
-  if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+  meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
+  /* meta is 1 if correct glob pattern containing metacharacters.
+     If meta has bit (1 << 2) set, it means there was an unterminated
+     [ which we handle the same, using fnmatch.  Broken unterminated
+     pattern bracket expressions ought to be rare enough that it is
+     not worth special casing them, fnmatch will do the right thing.  */
+  if (meta & 5)
     {
       /* The directory name contains metacharacters, so we
     {
       /* The directory name contains metacharacters, so we
-        have to glob for the directory, and then glob for
-        the pattern in each directory found.  */
-      glob_t dirs;
+         have to glob for the directory, and then glob for
+         the pattern in each directory found.  */
       size_t i;
 
       size_t i;
 
-      if ((flags & GLOB_ALTDIRFUNC) != 0)
-       {
-         /* Use the alternative access functions also in the recursive
-            call.  */
-         dirs.gl_opendir = pglob->gl_opendir;
-         dirs.gl_readdir = pglob->gl_readdir;
-         dirs.gl_closedir = pglob->gl_closedir;
-         dirs.gl_stat = pglob->gl_stat;
-         dirs.gl_lstat = pglob->gl_lstat;
-       }
+      if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
+        {
+          /* "foo\\/bar".  Remove the final backslash from dirname
+             if it has not been quoted.  */
+          char *p = (char *) &dirname[dirlen - 1];
+
+          while (p > dirname && p[-1] == '\\') --p;
+          if ((&dirname[dirlen] - p) & 1)
+            *(char *) &dirname[--dirlen] = '\0';
+        }
+
+      if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) != 0, 0))
+        {
+          /* Use the alternative access functions also in the recursive
+             call.  */
+          dirs.gl_opendir = pglob->gl_opendir;
+          dirs.gl_readdir = pglob->gl_readdir;
+          dirs.gl_closedir = pglob->gl_closedir;
+          dirs.gl_stat = pglob->gl_stat;
+          dirs.gl_lstat = pglob->gl_lstat;
+        }
 
       status = glob (dirname,
 
       status = glob (dirname,
-                    ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
-                               | GLOB_ALTDIRFUNC))
-                     | GLOB_NOSORT | GLOB_ONLYDIR),
-                    errfunc, &dirs);
+                     ((flags & (GLOB_ERR | GLOB_NOESCAPE
+                                | GLOB_ALTDIRFUNC))
+                      | GLOB_NOSORT | GLOB_ONLYDIR),
+                     errfunc, &dirs);
       if (status != 0)
       if (status != 0)
-       return status;
+        {
+          if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
+            return status;
+          goto no_matches;
+        }
 
       /* We have successfully globbed the preceding directory name.
 
       /* We have successfully globbed the preceding directory name.
-        For each name we found, call glob_in_dir on it and FILENAME,
-        appending the results to PGLOB.  */
+         For each name we found, call glob_in_dir on it and FILENAME,
+         appending the results to PGLOB.  */
       for (i = 0; i < dirs.gl_pathc; ++i)
       for (i = 0; i < dirs.gl_pathc; ++i)
-       {
-         int old_pathc;
-
-#ifdef SHELL
-         {
-           /* Make globbing interruptible in the bash shell. */
-           extern int interrupt_state;
-
-           if (interrupt_state)
-             {
-               globfree (&dirs);
-               return GLOB_ABORTED;
-             }
-         }
+        {
+          int old_pathc;
+
+#ifdef SHELL
+          {
+            /* Make globbing interruptible in the bash shell. */
+            extern int interrupt_state;
+
+            if (interrupt_state)
+              {
+                globfree (&dirs);
+                return GLOB_ABORTED;
+              }
+          }
 #endif /* SHELL.  */
 
 #endif /* SHELL.  */
 
-         old_pathc = pglob->gl_pathc;
-         status = glob_in_dir (filename, dirs.gl_pathv[i],
-                               ((flags | GLOB_APPEND)
-                                & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
-                               errfunc, pglob);
-         if (status == GLOB_NOMATCH)
-           /* No matches in this directory.  Try the next.  */
-           continue;
-
-         if (status != 0)
-           {
-             globfree (&dirs);
-             globfree (pglob);
-             pglob->gl_pathc = 0;
-             return status;
-           }
-
-         /* Stick the directory on the front of each name.  */
-         if (prefix_array (dirs.gl_pathv[i],
-                           &pglob->gl_pathv[old_pathc + pglob->gl_offs],
-                           pglob->gl_pathc - old_pathc))
-           {
-             globfree (&dirs);
-             globfree (pglob);
-             pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
-           }
-       }
+          old_pathc = pglob->gl_pathc;
+          status = glob_in_dir (filename, dirs.gl_pathv[i],
+                                ((flags | GLOB_APPEND)
+                                 & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+                                errfunc, pglob);
+          if (status == GLOB_NOMATCH)
+            /* No matches in this directory.  Try the next.  */
+            continue;
+
+          if (status != 0)
+            {
+              globfree (&dirs);
+              globfree (pglob);
+              pglob->gl_pathc = 0;
+              return status;
+            }
+
+          /* Stick the directory on the front of each name.  */
+          if (prefix_array (dirs.gl_pathv[i],
+                            &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+                            pglob->gl_pathc - old_pathc))
+            {
+              globfree (&dirs);
+              globfree (pglob);
+              pglob->gl_pathc = 0;
+              return GLOB_NOSPACE;
+            }
+        }
 
       flags |= GLOB_MAGCHAR;
 
 
       flags |= GLOB_MAGCHAR;
 
-      /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
-        But if we have not found any matching entry and the GLOB_NOCHECK
-        flag was set we must return the input pattern itself.  */
+      /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
+         But if we have not found any matching entry and the GLOB_NOCHECK
+         flag was set we must return the input pattern itself.  */
       if (pglob->gl_pathc + pglob->gl_offs == oldcount)
       if (pglob->gl_pathc + pglob->gl_offs == oldcount)
-       {
-         /* No matches.  */
-         if (flags & GLOB_NOCHECK)
-           {
-             int newcount = pglob->gl_pathc + pglob->gl_offs;
-             char **new_gl_pathv;
-
-             new_gl_pathv = realloc (pglob->gl_pathv,
-                                     (newcount + 2) * sizeof (char *));
-             if (new_gl_pathv == NULL)
-               {
-                 globfree (&dirs);
-                 return GLOB_NOSPACE;
-               }
-             pglob->gl_pathv = new_gl_pathv;
-
-             pglob->gl_pathv[newcount] = strdup (pattern);
-             if (pglob->gl_pathv[newcount] == NULL)
-               {
-                 globfree (&dirs);
-                 globfree (pglob);
-                 pglob->gl_pathc = 0;
-                 return GLOB_NOSPACE;
-               }
-
-             ++pglob->gl_pathc;
-             ++newcount;
-
-             pglob->gl_pathv[newcount] = NULL;
-             pglob->gl_flags = flags;
-           }
-         else
-           {
-             globfree (&dirs);
-             return GLOB_NOMATCH;
-           }
-       }
+        {
+        no_matches:
+          /* No matches.  */
+          if (flags & GLOB_NOCHECK)
+            {
+              int newcount = pglob->gl_pathc + pglob->gl_offs;
+              char **new_gl_pathv;
+
+              new_gl_pathv = realloc (pglob->gl_pathv,
+                                      (newcount + 2) * sizeof (char *));
+              if (new_gl_pathv == NULL)
+                {
+                  globfree (&dirs);
+                  return GLOB_NOSPACE;
+                }
+              pglob->gl_pathv = new_gl_pathv;
+
+              pglob->gl_pathv[newcount] = strdup (pattern);
+              if (pglob->gl_pathv[newcount] == NULL)
+                {
+                  globfree (&dirs);
+                  globfree (pglob);
+                  pglob->gl_pathc = 0;
+                  return GLOB_NOSPACE;
+                }
+
+              ++pglob->gl_pathc;
+              ++newcount;
+
+              pglob->gl_pathv[newcount] = NULL;
+              pglob->gl_flags = flags;
+            }
+          else
+            {
+              globfree (&dirs);
+              return GLOB_NOMATCH;
+            }
+        }
 
       globfree (&dirs);
     }
   else
     {
       int old_pathc = pglob->gl_pathc;
 
       globfree (&dirs);
     }
   else
     {
       int old_pathc = pglob->gl_pathc;
-
+      int orig_flags = flags;
+
+      if (meta & 2)
+        {
+          char *p = strchr (dirname, '\\'), *q;
+          /* We need to unescape the dirname string.  It is certainly
+             allocated by alloca, as otherwise filename would be NULL
+             or dirname wouldn't contain backslashes.  */
+          q = p;
+          do
+            {
+              if (*p == '\\')
+                {
+                  *q = *++p;
+                  --dirlen;
+                }
+              else
+                *q = *p;
+              ++q;
+            }
+          while (*p++ != '\0');
+          dirname_modified = 1;
+        }
+      if (dirname_modified)
+        flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
       status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
       if (status != 0)
       status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
       if (status != 0)
-       return status;
+        {
+          if (status == GLOB_NOMATCH && flags != orig_flags
+              && pglob->gl_pathc + pglob->gl_offs == oldcount)
+            {
+              /* Make sure globfree (&dirs); is a nop.  */
+              dirs.gl_pathv = NULL;
+              flags = orig_flags;
+              goto no_matches;
+            }
+          return status;
+        }
 
       if (dirlen > 0)
 
       if (dirlen > 0)
-       {
-         /* Stick the directory on the front of each name.  */
-         if (prefix_array (dirname,
-                           &pglob->gl_pathv[old_pathc + pglob->gl_offs],
-                           pglob->gl_pathc - old_pathc))
-           {
-             globfree (pglob);
-             pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
-           }
-       }
+        {
+          /* Stick the directory on the front of each name.  */
+          if (prefix_array (dirname,
+                            &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+                            pglob->gl_pathc - old_pathc))
+            {
+              globfree (pglob);
+              pglob->gl_pathc = 0;
+              return GLOB_NOSPACE;
+            }
+        }
+    }
+
+  if (flags & GLOB_MARK)
+    {
+      /* Append slashes to directory names.  */
+      size_t i;
+      struct stat st;
+      struct_stat64 st64;
+
+      for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
+        if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+             ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
+                && S_ISDIR (st.st_mode))
+             : (__stat64 (pglob->gl_pathv[i], &st64) == 0
+                && S_ISDIR (st64.st_mode))))
+          {
+            size_t len = strlen (pglob->gl_pathv[i]) + 2;
+            char *new = realloc (pglob->gl_pathv[i], len);
+            if (new == NULL)
+              {
+                globfree (pglob);
+                pglob->gl_pathc = 0;
+                return GLOB_NOSPACE;
+              }
+            strcpy (&new[len - 2], "/");
+            pglob->gl_pathv[i] = new;
+          }
     }
 
   if (!(flags & GLOB_NOSORT))
     {
       /* Sort the vector.  */
       qsort (&pglob->gl_pathv[oldcount],
     }
 
   if (!(flags & GLOB_NOSORT))
     {
       /* Sort the vector.  */
       qsort (&pglob->gl_pathv[oldcount],
-            pglob->gl_pathc + pglob->gl_offs - oldcount,
-            sizeof (char *), collated_compare);
+             pglob->gl_pathc + pglob->gl_offs - oldcount,
+             sizeof (char *), collated_compare);
     }
 
   return 0;
     }
 
   return 0;
@@ -857,7 +1088,7 @@ libc_hidden_def (glob)
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
 
 
 #if !defined _LIBC || !defined GLOB_ONLY_P
 
-/* Free storage allocated in PGLOB by a previous `glob' call.  */
+/* Free storage allocated in PGLOB by a previous 'glob' call.  */
 void
 globfree (pglob)
      register glob_t *pglob;
 void
 globfree (pglob)
      register glob_t *pglob;
@@ -866,8 +1097,8 @@ globfree (pglob)
     {
       size_t i;
       for (i = 0; i < pglob->gl_pathc; ++i)
     {
       size_t i;
       for (i = 0; i < pglob->gl_pathc; ++i)
-       if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
-         free (pglob->gl_pathv[pglob->gl_offs + i]);
+        if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
+          free (pglob->gl_pathv[pglob->gl_offs + i]);
       free (pglob->gl_pathv);
       pglob->gl_pathv = NULL;
     }
       free (pglob->gl_pathv);
       pglob->gl_pathv = NULL;
     }
@@ -918,14 +1149,14 @@ prefix_array (const char *dirname, char **array, size_t n)
   else if (dirlen > 1)
     {
       if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
   else if (dirlen > 1)
     {
       if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
-       /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
-       --dirlen;
+        /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
+        --dirlen;
       else if (dirname[dirlen - 1] == ':')
       else if (dirname[dirlen - 1] == ':')
-       {
-         /* DIRNAME is "d:".  Use `:' instead of `/'.  */
-         --dirlen;
-         sep_char = ':';
-       }
+        {
+          /* DIRNAME is "d:".  Use ':' instead of '/'.  */
+          --dirlen;
+          sep_char = ':';
+        }
     }
 #endif
 
     }
 #endif
 
@@ -934,16 +1165,16 @@ prefix_array (const char *dirname, char **array, size_t n)
       size_t eltlen = strlen (array[i]) + 1;
       char *new = malloc (dirlen + 1 + eltlen);
       if (new == NULL)
       size_t eltlen = strlen (array[i]) + 1;
       char *new = malloc (dirlen + 1 + eltlen);
       if (new == NULL)
-       {
-         while (i > 0)
-           free (array[--i]);
-         return 1;
-       }
+        {
+          while (i > 0)
+            free (array[--i]);
+          return 1;
+        }
 
       {
 
       {
-       char *endp = mempcpy (new, dirname, dirlen);
-       *endp++ = DIRSEP_CHAR;
-       mempcpy (endp, array[i], eltlen);
+        char *endp = mempcpy (new, dirname, dirlen);
+        *endp++ = DIRSEP_CHAR;
+        mempcpy (endp, array[i], eltlen);
       }
       free (array[i]);
       array[i] = new;
       }
       free (array[i]);
       array[i] = new;
@@ -955,39 +1186,51 @@ prefix_array (const char *dirname, char **array, size_t n)
 
 /* We must not compile this function twice.  */
 #if !defined _LIBC || !defined NO_GLOB_PATTERN_P
 
 /* We must not compile this function twice.  */
 #if !defined _LIBC || !defined NO_GLOB_PATTERN_P
-/* Return nonzero if PATTERN contains any metacharacters.
-   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
 int
 int
-__glob_pattern_p (pattern, quote)
+__glob_pattern_type (pattern, quote)
      const char *pattern;
      int quote;
 {
   register const char *p;
      const char *pattern;
      int quote;
 {
   register const char *p;
-  int open = 0;
+  int ret = 0;
 
   for (p = pattern; *p != '\0'; ++p)
     switch (*p)
       {
       case '?':
       case '*':
 
   for (p = pattern; *p != '\0'; ++p)
     switch (*p)
       {
       case '?':
       case '*':
-       return 1;
+        return 1;
 
       case '\\':
 
       case '\\':
-       if (quote && p[1] != '\0')
-         ++p;
-       break;
+        if (quote)
+          {
+            if (p[1] != '\0')
+              ++p;
+            ret |= 2;
+          }
+        break;
 
       case '[':
 
       case '[':
-       open = 1;
-       break;
+        ret |= 4;
+        break;
 
       case ']':
 
       case ']':
-       if (open)
-         return 1;
-       break;
+        if (ret & 4)
+          return 1;
+        break;
       }
 
       }
 
-  return 0;
+  return ret;
+}
+
+/* Return nonzero if PATTERN contains any metacharacters.
+   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
+int
+__glob_pattern_p (pattern, quote)
+     const char *pattern;
+     int quote;
+{
+  return __glob_pattern_type (pattern, quote) == 1;
 }
 # ifdef _LIBC
 weak_alias (__glob_pattern_p, glob_pattern_p)
 }
 # ifdef _LIBC
 weak_alias (__glob_pattern_p, glob_pattern_p)
@@ -997,262 +1240,312 @@ weak_alias (__glob_pattern_p, glob_pattern_p)
 #endif /* !GLOB_ONLY_P */
 
 
 #endif /* !GLOB_ONLY_P */
 
 
+#if !defined _LIBC || !defined GLOB_ONLY_P
 /* We put this in a separate function mainly to allow the memory
    allocated with alloca to be recycled.  */
 /* We put this in a separate function mainly to allow the memory
    allocated with alloca to be recycled.  */
-#if !defined _LIBC || !defined GLOB_ONLY_P
-static bool
-is_dir_p (const char *dir, size_t dirlen, const char *fname,
-         glob_t *pglob, int flags)
+static int
+__attribute_noinline__
+link_exists2_p (const char *dir, size_t dirlen, const char *fname,
+                glob_t *pglob
+# if !defined _LIBC && !HAVE_FSTATAT
+                , int flags
+# endif
+                )
 {
   size_t fnamelen = strlen (fname);
   char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
   struct stat st;
 {
   size_t fnamelen = strlen (fname);
   char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
   struct stat st;
-  struct_stat64 st64;
 
   mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
 
   mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
-          fname, fnamelen + 1);
+           fname, fnamelen + 1);
+
+# if !defined _LIBC && !HAVE_FSTATAT
+  if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
+    {
+      struct_stat64 st64;
+      return __stat64 (fullname, &st64) == 0;
+    }
+# endif
+  return (*pglob->gl_stat) (fullname, &st) == 0;
+}
 
 
-  return ((flags & GLOB_ALTDIRFUNC)
-         ? (*pglob->gl_stat) (fullname, &st) == 0 && S_ISDIR (st.st_mode)
-         : __stat64 (fullname, &st64) == 0 && S_ISDIR (st64.st_mode));
+/* Return true if DIR/FNAME exists.  */
+static int
+link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
+               glob_t *pglob, int flags)
+{
+# if defined _LIBC || HAVE_FSTATAT
+  if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+    return link_exists2_p (dir, dirlen, fname, pglob);
+  else
+    {
+      /* dfd cannot be -1 here, because dirfd never returns -1 on
+         glibc, or on hosts that have fstatat.  */
+      struct_stat64 st64;
+      return __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0;
+    }
+# else
+  return link_exists2_p (dir, dirlen, fname, pglob, flags);
+# endif
 }
 #endif
 
 
 }
 #endif
 
 
-/* Like `glob', but PATTERN is a final pathname component,
+/* Like 'glob', but PATTERN is a final pathname component,
    and matches are searched for in DIRECTORY.
    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
    The GLOB_APPEND flag is assumed to be set (always appends).  */
 static int
 glob_in_dir (const char *pattern, const char *directory, int flags,
    and matches are searched for in DIRECTORY.
    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
    The GLOB_APPEND flag is assumed to be set (always appends).  */
 static int
 glob_in_dir (const char *pattern, const char *directory, int flags,
-            int (*errfunc) (const char *, int),
-            glob_t *pglob)
+             int (*errfunc) (const char *, int),
+             glob_t *pglob)
 {
   size_t dirlen = strlen (directory);
   void *stream = NULL;
 {
   size_t dirlen = strlen (directory);
   void *stream = NULL;
-  struct globlink
+  struct globnames
     {
     {
-      struct globlink *next;
-      char *name;
+      struct globnames *next;
+      size_t count;
+      char *name[64];
     };
     };
-  struct globlink *names = NULL;
-  size_t nfound;
+#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
+  struct globnames init_names;
+  struct globnames *names = &init_names;
+  struct globnames *names_alloca = &init_names;
+  size_t nfound = 0;
+  size_t allocasize = sizeof (init_names);
+  size_t cur = 0;
   int meta;
   int save;
   int meta;
   int save;
+  int result;
+
+  init_names.next = NULL;
+  init_names.count = INITIAL_COUNT;
 
 
-  meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+  meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
     {
       /* We need not do any tests.  The PATTERN contains no meta
   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
     {
       /* We need not do any tests.  The PATTERN contains no meta
-        characters and we must not return an error therefore the
-        result will always contain exactly one name.  */
+         characters and we must not return an error therefore the
+         result will always contain exactly one name.  */
       flags |= GLOB_NOCHECK;
       flags |= GLOB_NOCHECK;
-      nfound = 0;
     }
     }
-  else if (meta == 0 &&
-          ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL))
+  else if (meta == 0)
     {
       /* Since we use the normal file functions we can also use stat()
     {
       /* Since we use the normal file functions we can also use stat()
-        to verify the file is there.  */
+         to verify the file is there.  */
       struct stat st;
       struct_stat64 st64;
       size_t patlen = strlen (pattern);
       char *fullname = __alloca (dirlen + 1 + patlen + 1);
 
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
       struct stat st;
       struct_stat64 st64;
       size_t patlen = strlen (pattern);
       char *fullname = __alloca (dirlen + 1 + patlen + 1);
 
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
-                       "/", 1),
-              pattern, patlen + 1);
-      if (((flags & GLOB_ALTDIRFUNC)
-          ? (*pglob->gl_stat) (fullname, &st)
-          : __stat64 (fullname, &st64)) == 0)
-       /* We found this file to be existing.  Now tell the rest
-          of the function to copy this name into the result.  */
-       flags |= GLOB_NOCHECK;
-
-      nfound = 0;
+                        "/", 1),
+               pattern, patlen + 1);
+      if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+           ? (*pglob->gl_stat) (fullname, &st)
+           : __stat64 (fullname, &st64)) == 0)
+        /* We found this file to be existing.  Now tell the rest
+           of the function to copy this name into the result.  */
+        flags |= GLOB_NOCHECK;
     }
   else
     {
     }
   else
     {
-      if (pattern[0] == '\0')
-       {
-         /* This is a special case for matching directories like in
-            "*a/".  */
-         names = __alloca (sizeof (struct globlink));
-         names->name = malloc (1);
-         if (names->name == NULL)
-           goto memory_error;
-         names->name[0] = '\0';
-         names->next = NULL;
-         nfound = 1;
-         meta = 0;
-       }
+      stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+                ? (*pglob->gl_opendir) (directory)
+                : opendir (directory));
+      if (stream == NULL)
+        {
+          if (errno != ENOTDIR
+              && ((errfunc != NULL && (*errfunc) (directory, errno))
+                  || (flags & GLOB_ERR)))
+            return GLOB_ABORTED;
+        }
       else
       else
-       {
-         stream = ((flags & GLOB_ALTDIRFUNC)
-                   ? (*pglob->gl_opendir) (directory)
-                   : opendir (directory));
-         if (stream == NULL)
-           {
-             if (errno != ENOTDIR
-                 && ((errfunc != NULL && (*errfunc) (directory, errno))
-                     || (flags & GLOB_ERR)))
-               return GLOB_ABORTED;
-             nfound = 0;
-             meta = 0;
-           }
-         else
-           {
-             int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
-                              | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
-#if defined _AMIGA || defined __VMS
-                              | FNM_CASEFOLD
+        {
+          int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+                     ? -1 : dirfd ((DIR *) stream));
+          int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+                           | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+#if defined _AMIGA || defined VMS
+                           | FNM_CASEFOLD
 #endif
 #endif
-                              );
-             nfound = 0;
-             flags |= GLOB_MAGCHAR;
-
-             while (1)
-               {
-                 const char *name;
-                 size_t len;
+                           );
+          flags |= GLOB_MAGCHAR;
+
+          while (1)
+            {
+              const char *name;
+              size_t len;
 #if defined _LIBC && !defined COMPILE_GLOB64
 #if defined _LIBC && !defined COMPILE_GLOB64
-                 struct dirent64 *d;
-                 union
-                   {
-                     struct dirent64 d64;
-                     char room [offsetof (struct dirent64, d_name[0])
-                                + NAME_MAX + 1];
-                   }
-                 d64buf;
-
-                 if (flags & GLOB_ALTDIRFUNC)
-                   {
-                     struct dirent *d32 = (*pglob->gl_readdir) (stream);
-                     if (d32 != NULL)
-                       {
-                         CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
-                         d = &d64buf.d64;
-                       }
-                     else
-                       d = NULL;
-                   }
-                 else
-                   d = __readdir64 (stream);
+              struct dirent64 *d;
+              union
+                {
+                  struct dirent64 d64;
+                  char room [offsetof (struct dirent64, d_name[0])
+                             + NAME_MAX + 1];
+                }
+              d64buf;
+
+              if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+                {
+                  struct dirent *d32 = (*pglob->gl_readdir) (stream);
+                  if (d32 != NULL)
+                    {
+                      CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+                      d = &d64buf.d64;
+                    }
+                  else
+                    d = NULL;
+                }
+              else
+                d = __readdir64 (stream);
 #else
 #else
-                 struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
-                                     ? ((*pglob->gl_readdir) (stream))
-                                     : __readdir (stream));
+              struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+                                  ? ((struct dirent *)
+                                     (*pglob->gl_readdir) (stream))
+                                  : __readdir (stream));
 #endif
 #endif
-                 if (d == NULL)
-                   break;
-                 if (! REAL_DIR_ENTRY (d))
-                   continue;
-
-                 /* If we shall match only directories use the information
-                    provided by the dirent call if possible.  */
-                 if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
-                   continue;
-
-                 name = d->d_name;
-
-                 if (fnmatch (pattern, name, fnm_flags) == 0)
-                   {
-                     /* ISDIR will often be incorrectly set to false
-                        when not in GLOB_ONLYDIR || GLOB_MARK mode, but we
-                        don't care.  It won't be used and we save the
-                        expensive call to stat.  */
-                     int need_dir_test =
-                       (GLOB_MARK | (DIRENT_MIGHT_BE_SYMLINK (d)
-                                     ? GLOB_ONLYDIR : 0));
-                     bool isdir = (DIRENT_MUST_BE (d, DT_DIR)
-                                   || ((flags & need_dir_test)
-                                       && is_dir_p (directory, dirlen, name,
-                                                    pglob, flags)));
-
-                     /* In GLOB_ONLYDIR mode, skip non-dirs.  */
-                     if ((flags & GLOB_ONLYDIR) && !isdir)
-                         continue;
-
-                       {
-                         struct globlink *new =
-                           __alloca (sizeof (struct globlink));
-                         char *p;
-                         len = _D_EXACT_NAMLEN (d);
-                         new->name =
-                           malloc (len + 1 + ((flags & GLOB_MARK) && isdir));
-                         if (new->name == NULL)
-                           goto memory_error;
-                         p = mempcpy (new->name, name, len);
-                         if ((flags & GLOB_MARK) && isdir)
-                             *p++ = '/';
-                         *p = '\0';
-                         new->next = names;
-                         names = new;
-                         ++nfound;
-                       }
-                   }
-               }
-           }
-       }
+              if (d == NULL)
+                break;
+              if (! REAL_DIR_ENTRY (d))
+                continue;
+
+              /* If we shall match only directories use the information
+                 provided by the dirent call if possible.  */
+              if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+                continue;
+
+              name = d->d_name;
+
+              if (fnmatch (pattern, name, fnm_flags) == 0)
+                {
+                  /* If the file we found is a symlink we have to
+                     make sure the target file exists.  */
+                  if (!DIRENT_MIGHT_BE_SYMLINK (d)
+                      || link_exists_p (dfd, directory, dirlen, name, pglob,
+                                        flags))
+                    {
+                      if (cur == names->count)
+                        {
+                          struct globnames *newnames;
+                          size_t count = names->count * 2;
+                          size_t size = (sizeof (struct globnames)
+                                         + ((count - INITIAL_COUNT)
+                                            * sizeof (char *)));
+                          allocasize += size;
+                          if (__libc_use_alloca (allocasize))
+                            newnames = names_alloca = __alloca (size);
+                          else if ((newnames = malloc (size))
+                                   == NULL)
+                            goto memory_error;
+                          newnames->count = count;
+                          newnames->next = names;
+                          names = newnames;
+                          cur = 0;
+                        }
+                      len = _D_EXACT_NAMLEN (d);
+                      names->name[cur] = malloc (len + 1);
+                      if (names->name[cur] == NULL)
+                        goto memory_error;
+                      *((char *) mempcpy (names->name[cur++], name, len))
+                        = '\0';
+                      ++nfound;
+                    }
+                }
+            }
+        }
     }
 
   if (nfound == 0 && (flags & GLOB_NOCHECK))
     {
       size_t len = strlen (pattern);
       nfound = 1;
     }
 
   if (nfound == 0 && (flags & GLOB_NOCHECK))
     {
       size_t len = strlen (pattern);
       nfound = 1;
-      names = __alloca (sizeof (struct globlink));
-      names->next = NULL;
-      names->name = malloc (len + 1);
-      if (names->name == NULL)
-       goto memory_error;
-      *((char *) mempcpy (names->name, pattern, len)) = '\0';
+      names->name[cur] = malloc (len + 1);
+      if (names->name[cur] == NULL)
+        goto memory_error;
+      *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
     }
 
     }
 
+  result = GLOB_NOMATCH;
   if (nfound != 0)
     {
   if (nfound != 0)
     {
-      char **new_gl_pathv;
+      char **new_gl_pathv
+        = realloc (pglob->gl_pathv,
+                   (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+                   * sizeof (char *));
+      result = 0;
 
 
-      new_gl_pathv
-       = realloc (pglob->gl_pathv,
-                  (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
-                  * sizeof (char *));
       if (new_gl_pathv == NULL)
       if (new_gl_pathv == NULL)
-       goto memory_error;
-      pglob->gl_pathv = new_gl_pathv;
-
-      for (; names != NULL; names = names->next)
-       pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
-      pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
-
-      pglob->gl_flags = flags;
+        {
+        memory_error:
+          while (1)
+            {
+              struct globnames *old = names;
+              size_t i;
+              for (i = 0; i < cur; ++i)
+                free (names->name[i]);
+              names = names->next;
+              /* NB: we will not leak memory here if we exit without
+                 freeing the current block assigned to OLD.  At least
+                 the very first block is always allocated on the stack
+                 and this is the block assigned to OLD here.  */
+              if (names == NULL)
+                {
+                  assert (old == &init_names);
+                  break;
+                }
+              cur = names->count;
+              if (old == names_alloca)
+                names_alloca = names;
+              else
+                free (old);
+            }
+          result = GLOB_NOSPACE;
+        }
+      else
+        {
+          while (1)
+            {
+              struct globnames *old = names;
+              size_t i;
+              for (i = 0; i < cur; ++i)
+                new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
+                  = names->name[i];
+              names = names->next;
+              /* NB: we will not leak memory here if we exit without
+                 freeing the current block assigned to OLD.  At least
+                 the very first block is always allocated on the stack
+                 and this is the block assigned to OLD here.  */
+              if (names == NULL)
+                {
+                  assert (old == &init_names);
+                  break;
+                }
+              cur = names->count;
+              if (old == names_alloca)
+                names_alloca = names;
+              else
+                free (old);
+            }
+
+          pglob->gl_pathv = new_gl_pathv;
+
+          pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+          pglob->gl_flags = flags;
+        }
     }
 
     }
 
-  save = errno;
   if (stream != NULL)
     {
   if (stream != NULL)
     {
-      if (flags & GLOB_ALTDIRFUNC)
-       (*pglob->gl_closedir) (stream);
+      save = errno;
+      if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+        (*pglob->gl_closedir) (stream);
       else
       else
-       closedir (stream);
+        closedir (stream);
+      __set_errno (save);
     }
     }
-  __set_errno (save);
 
 
-  return nfound == 0 ? GLOB_NOMATCH : 0;
-
- memory_error:
-  {
-    int save = errno;
-    if (flags & GLOB_ALTDIRFUNC)
-      (*pglob->gl_closedir) (stream);
-    else
-      closedir (stream);
-    __set_errno (save);
-  }
-  while (names != NULL)
-    {
-      if (names->name != NULL)
-       free (names->name);
-      names = names->next;
-    }
-  return GLOB_NOSPACE;
+  return result;
 }
 }