maint: update copyright
[gnulib.git] / lib / glob.c
index ccd0e7a..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.
 
-   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
-   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
+/* 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
 
@@ -31,7 +32,9 @@
 /* #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
 
 # 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
 #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.  */
-# 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.  */
-# 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 */
-# 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 */
 
-/* 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)
 # 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
 
 # ifndef __stat64
 #  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
 # endif
-# define struct_stat64         struct stat64
+# define struct_stat64          struct stat64
 #else /* !_LIBC */
-# include "getlogin_r.h"
-# 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 */
 
-#include <stdbool.h>
 #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
-# define GETPW_R_SIZE_MAX()    (-1)
+# define GETPW_R_SIZE_MAX()     (-1)
 #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
-# define GET_LOGIN_NAME_MAX()  (-1)
+# define GET_LOGIN_NAME_MAX()   (-1)
 #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 */
 
+#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,
-   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,
-                       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
-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.  */
@@ -182,17 +222,17 @@ next_brace_sub (const char *cp, int flags)
   while (*cp != '\0')
     if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
       {
-       if (*++cp == '\0')
-         break;
-       ++cp;
+        if (*++cp == '\0')
+          break;
+        ++cp;
       }
     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;
@@ -204,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
-   `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.
-   Otherwise, `glob' returns zero.  */
+   Otherwise, 'glob' returns zero.  */
 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);
-     glob_t *pglob;
+     glob_t * restrict pglob;
 {
   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)
     {
@@ -231,7 +274,7 @@ glob (pattern, flags, errfunc, pglob)
     }
 
   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;
 
@@ -240,185 +283,188 @@ glob (pattern, flags, errfunc, pglob)
       const char *begin;
 
       if (flags & GLOB_NOESCAPE)
-       begin = strchr (pattern, '{');
+        begin = strchr (pattern, '{');
       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)
-       {
-         /* 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__
-         char onealt[strlen (pattern) - 1];
+          char onealt[strlen (pattern) - 1];
 #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
 
-         /* 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__
-             free (onealt);
+              free (onealt);
 #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__
-                 free (onealt);
+                  free (onealt);
 #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__
-                 free (onealt);
+                  free (onealt);
 #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__
-         free (onealt);
+          free (onealt);
 #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
-  /* 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 */
+  dirname_modified = 0;
   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] == '~')
-       {
-         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
-       {
-         filename = pattern;
+        {
+          filename = pattern;
 #ifdef _AMIGA
-         dirname = "";
+          dirname = "";
 #else
-         dirname = ".";
+          dirname = ".";
 #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;
@@ -429,21 +475,21 @@ glob (pattern, flags, errfunc, pglob)
       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';
@@ -453,18 +499,41 @@ glob (pattern, flags, errfunc, pglob)
       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
-         && 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))
@@ -473,185 +542,251 @@ glob (pattern, flags, errfunc, pglob)
       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] == '~')
     {
-      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
-         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
-         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
-         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
-                 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
-                 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
-                 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
-                     pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
-                                               2 * pwbuflen);
+                      pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+                                                2 * pwbuflen);
 #    else
-                     pwbuflen *= 2;
-                     pwtmpbuf = __alloca (pwbuflen);
+                      pwbuflen *= 2;
+                      pwtmpbuf = __alloca (pwbuflen);
 #    endif
-                     __set_errno (save);
-                   }
+                      __set_errno (save);
+                    }
 #   else
-                 p = getpwnam (name);
+                  p = getpwnam (name);
 #   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
-         /* 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
-       {
-         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
-           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
-           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
-           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
-               pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+                pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
 #   else
-               buflen *= 2;
-               pwtmpbuf = __alloca (buflen);
+                buflen *= 2;
+                pwtmpbuf = __alloca (buflen);
 #   endif
-               __set_errno (save);
-             }
+                __set_errno (save);
+              }
 #  else
-           p = getpwnam (user_name);
+            p = getpwnam (user_name);
 #  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
@@ -663,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)
-         || (((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;
     }
 
-  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
-        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;
 
-      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,
-                    ((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)
-       return status;
+        {
+          if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
+            return status;
+          goto no_matches;
+        }
 
       /* 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)
-       {
-         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.  */
 
-         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;
 
-      /* 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)
-       {
-         /* 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;
-
+      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)
-       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)
-       {
-         /* 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],
-            pglob->gl_pathc + pglob->gl_offs - oldcount,
-            sizeof (char *), collated_compare);
+             pglob->gl_pathc + pglob->gl_offs - oldcount,
+             sizeof (char *), collated_compare);
     }
 
   return 0;
@@ -858,7 +1088,7 @@ libc_hidden_def (glob)
 
 #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;
@@ -867,8 +1097,8 @@ globfree (pglob)
     {
       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;
     }
@@ -919,14 +1149,14 @@ prefix_array (const char *dirname, char **array, size_t n)
   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] == ':')
-       {
-         /* DIRNAME is "d:".  Use `:' instead of `/'.  */
-         --dirlen;
-         sep_char = ':';
-       }
+        {
+          /* DIRNAME is "d:".  Use ':' instead of '/'.  */
+          --dirlen;
+          sep_char = ':';
+        }
     }
 #endif
 
@@ -935,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)
-       {
-         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;
@@ -956,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
-/* Return nonzero if PATTERN contains any metacharacters.
-   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
 int
-__glob_pattern_p (pattern, quote)
+__glob_pattern_type (pattern, quote)
      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 '*':
-       return 1;
+        return 1;
 
       case '\\':
-       if (quote && p[1] != '\0')
-         ++p;
-       break;
+        if (quote)
+          {
+            if (p[1] != '\0')
+              ++p;
+            ret |= 2;
+          }
+        break;
 
       case '[':
-       open = 1;
-       break;
+        ret |= 4;
+        break;
 
       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)
@@ -998,262 +1240,312 @@ weak_alias (__glob_pattern_p, glob_pattern_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.  */
-#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;
-  struct_stat64 st64;
 
   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
 
 
-/* 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,
-            int (*errfunc) (const char *, int),
-            glob_t *pglob)
+             int (*errfunc) (const char *, int),
+             glob_t *pglob)
 {
   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 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
-        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;
-      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()
-        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),
-                       "/", 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
     {
-      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
-       {
-         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
-                              );
-             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
-                 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
-                 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
-                 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;
-      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)
     {
-      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)
-       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 (flags & GLOB_ALTDIRFUNC)
-       (*pglob->gl_closedir) (stream);
+      save = errno;
+      if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+        (*pglob->gl_closedir) (stream);
       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;
 }