]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - posix/glob.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / posix / glob.c
index 29e894819f7a0d5c2729edf8cbbb027e1a883824..4be734420499322f2149fe15ca172de795adca12 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2019 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
 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _LIBC
-# include <config.h>
-#endif
+   <https://www.gnu.org/licenses/>.  */
 
 #include <glob.h>
 
 #endif
 
 #include <errno.h>
-#ifndef __set_errno
-# define __set_errno(val) errno = (val)
-#endif
-
 #include <dirent.h>
 #include <stdlib.h>
 #include <string.h>
@@ -65,7 +57,9 @@
 # endif
 # define struct_stat64         struct stat64
 # define FLEXIBLE_ARRAY_MEMBER
+# include <shlib-compat.h>
 #else /* !_LIBC */
+# define __glob                 glob
 # define __getlogin_r(buf, len) getlogin_r (buf, len)
 # define __lstat64(fname, buf)  lstat (fname, buf)
 # define __stat64(fname, buf)   stat (fname, buf)
 
 #include <flexmember.h>
 #include <glob_internal.h>
-
-#ifdef _SC_GETPW_R_SIZE_MAX
-# define GETPW_R_SIZE_MAX()    sysconf (_SC_GETPW_R_SIZE_MAX)
-#else
-# define GETPW_R_SIZE_MAX()    (-1)
-#endif
-#ifdef _SC_LOGIN_NAME_MAX
-# define GET_LOGIN_NAME_MAX()  sysconf (_SC_LOGIN_NAME_MAX)
-#else
-# define GET_LOGIN_NAME_MAX()  (-1)
-#endif
+#include <scratch_buffer.h>
 \f
 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
@@ -197,6 +181,29 @@ convert_dirent64 (const struct dirent64 *source)
     ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
 #endif
 
+static int
+glob_lstat (glob_t *pglob, int flags, const char *fullname)
+{
+/* Use on glob-lstat-compat.c to provide a compat symbol which does not
+   use lstat / gl_lstat.  */
+#ifdef GLOB_NO_LSTAT
+# define GL_LSTAT gl_stat
+# define LSTAT64 __stat64
+#else
+# define GL_LSTAT gl_lstat
+# define LSTAT64 __lstat64
+#endif
+
+  union
+  {
+    struct stat st;
+    struct_stat64 st64;
+  } ust;
+  return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
+          ? pglob->GL_LSTAT (fullname, &ust.st)
+          : LSTAT64 (fullname, &ust.st64));
+}
+
 /* Set *R = A + B.  Return true if the answer is mathematically
    incorrect due to overflow; in this case, *R is the low order
    bits of the correct answer.  */
@@ -223,9 +230,6 @@ glob_use_alloca (size_t alloca_used, size_t len)
 static int glob_in_dir (const char *pattern, const char *directory,
                        int flags, int (*errfunc) (const char *, int),
                        glob_t *pglob, size_t alloca_used);
-extern int __glob_pattern_type (const char *pattern, int quote)
-    attribute_hidden;
-
 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
 static int collated_compare (const void *, const void *) __THROWNL;
 
@@ -266,6 +270,9 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
+#ifndef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -276,11 +283,9 @@ next_brace_sub (const char *cp, int flags)
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, 'glob' returns zero.  */
 int
-#ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
-#endif
-glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
-      glob_t *pglob)
+__glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+       glob_t *pglob)
 {
   const char *filename;
   char *dirname = NULL;
@@ -424,9 +429,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              /* 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);
+             result = __glob (onealt,
+                              ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+                               | GLOB_APPEND),
+                              errfunc, pglob);
 
              /* If we got an error, return it.  */
              if (result && result != GLOB_NOMATCH)
@@ -575,7 +581,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
                }
            }
-         int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+         int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
          if (val == 0)
            pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
                               | (flags & GLOB_MARK));
@@ -622,128 +628,46 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              else
                home_dir = "c:/users/default"; /* poor default */
 #else
-             int success;
-             char *name;
-             int malloc_name = 0;
-             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;
-             if (glob_use_alloca (alloca_used, buflen))
-               name = alloca_account (buflen, alloca_used);
-             else
+             int err;
+             struct passwd *p;
+             struct passwd pwbuf;
+             struct scratch_buffer s;
+             scratch_buffer_init (&s);
+             while (true)
                {
-                 name = malloc (buflen);
-                 if (name == NULL)
+                 p = NULL;
+                 err = __getlogin_r (s.data, s.length);
+                 if (err == 0)
                    {
-                     retval = GLOB_NOSPACE;
-                     goto out;
-                   }
-                 malloc_name = 1;
-               }
-
-             success = __getlogin_r (name, buflen) == 0;
-             if (success)
-               {
-                 struct passwd *p;
-                 char *malloc_pwtmpbuf = NULL;
-                 char *pwtmpbuf;
 # if defined HAVE_GETPWNAM_R || defined _LIBC
-                 long int pwbuflenmax = GETPW_R_SIZE_MAX ();
-                 size_t pwbuflen = pwbuflenmax;
-                 struct passwd pwbuf;
-                 int save = errno;
-
-#  ifndef _LIBC
-                 if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
-                   /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
-                      Try a moderate value.  */
-                   pwbuflen = 1024;
-#  endif
-                 if (glob_use_alloca (alloca_used, pwbuflen))
-                   pwtmpbuf = alloca_account (pwbuflen, alloca_used);
-                 else
-                   {
-                     pwtmpbuf = malloc (pwbuflen);
-                     if (pwtmpbuf == NULL)
-                       {
-                         if (__glibc_unlikely (malloc_name))
-                           free (name);
-                         retval = GLOB_NOSPACE;
-                         goto out;
-                       }
-                     malloc_pwtmpbuf = pwtmpbuf;
-                   }
-
-                 while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
-                        != 0)
-                   {
-                     size_t newlen;
-                     bool v;
-                     if (errno != ERANGE)
-                       {
-                         p = NULL;
-                         break;
-                       }
-                     v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
-                     if (!v && malloc_pwtmpbuf == NULL
-                         && glob_use_alloca (alloca_used, newlen))
-                       pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
-                                                         newlen, alloca_used);
-                     else
-                       {
-                         char *newp = (v ? NULL
-                                       : realloc (malloc_pwtmpbuf, newlen));
-                         if (newp == NULL)
-                           {
-                             free (malloc_pwtmpbuf);
-                             if (__glibc_unlikely (malloc_name))
-                               free (name);
-                             retval = GLOB_NOSPACE;
-                             goto out;
-                           }
-                         malloc_pwtmpbuf = pwtmpbuf = newp;
-                       }
-                     pwbuflen = newlen;
-                     __set_errno (save);
-                   }
+                     size_t ssize = strlen (s.data) + 1;
+                     char *sdata = s.data;
+                     err = getpwnam_r (sdata, &pwbuf, sdata + ssize,
+                                       s.length - ssize, &p);
 # else
-                 p = getpwnam (name);
+                     p = getpwnam (s.data);
+                     if (p == NULL)
+                       err = errno;
 # endif
-                 if (__glibc_unlikely (malloc_name))
-                   free (name);
-                 if (p != NULL)
+                   }
+                 if (err != ERANGE)
+                   break;
+                 if (!scratch_buffer_grow (&s))
                    {
-                     if (malloc_pwtmpbuf == NULL)
-                       home_dir = p->pw_dir;
-                     else
-                       {
-                         size_t home_dir_len = strlen (p->pw_dir) + 1;
-                         if (glob_use_alloca (alloca_used, home_dir_len))
-                           home_dir = alloca_account (home_dir_len,
-                                                      alloca_used);
-                         else
-                           {
-                             home_dir = malloc (home_dir_len);
-                             if (home_dir == NULL)
-                               {
-                                 free (pwtmpbuf);
-                                 retval = GLOB_NOSPACE;
-                                 goto out;
-                               }
-                             malloc_home_dir = 1;
-                           }
-                         memcpy (home_dir, p->pw_dir, home_dir_len);
-                       }
+                     retval = GLOB_NOSPACE;
+                     goto out;
                    }
-                 free (malloc_pwtmpbuf);
                }
-             else
+             if (err == 0)
+               {
+                 home_dir = strdup (p->pw_dir);
+                 malloc_home_dir = 1;
+               }
+             scratch_buffer_free (&s);
+             if (err == 0 && home_dir == NULL)
                {
-                 if (__glibc_unlikely (malloc_name))
-                   free (name);
+                 retval = GLOB_NOSPACE;
+                 goto out;
                }
 #endif /* WINDOWS32 */
            }
@@ -847,11 +771,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  char *p = mempcpy (newp, dirname + 1,
                                     unescape - dirname - 1);
                  char *q = unescape;
-                 while (*q != '\0')
+                 while (q != end_name)
                    {
                      if (*q == '\\')
                        {
-                         if (q[1] == '\0')
+                         if (q + 1 == end_name)
                            {
                              /* "~fo\\o\\" unescape to user_name "foo\\",
                                 but "~fo\\o\\/" unescape to user_name
@@ -867,7 +791,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  *p = '\0';
                }
              else
-               *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+               *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
                  = '\0';
              user_name = newp;
            }
@@ -875,61 +799,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          /* Look up specific user's home directory.  */
          {
            struct passwd *p;
-           char *malloc_pwtmpbuf = NULL;
+           struct scratch_buffer pwtmpbuf;
+           scratch_buffer_init (&pwtmpbuf);
+
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
-           long int buflenmax = GETPW_R_SIZE_MAX ();
-           size_t buflen = buflenmax;
-           char *pwtmpbuf;
            struct passwd pwbuf;
-           int save = errno;
-
-#   ifndef _LIBC
-           if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
-             /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
-                moderate value.  */
-             buflen = 1024;
-#   endif
-           if (glob_use_alloca (alloca_used, buflen))
-             pwtmpbuf = alloca_account (buflen, alloca_used);
-           else
+
+           while (getpwnam_r (user_name, &pwbuf,
+                              pwtmpbuf.data, pwtmpbuf.length, &p)
+                  == ERANGE)
              {
-               pwtmpbuf = malloc (buflen);
-               if (pwtmpbuf == NULL)
+               if (!scratch_buffer_grow (&pwtmpbuf))
                  {
-                 nomem_getpw:
-                   if (__glibc_unlikely (malloc_user_name))
-                     free (user_name);
                    retval = GLOB_NOSPACE;
                    goto out;
                  }
-               malloc_pwtmpbuf = pwtmpbuf;
-             }
-
-           while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
-             {
-               size_t newlen;
-               bool v;
-               if (errno != ERANGE)
-                 {
-                   p = NULL;
-                   break;
-                 }
-               v = size_add_wrapv (buflen, buflen, &newlen);
-               if (!v && malloc_pwtmpbuf == NULL
-                   && glob_use_alloca (alloca_used, newlen))
-                 pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
-                                                   newlen, alloca_used);
-               else
-                 {
-                   char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
-                   if (newp == NULL)
-                     {
-                       free (malloc_pwtmpbuf);
-                       goto nomem_getpw;
-                     }
-                   malloc_pwtmpbuf = pwtmpbuf = newp;
-                 }
-               __set_errno (save);
              }
 #  else
            p = getpwnam (user_name);
@@ -943,6 +827,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              {
                size_t home_len = strlen (p->pw_dir);
                size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+               char *d;
 
                if (__glibc_unlikely (malloc_dirname))
                  free (dirname);
@@ -956,24 +841,22 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                    dirname = malloc (home_len + rest_len + 1);
                    if (dirname == NULL)
                      {
-                       free (malloc_pwtmpbuf);
+                       scratch_buffer_free (&pwtmpbuf);
                        retval = GLOB_NOSPACE;
                        goto out;
                      }
                    malloc_dirname = 1;
                  }
-               *((char *) mempcpy (mempcpy (dirname, p->pw_dir, home_len),
-                                   end_name, rest_len)) = '\0';
+               d = mempcpy (dirname, p->pw_dir, home_len);
+               if (end_name != NULL)
+                 d = mempcpy (d, end_name, rest_len);
+               *d = '\0';
 
                dirlen = home_len + rest_len;
                dirname_modified = 1;
-
-               free (malloc_pwtmpbuf);
              }
            else
              {
-               free (malloc_pwtmpbuf);
-
                if (flags & GLOB_TILDE_CHECK)
                  {
                    /* We have to regard it as an error if we cannot find the
@@ -982,6 +865,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                    goto out;
                  }
              }
+           scratch_buffer_free (&pwtmpbuf);
          }
 #endif /* !WINDOWS32 */
        }
@@ -1046,7 +930,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
      [ 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)
+  if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET))
     {
       /* The directory name contains metacharacters, so we
         have to glob for the directory, and then glob for
@@ -1075,11 +959,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          dirs.gl_lstat = pglob->gl_lstat;
        }
 
-      status = glob (dirname,
-                    ((flags & (GLOB_ERR | GLOB_NOESCAPE
-                               | GLOB_ALTDIRFUNC))
-                     | GLOB_NOSORT | GLOB_ONLYDIR),
-                    errfunc, &dirs);
+      status = __glob (dirname,
+                      ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
+                       | GLOB_NOSORT | GLOB_ONLYDIR),
+                      errfunc, &dirs);
       if (status != 0)
        {
          if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
@@ -1187,7 +1070,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
       size_t old_pathc = pglob->gl_pathc;
       int orig_flags = flags;
 
-      if (meta & 2)
+      if (meta & GLOBPAT_BACKSLASH)
        {
          char *p = strchr (dirname, '\\'), *q;
          /* We need to unescape the dirname string.  It is certainly
@@ -1277,8 +1160,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 
   return retval;
 }
-#if defined _LIBC && !defined glob
-libc_hidden_def (glob)
+#if defined _LIBC && !defined __glob
+versioned_symbol (libc, __glob, glob, GLIBC_2_27);
+libc_hidden_ver (__glob, glob)
 #endif
 
 
@@ -1385,20 +1269,15 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
                        / sizeof init_names->name[0]);
 
   meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
-  if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+  if (meta == GLOBPAT_NONE && (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.  */
       flags |= GLOB_NOCHECK;
     }
-  else if (meta == 0)
+  else if (meta == GLOBPAT_NONE)
     {
-      union
-      {
-       struct stat st;
-       struct_stat64 st64;
-      } ust;
       size_t patlen = strlen (pattern);
       size_t fullsize;
       bool alloca_fullname
@@ -1417,10 +1296,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
                        "/", 1),
               pattern, patlen + 1);
-      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-          ? (*pglob->gl_lstat) (fullname, &ust.st)
-           : __lstat64 (fullname, &ust.st64))
-          == 0)
+      if (glob_lstat (pglob, flags, fullname) == 0
          || errno == EOVERFLOW)
        /* We found this file to be existing.  Now tell the rest
           of the function to copy this name into the result.  */