Back to index

glibc  2.9
Defines | Functions
glob.c File Reference
#include <glob.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <alloca.h>
#include "getlogin_r.h"
#include "mempcpy.h"
#include "stat-macros.h"
#include "strdup.h"
#include <fnmatch.h>
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define __set_errno(val)   errno = (val)
#define dirent   direct
#define NAMLEN(dirent)   (dirent)->d_namlen
#define DIRENT_MUST_BE(d, t)   false
#define DIRENT_MIGHT_BE_SYMLINK(d)   true
#define DIRENT_MIGHT_BE_DIR(d)   true
#define REAL_DIR_ENTRY(dp)   (dp->d_ino != 0)
#define NAME_MAX   (sizeof (((struct dirent *) 0)->d_name))
#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 GETPW_R_SIZE_MAX()   (-1)
#define GET_LOGIN_NAME_MAX()   (-1)
#define attribute_hidden
#define DIRSEP_CHAR   '/'
#define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags)   link_exists2_p (dirname, dirnamelen, fname, pglob, flags)
#define INITIAL_COUNT   sizeof (init_names.name) / sizeof (init_names.name[0])

Functions

static const char * next_brace_sub (const char *begin, int flags) __THROW
static int glob_in_dir (const char *pattern, const char *directory, int flags, int(*errfunc)(const char *, int), glob_t *pglob)
int __glob_pattern_type (const char *pattern, int quote) attribute_hidden
static int prefix_array (const char *prefix, char **array, size_t n) __THROW
static int collated_compare (const void *, const void *)
int glob (char *pattern, int flags, int *errfunc, glob_t *pglob) const
void globfree (glob_t *pglob)
int __glob_pattern_type (char *pattern, int quote) const
int __glob_pattern_p (char *pattern, int quote) const
static int __attribute_noinline__ link_exists2_p (const char *dir, size_t dirlen, const char *fname, glob_t *pglob, int flags)

Define Documentation

#define __alloca   alloca

Definition at line 173 of file glob.c.

#define __glob_pattern_p   glob_pattern_p

Definition at line 176 of file glob.c.

#define __readdir   readdir

Definition at line 174 of file glob.c.

#define __readdir64   readdir64

Definition at line 175 of file glob.c.

#define __set_errno (   val)    errno = (val)

Definition at line 51 of file glob.c.

#define __stat (   fname,
  buf 
)    stat (fname, buf)

Definition at line 172 of file glob.c.

#define __stat64 (   fname,
  buf 
)    stat (fname, buf)

Definition at line 170 of file glob.c.

Definition at line 197 of file glob.c.

#define dirent   direct

Definition at line 58 of file glob.c.

#define DIRENT_MIGHT_BE_DIR (   d)    true

Definition at line 99 of file glob.c.

#define DIRENT_MIGHT_BE_SYMLINK (   d)    true

Definition at line 98 of file glob.c.

#define DIRENT_MUST_BE (   d,
  t 
)    false

Definition at line 97 of file glob.c.

#define DIRSEP_CHAR   '/'
#define GET_LOGIN_NAME_MAX ( )    (-1)

Definition at line 189 of file glob.c.

#define GETPW_R_SIZE_MAX ( )    (-1)

Definition at line 184 of file glob.c.

#define INITIAL_COUNT   sizeof (init_names.name) / sizeof (init_names.name[0])
#define link_exists_p (   dfd,
  dirname,
  dirnamelen,
  fname,
  pglob,
  flags 
)    link_exists2_p (dirname, dirnamelen, fname, pglob, flags)

Definition at line 1257 of file glob.c.

#define NAME_MAX   (sizeof (((struct dirent *) 0)->d_name))

Definition at line 147 of file glob.c.

#define NAMLEN (   dirent)    (dirent)->d_namlen

Definition at line 59 of file glob.c.

#define REAL_DIR_ENTRY (   dp)    (dp->d_ino != 0)

Definition at line 138 of file glob.c.

#define struct_stat64   struct stat

Definition at line 171 of file glob.c.


Function Documentation

int __glob_pattern_p ( char *  pattern,
int  quote 
) const

Definition at line 1206 of file glob.c.

{
  return __glob_pattern_type (pattern, quote) == 1;
}

Here is the call graph for this function:

int __glob_pattern_type ( const char *  pattern,
int  quote 
)

Here is the caller graph for this function:

int __glob_pattern_type ( char *  pattern,
int  quote 
) const

Definition at line 1167 of file glob.c.

{
  register const char *p;
  int ret = 0;

  for (p = pattern; *p != '\0'; ++p)
    switch (*p)
      {
      case '?':
      case '*':
       return 1;

      case '\\':
       if (quote)
         {
           if (p[1] != '\0')
             ++p;
           ret |= 2;
         }
       break;

      case '[':
       ret |= 4;
       break;

      case ']':
       if (ret & 4)
         return 1;
       break;
      }

  return ret;
}
static int collated_compare ( const void *  a,
const void *  b 
) [static]

Definition at line 208 of file glob.c.

{
  unsigned int depth = 0;
  while (*cp != '\0')
    if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
      {
       if (*++cp == '\0')
         break;
       ++cp;
      }
    else
      {
       if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
         break;

       if (*cp++ == '{')
         depth++;
      }

  return *cp != '\0' ? cp : NULL;
}
int glob ( char *  pattern,
int  flags,
int errfunc,
glob_t pglob 
) const

Definition at line 249 of file glob.c.

{
  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)
    {
      __set_errno (EINVAL);
      return -1;
    }

  if (!(flags & GLOB_DOOFFS))
    /* 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;

  if (flags & GLOB_BRACE)
    {
      const char *begin;

      if (flags & GLOB_NOESCAPE)
       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;
           }
       }

      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;
#ifdef __GNUC__
         char onealt[strlen (pattern) - 1];
#else
         char *onealt = (char *) 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);

         /* 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 illegal expression.  */
#ifndef __GNUC__
             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 illegal expression.  */
#ifndef __GNUC__
                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)
              {
#ifndef __GNUC__
                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);
           }

#ifndef __GNUC__
         free (onealt);
#endif

         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
     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.  */
      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;
       }
      else
       {
         filename = pattern;
#ifdef _AMIGA
         dirname = "";
#else
         dirname = ".";
#endif
         dirlen = 0;
       }
    }
  else if (filename == pattern
          || (filename == pattern + 1 && pattern[0] == '\\'
              && (flags & GLOB_NOESCAPE) == 0))
    {
      /* "/pattern" or "\\/pattern".  */
      dirname = "/";
      dirlen = 1;
      ++filename;
    }
  else
    {
      char *newp;
      dirlen = filename - pattern;
#if defined __MSDOS__ || defined WINDOWS32
      if (*filename == ':'
         || (filename > pattern + 1 && filename[-1] == ':'))
       {
         char *drive_spec;

         ++dirlen;
         drive_spec = (char *) __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 = (char *) __alloca (dirlen + 1);
      *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
      dirname = newp;
      ++filename;

      if (filename[0] == '\0'
#if defined __MSDOS__ || defined WINDOWS32
          && dirname[dirlen - 1] != ':'
         && (dirlen < 3 || dirname[dirlen - 2] != ':'
             || dirname[dirlen - 1] != '/')
#endif
         && dirlen > 1)
       /* "pattern/".  Expand "pattern", appending slashes.  */
       {
         int orig_flags = flags;
         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);
              }
           }
         int 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))
    {
      pglob->gl_pathc = 0;
      if (!(flags & GLOB_DOOFFS))
        pglob->gl_pathv = NULL;
      else
       {
         size_t i;
         pglob->gl_pathv = (char **) 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;

#ifndef VMS
  if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
    {
      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:";
# else
#  ifdef WINDOWS32
         if (home_dir == NULL || home_dir[0] == '\0')
            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 = (char *) __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;

#    ifndef _LIBC
                if (pwbuflen == -1)
                  /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
                     Try a moderate value.  */
                  pwbuflen = 1024;
#    endif
                pwtmpbuf = (char *) __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);
#    else
                    pwbuflen *= 2;
                    pwtmpbuf = (char *) __alloca (pwbuflen);
#    endif
                    __set_errno (save);
                  }
#   else
                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.  */
           }
#  endif /* WINDOWS32 */
# endif
         /* 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 = (char *) __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;
         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 = (char *) __alloca (end_name - dirname);
             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;

#   ifndef _LIBC
           if (buflen == -1)
             /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
               moderate value.  */
             buflen = 1024;
#   endif
           pwtmpbuf = (char *) __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);
#   else
              buflen *= 2;
              pwtmpbuf = __alloca (buflen);
#   endif
              __set_errno (save);
             }
#  else
           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 = (char *) __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.  */
    }
#endif /* Not VMS.  */

  /* Now test whether we looked for "~" or "~NAME".  In this case we
     can give the answer now.  */
  if (filename == NULL)
    {
      struct stat st;
      struct_stat64 st64;

      /* Return the directory if we don't check for error or if it exists.  */
      if ((flags & GLOB_NOCHECK)
         || (((__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
           = (char **) 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;
    }

  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.  */
      size_t i;

      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_NOESCAPE
                            | GLOB_ALTDIRFUNC))
                    | GLOB_NOSORT | GLOB_ONLYDIR),
                   errfunc, &dirs);
      if (status != 0)
       {
         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 (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;
             }
         }
#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;
           }
       }

      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.  */
      if (pglob->gl_pathc + pglob->gl_offs == oldcount)
       {
       no_matches:
         /* No matches.  */
         if (flags & GLOB_NOCHECK)
           {
             int newcount = pglob->gl_pathc + pglob->gl_offs;
             char **new_gl_pathv;

             new_gl_pathv = (char **) 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)
       {
         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;
           }
       }
    }

  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);
    }

  return 0;
}

Here is the call graph for this function:

static int glob_in_dir ( const char *  pattern,
const char *  directory,
int  flags,
int(*)(const char *, int errfunc,
glob_t pglob 
) [static]

Definition at line 1268 of file glob.c.

{
  size_t dirlen = strlen (directory);
  void *stream = NULL;
  struct globnames
    {
      struct globnames *next;
      size_t count;
      char *name[64];
    };
#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;

  init_names.next = NULL;
  init_names.count = INITIAL_COUNT;

  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.  */
      flags |= GLOB_NOCHECK;
    }
  else if (meta == 0)
    {
      /* Since we use the normal file functions we can also use stat()
        to verify the file is there.  */
      struct stat st;
      struct_stat64 st64;
      size_t patlen = strlen (pattern);
      char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);

      mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
                     "/", 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
    {
      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
       {
#ifdef _LIBC
         int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
                   ? -1 : dirfd ((DIR *) stream));
#endif
         int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
                        | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
#if defined _AMIGA || defined VMS
                        | FNM_CASEFOLD
#endif
                        );
         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 (__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 = (__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)
              {
                /* 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 = NAMLEN (d);
                    names->name[cur] = (char *) 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->name[cur] = (char *) malloc (len + 1);
      if (names->name[cur] == NULL)
       goto memory_error;
      *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
    }

  int result = GLOB_NOMATCH;
  if (nfound != 0)
    {
      result = 0;

      char **new_gl_pathv;
      new_gl_pathv
       = (char **) realloc (pglob->gl_pathv,
                          (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
                          * sizeof (char *));
      if (new_gl_pathv == NULL)
       {
       memory_error:
         while (1)
           {
             struct globnames *old = names;
             for (size_t 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;
             for (size_t 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;
       }
    }

  if (stream != NULL)
    {
      save = errno;
      if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
       (*pglob->gl_closedir) (stream);
      else
       closedir (stream);
      __set_errno (save);
    }

  return result;
}

Here is the call graph for this function:

void globfree ( glob_t pglob)

Definition at line 1071 of file glob.c.

{
  if (pglob->gl_pathv != NULL)
    {
      size_t i;
      for (i = 0; i < pglob->gl_pathc; ++i)
       free (pglob->gl_pathv[pglob->gl_offs + i]);
      free (pglob->gl_pathv);
      pglob->gl_pathv = NULL;
    }
}
static int __attribute_noinline__ link_exists2_p ( const char *  dir,
size_t  dirlen,
const char *  fname,
glob_t pglob,
int  flags 
) [static]

Definition at line 1225 of file glob.c.

{
  size_t fnamelen = strlen (fname);
  char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
  struct stat st;
# ifndef _LIBC
  struct_stat64 st64;
# endif

  mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
          fname, fnamelen + 1);

# ifdef _LIBC
  return (*pglob->gl_stat) (fullname, &st) == 0;
# else
  return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
          ? (*pglob->gl_stat) (fullname, &st)
          : __stat64 (fullname, &st64)) == 0);
# endif
}

Here is the call graph for this function:

static const char* next_brace_sub ( const char *  begin,
int  flags 
) [static]

Here is the caller graph for this function:

static int prefix_array ( const char *  prefix,
char **  array,
size_t  n 
) [static]

Definition at line 1110 of file glob.c.

{
  register size_t i;
  size_t dirlen = strlen (dirname);
#if defined __MSDOS__ || defined WINDOWS32
  int sep_char = '/';
# define DIRSEP_CHAR sep_char
#else
# define DIRSEP_CHAR '/'
#endif

  if (dirlen == 1 && dirname[0] == '/')
    /* DIRNAME is just "/", so normal prepending would get us "//foo".
       We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
    dirlen = 0;
#if defined __MSDOS__ || defined WINDOWS32
  else if (dirlen > 1)
    {
      if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
       /* 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 = ':';
       }
    }
#endif

  for (i = 0; i < n; ++i)
    {
      size_t eltlen = strlen (array[i]) + 1;
      char *new = (char *) malloc (dirlen + 1 + eltlen);
      if (new == NULL)
       {
         while (i > 0)
           free (array[--i]);
         return 1;
       }

      {
       char *endp = mempcpy (new, dirname, dirlen);
       *endp++ = DIRSEP_CHAR;
       mempcpy (endp, array[i], eltlen);
      }
      free (array[i]);
      array[i] = new;
    }

  return 0;
}

Here is the call graph for this function: