rpm 5.3.7

rpmio/glob.c

Go to the documentation of this file.
00001 /*@-bounds@*/
00002 /*@-branchstate@*/
00003 /*@-compdef@*/
00004 /*@-immediatetrans@*/
00005 /*@-internalglobs@*/
00006 /*@-loopswitchbreak@*/
00007 /*@-modnomods@*/
00008 /*@-mods@*/
00009 /*@-moduncon@*/
00010 /*@-modunconnomods@*/
00011 /*@-noeffectuncon@*/
00012 /*@-nullpass@*/
00013 /*@-onlytrans@*/
00014 /*@-protoparammatch@*/
00015 /*@-retalias@*/
00016 /*@-retvalint@*/
00017 /*@-shadow@*/
00018 /*@-sizeoftype@*/
00019 /*@-temptrans@*/
00020 /*@-type@*/
00021 /*@-unqualifiedtrans@*/
00022 /*@-unrecog@*/
00023 
00024 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
00025 
00026    This library is free software; you can redistribute it and/or
00027    modify it under the terms of the GNU Library General Public License as
00028    published by the Free Software Foundation; either version 2 of the
00029    License, or (at your option) any later version.
00030 
00031    This library is distributed in the hope that it will be useful,
00032    but WITHOUT ANY WARRANTY; without even the implied warranty of
00033    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00034    Library General Public License for more details.
00035 
00036    You should have received a copy of the GNU Library General Public
00037    License along with this library; see the file COPYING.LIB.  If not,
00038    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00039    Boston, MA 02111-1307, USA.  */
00040 
00041 /* AIX requires this to be the first thing in the file.  */
00042 #if defined _AIX && !defined __GNUC__
00043  #pragma alloca
00044 #endif
00045 
00046 /*@access DIR@*/
00047 
00048 # include "system.h"
00049 
00050 /* Needed for offsetof() */
00051 # include <stddef.h>
00052 
00053 # include <assert.h>
00054 
00055 #undef __alloca
00056 #define __alloca        alloca
00057 #define __stat          stat
00058 #define NAMLEN(_d)      NLENGTH(_d)
00059 
00060 /* If the system has the `struct dirent64' type we use it internally.  */
00061 # if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
00062 #  define CONVERT_D_NAMLEN(d64, d32)
00063 # else
00064 #  define CONVERT_D_NAMLEN(d64, d32) \
00065   (d64)->d_namlen = (d32)->d_namlen;
00066 # endif
00067 
00068 # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
00069 #  define CONVERT_D_INO(d64, d32)
00070 # else
00071 #  define CONVERT_D_INO(d64, d32) \
00072   (d64)->d_ino = (d32)->d_ino;
00073 # endif
00074 
00075 # ifdef _DIRENT_HAVE_D_TYPE
00076 #  define CONVERT_D_TYPE(d64, d32) \
00077   (d64)->d_type = (d32)->d_type;
00078 # else
00079 #  define CONVERT_D_TYPE(d64, d32)
00080 # endif
00081 
00082 # define CONVERT_DIRENT_DIRENT64(d64, d32) \
00083   memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1);                    \
00084   CONVERT_D_NAMLEN (d64, d32)                                                 \
00085   CONVERT_D_INO (d64, d32)                                                    \
00086   CONVERT_D_TYPE (d64, d32)
00087 
00088 #if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
00089 /* Posix does not require that the d_ino field be present, and some
00090    systems do not provide it. */
00091 # define REAL_DIR_ENTRY(dp) 1
00092 #else
00093 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
00094 #endif /* POSIX */
00095 
00096 #include <errno.h>
00097 #ifndef __set_errno
00098 # define __set_errno(val) errno = (val)
00099 #endif
00100 
00101 #if !defined(NAME_MAX)  /* XXX OpenIndiana needs this. */
00102 #define NAME_MAX        255
00103 #endif
00104 
00105 /* Outcomment the following line for production quality code.  */
00106 /* #define NDEBUG 1 */
00107 
00108 #define GLOB_INTERFACE_VERSION 1
00109 
00110 /*@null@*/
00111 static inline const char *next_brace_sub __P ((const char *begin))
00112         /*@*/;
00113 static int glob_in_dir __P ((const char *pattern, const char *directory,
00114                              int flags,
00115                              int (*errfunc) (const char *, int),
00116                              glob_t *pglob))
00117         /*@globals fileSystem @*/
00118         /*@modifies fileSystem @*/;
00119 static int prefix_array __P ((const char *prefix, char **array, size_t n))
00120         /*@*/;
00121 static int collated_compare __P ((const __ptr_t, const __ptr_t))
00122         /*@*/;
00123 
00124 
00125 /* Find the end of the sub-pattern in a brace expression.  We define
00126    this as an inline function if the compiler permits.  */
00127 static inline const char *
00128 next_brace_sub (const char *begin)
00129 {
00130   unsigned int depth = 0;
00131   const char *cp = begin;
00132 
00133   while (1)
00134     {
00135       if (depth == 0)
00136         {
00137           if (*cp != ',' && *cp != '}' && *cp != '\0')
00138             {
00139               if (*cp == '{')
00140                 ++depth;
00141               ++cp;
00142               continue;
00143             }
00144         }
00145       else
00146         {
00147           while (*cp != '\0' && (*cp != '}' || depth > 0))
00148             {
00149               if (*cp == '}')
00150                 --depth;
00151               ++cp;
00152             }
00153           if (*cp == '\0')
00154             /* An incorrectly terminated brace expression.  */
00155             return NULL;
00156 
00157           continue;
00158         }
00159       break;
00160     }
00161 
00162   return cp;
00163 }
00164 
00165 static int __glob_pattern_p (const char *pattern, int quote);
00166 
00167 /* Do glob searching for PATTERN, placing results in PGLOB.
00168    The bits defined above may be set in FLAGS.
00169    If a directory cannot be opened or read and ERRFUNC is not nil,
00170    it is called with the pathname that caused the error, and the
00171    `errno' value from the failing call; if it returns non-zero
00172    `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
00173    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
00174    Otherwise, `glob' returns zero.  */
00175 int
00176 glob (const char *pattern, int flags,
00177         int (*errfunc) __P ((const char *, int)), glob_t *pglob)
00178 {
00179   const char *filename;
00180   const char *dirname;
00181   size_t dirlen;
00182   int status;
00183   int oldcount;
00184 
00185   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
00186     {
00187       __set_errno (EINVAL);
00188       return -1;
00189     }
00190 
00191   if (flags & GLOB_BRACE)
00192     {
00193       const char *begin = strchr (pattern, '{');
00194       if (begin != NULL)
00195         {
00196           /* Allocate working buffer large enough for our work.  Note that
00197             we have at least an opening and closing brace.  */
00198           int firstc;
00199           char *alt_start;
00200           const char *p;
00201           const char *next;
00202           const char *rest;
00203           size_t rest_len;
00204 #ifdef __GNUC__
00205           char onealt[strlen (pattern) - 1];
00206 #else
00207           char *onealt = (char *) xmalloc (strlen (pattern) - 1);
00208           if (onealt == NULL)
00209             {
00210               if (!(flags & GLOB_APPEND))
00211                 globfree (pglob);
00212               return GLOB_NOSPACE;
00213             }
00214 #endif
00215 
00216           /* We know the prefix for all sub-patterns.  */
00217 #ifdef HAVE_MEMPCPY
00218           alt_start = mempcpy (onealt, pattern, begin - pattern);
00219 #else
00220           memcpy (onealt, pattern, begin - pattern);
00221           alt_start = &onealt[begin - pattern];
00222 #endif
00223 
00224           /* Find the first sub-pattern and at the same time find the
00225              rest after the closing brace.  */
00226           next = next_brace_sub (begin + 1);
00227           if (next == NULL)
00228             {
00229               /* It is an illegal expression.  */
00230 #ifndef __GNUC__
00231               free (onealt);
00232 #endif
00233               return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
00234             }
00235 
00236           /* Now find the end of the whole brace expression.  */
00237           rest = next;
00238           while (*rest != '}')
00239             {
00240               rest = next_brace_sub (rest + 1);
00241               if (rest == NULL)
00242                 {
00243                   /* It is an illegal expression.  */
00244 #ifndef __GNUC__
00245                   free (onealt);
00246 #endif
00247                   return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
00248                 }
00249             }
00250           /* Please note that we now can be sure the brace expression
00251              is well-formed.  */
00252           rest_len = strlen (++rest) + 1;
00253 
00254           /* We have a brace expression.  BEGIN points to the opening {,
00255              NEXT points past the terminator of the first element, and END
00256              points past the final }.  We will accumulate result names from
00257              recursive runs for each brace alternative in the buffer using
00258              GLOB_APPEND.  */
00259 
00260           if (!(flags & GLOB_APPEND))
00261             {
00262               /* This call is to set a new vector, so clear out the
00263                  vector so we can append to it.  */
00264               pglob->gl_pathc = 0;
00265               pglob->gl_pathv = NULL;
00266             }
00267           firstc = pglob->gl_pathc;
00268 
00269           p = begin + 1;
00270           while (1)
00271             {
00272               int result;
00273 
00274               /* Construct the new glob expression.  */
00275 #ifdef HAVE_MEMPCPY
00276               mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
00277 #else
00278               memcpy (alt_start, p, next - p);
00279               memcpy (&alt_start[next - p], rest, rest_len);
00280 #endif
00281 
00282               result = glob (onealt,
00283                              ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
00284                               | GLOB_APPEND), errfunc, pglob);
00285 
00286               /* If we got an error, return it.  */
00287               if (result && result != GLOB_NOMATCH)
00288                 {
00289 #ifndef __GNUC__
00290                   free (onealt);
00291 #endif
00292                   if (!(flags & GLOB_APPEND))
00293                     globfree (pglob);
00294                   return result;
00295                 }
00296 
00297               if (*next == '}')
00298                 /* We saw the last entry.  */
00299                 break;
00300 
00301               p = next + 1;
00302               next = next_brace_sub (p);
00303               assert (next != NULL);
00304             }
00305 
00306 #ifndef __GNUC__
00307           free (onealt);
00308 #endif
00309 
00310           if ((int)pglob->gl_pathc != firstc)
00311             /* We found some entries.  */
00312             return 0;
00313           else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
00314             return GLOB_NOMATCH;
00315         }
00316     }
00317 
00318   /* Find the filename.  */
00319   filename = strrchr (pattern, '/');
00320 #if defined __MSDOS__ || defined WINDOWS32
00321   /* The case of "d:pattern".  Since `:' is not allowed in
00322      file names, we can safely assume that wherever it
00323      happens in pattern, it signals the filename part.  This
00324      is so we could some day support patterns like "[a-z]:foo".  */
00325   if (filename == NULL)
00326     filename = strchr (pattern, ':');
00327 #endif /* __MSDOS__ || WINDOWS32 */
00328   if (filename == NULL)
00329     {
00330       /* This can mean two things: a simple name or "~name".  The latter
00331          case is nothing but a notation for a directory.  */
00332       if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
00333         {
00334           dirname = pattern;
00335           dirlen = strlen (pattern);
00336 
00337           /* Set FILENAME to NULL as a special flag.  This is ugly but
00338              other solutions would require much more code.  We test for
00339              this special case below.  */
00340           filename = NULL;
00341         }
00342       else
00343         {
00344           filename = pattern;
00345 #ifdef _AMIGA
00346           dirname = "";
00347 #else
00348           dirname = ".";
00349 #endif
00350           dirlen = 0;
00351         }
00352     }
00353   else if (filename == pattern)
00354     {
00355       /* "/pattern".  */
00356       dirname = "/";
00357       dirlen = 1;
00358       ++filename;
00359     }
00360   else
00361     {
00362       char *newp;
00363       dirlen = filename - pattern;
00364 #if defined __MSDOS__ || defined WINDOWS32
00365       if (*filename == ':'
00366           || (filename > pattern + 1 && filename[-1] == ':'))
00367         {
00368           char *drive_spec;
00369 
00370           ++dirlen;
00371           drive_spec = (char *) __alloca (dirlen + 1);
00372 #ifdef HAVE_MEMPCPY
00373           *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
00374 #else
00375           memcpy (drive_spec, pattern, dirlen);
00376           drive_spec[dirlen] = '\0';
00377 #endif
00378           /* For now, disallow wildcards in the drive spec, to
00379              prevent infinite recursion in glob.  */
00380           if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
00381             return GLOB_NOMATCH;
00382           /* If this is "d:pattern", we need to copy `:' to DIRNAME
00383              as well.  If it's "d:/pattern", don't remove the slash
00384              from "d:/", since "d:" and "d:/" are not the same.*/
00385         }
00386 #endif
00387       newp = (char *) __alloca (dirlen + 1);
00388 #ifdef HAVE_MEMPCPY
00389       *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
00390 #else
00391       memcpy (newp, pattern, dirlen);
00392       newp[dirlen] = '\0';
00393 #endif
00394       dirname = newp;
00395       ++filename;
00396 
00397       if (filename[0] == '\0'
00398 #if defined __MSDOS__ || defined WINDOWS32
00399           && dirname[dirlen - 1] != ':'
00400           && (dirlen < 3 || dirname[dirlen - 2] != ':'
00401               || dirname[dirlen - 1] != '/')
00402 #endif
00403           && dirlen > 1)
00404         /* "pattern/".  Expand "pattern", appending slashes.  */
00405         {
00406           int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
00407           if (val == 0)
00408             pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
00409                                | (flags & GLOB_MARK));
00410           return val;
00411         }
00412     }
00413 
00414   if (!(flags & GLOB_APPEND))
00415     {
00416       pglob->gl_pathc = 0;
00417       pglob->gl_pathv = NULL;
00418     }
00419 
00420   oldcount = pglob->gl_pathc;
00421 
00422 #ifndef VMS
00423   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
00424     {
00425       if (dirname[1] == '\0' || dirname[1] == '/')
00426         {
00427           /* Look up home directory.  */
00428           const char *home_dir = getenv ("HOME");
00429 # ifdef _AMIGA
00430           if (home_dir == NULL || home_dir[0] == '\0')
00431             home_dir = "SYS:";
00432 # else
00433 #  ifdef WINDOWS32
00434           if (home_dir == NULL || home_dir[0] == '\0')
00435             home_dir = "c:/users/default"; /* poor default */
00436 #  else
00437           if (home_dir == NULL || home_dir[0] == '\0')
00438             {
00439               int success;
00440               char *name;
00441 #   if defined HAVE_GETLOGIN_R || defined _LIBC
00442               size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1;
00443 
00444               if (buflen == 0)
00445                 /* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
00446                    a moderate value.  */
00447                 buflen = 20;
00448               name = (char *) __alloca (buflen);
00449 
00450               success = getlogin_r (name, buflen) >= 0;
00451 #   else
00452               success = (name = getlogin ()) != NULL;
00453 #   endif
00454               if (success)
00455                 {
00456                   struct passwd *p;
00457 #   if defined HAVE_GETPWNAM_R || defined _LIBC
00458                   size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX);
00459                   char *pwtmpbuf;
00460                   struct passwd pwbuf;
00461                   int save = errno;
00462 
00463                   if (pwbuflen == -1)
00464                     /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
00465                        Try a moderate value.  */
00466                     pwbuflen = 1024;
00467                   pwtmpbuf = (char *) __alloca (pwbuflen);
00468 
00469                   while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
00470                          != 0)
00471                     {
00472                       if (errno != ERANGE)
00473                         {
00474                           p = NULL;
00475                           break;
00476                         }
00477                       pwbuflen *= 2;
00478                       pwtmpbuf = (char *) __alloca (pwbuflen);
00479                       __set_errno (save);
00480                     }
00481 #   else
00482                   p = getpwnam (name);
00483 #   endif
00484                   if (p != NULL)
00485                     home_dir = p->pw_dir;
00486                 }
00487             }
00488           if (home_dir == NULL || home_dir[0] == '\0')
00489             {
00490               if (flags & GLOB_TILDE_CHECK)
00491                 return GLOB_NOMATCH;
00492               else
00493                 home_dir = "~"; /* No luck.  */
00494             }
00495 #  endif /* WINDOWS32 */
00496 # endif
00497           /* Now construct the full directory.  */
00498           if (dirname[1] == '\0')
00499             dirname = home_dir;
00500           else
00501             {
00502               char *newp;
00503               size_t home_len = strlen (home_dir);
00504               newp = (char *) __alloca (home_len + dirlen);
00505 # ifdef HAVE_MEMPCPY
00506               mempcpy (mempcpy (newp, home_dir, home_len),
00507                        &dirname[1], dirlen);
00508 # else
00509               memcpy (newp, home_dir, home_len);
00510               memcpy (&newp[home_len], &dirname[1], dirlen);
00511 # endif
00512               dirname = newp;
00513             }
00514         }
00515 # if !defined _AMIGA && !defined WINDOWS32
00516       else
00517         {
00518           char *end_name = strchr (dirname, '/');
00519           const char *user_name;
00520           const char *home_dir;
00521 
00522           if (end_name == NULL)
00523             user_name = dirname + 1;
00524           else
00525             {
00526               char *newp;
00527               newp = (char *) __alloca (end_name - dirname);
00528 # ifdef HAVE_MEMPCPY
00529               *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
00530                 = '\0';
00531 # else
00532               memcpy (newp, dirname + 1, end_name - dirname);
00533               newp[end_name - dirname - 1] = '\0';
00534 # endif
00535               user_name = newp;
00536             }
00537 
00538           /* Look up specific user's home directory.  */
00539           {
00540             struct passwd *p;
00541 #  if defined HAVE_GETPWNAM_R || defined _LIBC
00542             size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
00543             char *pwtmpbuf;
00544             struct passwd pwbuf;
00545             int save = errno;
00546 
00547             if (buflen == -1)
00548               /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
00549                  moderate value.  */
00550               buflen = 1024;
00551             pwtmpbuf = (char *) __alloca (buflen);
00552 
00553             while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
00554               {
00555                 if (errno != ERANGE)
00556                   {
00557                     p = NULL;
00558                     break;
00559                   }
00560                 buflen *= 2;
00561                 pwtmpbuf = __alloca (buflen);
00562                 __set_errno (save);
00563               }
00564 #  else
00565             p = getpwnam (user_name);
00566 #  endif
00567             if (p != NULL)
00568               home_dir = p->pw_dir;
00569             else
00570               home_dir = NULL;
00571           }
00572           /* If we found a home directory use this.  */
00573           if (home_dir != NULL)
00574             {
00575               char *newp;
00576               size_t home_len = strlen (home_dir);
00577               size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
00578               newp = (char *) __alloca (home_len + rest_len + 1);
00579 #  ifdef HAVE_MEMPCPY
00580               *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
00581                                   end_name, rest_len)) = '\0';
00582 #  else
00583               memcpy (newp, home_dir, home_len);
00584               memcpy (&newp[home_len], end_name, rest_len);
00585               newp[home_len + rest_len] = '\0';
00586 #  endif
00587               dirname = newp;
00588             }
00589           else
00590             if (flags & GLOB_TILDE_CHECK)
00591               /* We have to regard it as an error if we cannot find the
00592                  home directory.  */
00593               return GLOB_NOMATCH;
00594         }
00595 # endif /* Not Amiga && not WINDOWS32.  */
00596     }
00597 #endif  /* Not VMS.  */
00598 
00599   /* Now test whether we looked for "~" or "~NAME".  In this case we
00600      can give the answer now.  */
00601   if (filename == NULL)
00602     {
00603       struct stat st;
00604 
00605       /* Return the directory if we don't check for error or if it exists.  */
00606       if ((flags & GLOB_NOCHECK)
00607           || (((flags & GLOB_ALTDIRFUNC)
00608                ? (*pglob->gl_stat) (dirname, &st)
00609                : __stat (dirname, &st)) == 0
00610               && S_ISDIR (st.st_mode)))
00611         {
00612           pglob->gl_pathv
00613             = (char **) xrealloc (pglob->gl_pathv,
00614                                  (pglob->gl_pathc +
00615                                   ((flags & GLOB_DOOFFS) ?
00616                                    pglob->gl_offs : 0) +
00617                                   1 + 1) *
00618                                  sizeof (char *));
00619           if (pglob->gl_pathv == NULL)
00620             return GLOB_NOSPACE;
00621 
00622           if (flags & GLOB_DOOFFS)
00623             while (pglob->gl_pathc < pglob->gl_offs)
00624               pglob->gl_pathv[pglob->gl_pathc++] = NULL;
00625 
00626 #if defined HAVE_STRDUP || defined _LIBC
00627           pglob->gl_pathv[pglob->gl_pathc] = xstrdup (dirname);
00628 #else
00629           {
00630             size_t len = strlen (dirname) + 1;
00631             char *dircopy = xmalloc (len);
00632             if (dircopy != NULL)
00633               pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname,
00634                                                          len);
00635           }
00636 #endif
00637           if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
00638             {
00639               free (pglob->gl_pathv);
00640               return GLOB_NOSPACE;
00641             }
00642           pglob->gl_pathv[++pglob->gl_pathc] = NULL;
00643           pglob->gl_flags = flags;
00644 
00645           return 0;
00646         }
00647 
00648       /* Not found.  */
00649       return GLOB_NOMATCH;
00650     }
00651 
00652   if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
00653     {
00654       /* The directory name contains metacharacters, so we
00655          have to glob for the directory, and then glob for
00656          the pattern in each directory found.  */
00657       glob_t dirs;
00658       register int i;
00659 
00660       if ((flags & GLOB_ALTDIRFUNC) != 0)
00661         {
00662           /* Use the alternative access functions also in the recursive
00663              call.  */
00664           dirs.gl_opendir = pglob->gl_opendir;
00665           dirs.gl_readdir = pglob->gl_readdir;
00666           dirs.gl_closedir = pglob->gl_closedir;
00667           dirs.gl_stat = pglob->gl_stat;
00668           dirs.gl_lstat = pglob->gl_lstat;
00669         }
00670 
00671       status = glob (dirname,
00672                      ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
00673                                 | GLOB_ALTDIRFUNC))
00674                       | GLOB_NOSORT | GLOB_ONLYDIR),
00675                      errfunc, &dirs);
00676       if (status != 0)
00677         return status;
00678 
00679       /* We have successfully globbed the preceding directory name.
00680          For each name we found, call glob_in_dir on it and FILENAME,
00681          appending the results to PGLOB.  */
00682       for (i = 0; i < (int)dirs.gl_pathc; ++i)
00683         {
00684           int old_pathc;
00685 
00686 #ifdef  SHELL
00687           {
00688             /* Make globbing interruptible in the bash shell. */
00689             extern int interrupt_state;
00690 
00691             if (interrupt_state)
00692               {
00693                 globfree (&dirs);
00694                 globfree (&files);
00695                 return GLOB_ABORTED;
00696               }
00697           }
00698 #endif /* SHELL.  */
00699 
00700           old_pathc = pglob->gl_pathc;
00701           status = glob_in_dir (filename, dirs.gl_pathv[i],
00702                                 ((flags | GLOB_APPEND)
00703                                  & ~(GLOB_NOCHECK | GLOB_ERR)),
00704                                 errfunc, pglob);
00705           if (status == GLOB_NOMATCH)
00706             /* No matches in this directory.  Try the next.  */
00707             continue;
00708 
00709           if (status != 0)
00710             {
00711               globfree (&dirs);
00712               globfree (pglob);
00713               return status;
00714             }
00715 
00716           /* Stick the directory on the front of each name.  */
00717           if (prefix_array (dirs.gl_pathv[i],
00718                             &pglob->gl_pathv[old_pathc],
00719                             pglob->gl_pathc - old_pathc))
00720             {
00721               globfree (&dirs);
00722               globfree (pglob);
00723               return GLOB_NOSPACE;
00724             }
00725         }
00726 
00727       flags |= GLOB_MAGCHAR;
00728 
00729       /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
00730          But if we have not found any matching entry and thie GLOB_NOCHECK
00731          flag was set we must return the list consisting of the disrectory
00732          names followed by the filename.  */
00733       if ((int)pglob->gl_pathc == oldcount)
00734         {
00735           /* No matches.  */
00736           if (flags & GLOB_NOCHECK)
00737             {
00738               size_t filename_len = strlen (filename) + 1;
00739               char **new_pathv;
00740               struct stat st;
00741 
00742               /* This is an pessimistic guess about the size.  */
00743               pglob->gl_pathv
00744                 = (char **) xrealloc (pglob->gl_pathv,
00745                                      (pglob->gl_pathc +
00746                                       ((flags & GLOB_DOOFFS) ?
00747                                        pglob->gl_offs : 0) +
00748                                       dirs.gl_pathc + 1) *
00749                                      sizeof (char *));
00750               if (pglob->gl_pathv == NULL)
00751                 {
00752                   globfree (&dirs);
00753                   return GLOB_NOSPACE;
00754                 }
00755 
00756               if (flags & GLOB_DOOFFS)
00757                 while (pglob->gl_pathc < pglob->gl_offs)
00758                   pglob->gl_pathv[pglob->gl_pathc++] = NULL;
00759 
00760               for (i = 0; i < (int)dirs.gl_pathc; ++i)
00761                 {
00762                   const char *dir = dirs.gl_pathv[i];
00763                   size_t dir_len = strlen (dir);
00764 
00765                   /* First check whether this really is a directory.  */
00766                   if (((flags & GLOB_ALTDIRFUNC)
00767                        ? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0
00768                       || !S_ISDIR (st.st_mode))
00769                     /* No directory, ignore this entry.  */
00770                     continue;
00771 
00772                   pglob->gl_pathv[pglob->gl_pathc] = xmalloc (dir_len + 1
00773                                                              + filename_len);
00774                   if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
00775                     {
00776                       globfree (&dirs);
00777                       globfree (pglob);
00778                       return GLOB_NOSPACE;
00779                     }
00780 
00781 #ifdef HAVE_MEMPCPY
00782                   mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc],
00783                                              dir, dir_len),
00784                                     "/", 1),
00785                            filename, filename_len);
00786 #else
00787                   memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len);
00788                   pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/';
00789                   memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1],
00790                           filename, filename_len);
00791 #endif
00792                   ++pglob->gl_pathc;
00793                 }
00794 
00795               pglob->gl_pathv[pglob->gl_pathc] = NULL;
00796               pglob->gl_flags = flags;
00797 
00798               /* Now we know how large the gl_pathv vector must be.  */
00799               new_pathv = (char **) xrealloc (pglob->gl_pathv,
00800                                              ((pglob->gl_pathc + 1)
00801                                               * sizeof (char *)));
00802               if (new_pathv != NULL)
00803                 pglob->gl_pathv = new_pathv;
00804             }
00805           else
00806             return GLOB_NOMATCH;
00807         }
00808 
00809       globfree (&dirs);
00810     }
00811   else
00812     {
00813       status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
00814       if (status != 0)
00815         return status;
00816 
00817       if (dirlen > 0)
00818         {
00819           /* Stick the directory on the front of each name.  */
00820           int ignore = oldcount;
00821 
00822           if ((flags & GLOB_DOOFFS) && ignore < (int)pglob->gl_offs)
00823             ignore = pglob->gl_offs;
00824 
00825           if (prefix_array (dirname,
00826                             &pglob->gl_pathv[ignore],
00827                             pglob->gl_pathc - ignore))
00828             {
00829               globfree (pglob);
00830               return GLOB_NOSPACE;
00831             }
00832         }
00833     }
00834 
00835   if (flags & GLOB_MARK)
00836     {
00837       /* Append slashes to directory names.  */
00838       int i;
00839       struct stat st;
00840       for (i = oldcount; i < (int)pglob->gl_pathc; ++i)
00841         if (((flags & GLOB_ALTDIRFUNC)
00842              ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
00843              : __stat (pglob->gl_pathv[i], &st)) == 0
00844             && S_ISDIR (st.st_mode))
00845           {
00846             size_t len = strlen (pglob->gl_pathv[i]) + 2;
00847             char *new = xrealloc (pglob->gl_pathv[i], len);
00848             if (new == NULL)
00849               {
00850                 globfree (pglob);
00851                 return GLOB_NOSPACE;
00852               }
00853             strcpy (&new[len - 2], "/");
00854             pglob->gl_pathv[i] = new;
00855           }
00856     }
00857 
00858   if (!(flags & GLOB_NOSORT))
00859     {
00860       /* Sort the vector.  */
00861       int non_sort = oldcount;
00862 
00863       if ((flags & GLOB_DOOFFS) && (int)pglob->gl_offs > oldcount)
00864         non_sort = pglob->gl_offs;
00865 
00866       qsort ((__ptr_t) &pglob->gl_pathv[non_sort],
00867              pglob->gl_pathc - non_sort,
00868              sizeof (char *), collated_compare);
00869     }
00870 
00871   return 0;
00872 }
00873 
00874 
00875 /* Free storage allocated in PGLOB by a previous `glob' call.  */
00876 void
00877 globfree (glob_t *pglob)
00878 {
00879   if (pglob->gl_pathv != NULL)
00880     {
00881       register int i;
00882       for (i = 0; i < (int)pglob->gl_pathc; ++i)
00883         if (pglob->gl_pathv[i] != NULL)
00884           free ((__ptr_t) pglob->gl_pathv[i]);
00885       free ((__ptr_t) pglob->gl_pathv);
00886     }
00887 }
00888 
00889 
00890 /* Do a collated comparison of A and B.  */
00891 static int
00892 collated_compare (const __ptr_t a, const __ptr_t b)
00893 {
00894   const char *const s1 = *(const char *const * const) a;
00895   const char *const s2 = *(const char *const * const) b;
00896 
00897   if (s1 == s2)
00898     return 0;
00899   if (s1 == NULL)
00900     return 1;
00901   if (s2 == NULL)
00902     return -1;
00903   return strcoll (s1, s2);
00904 }
00905 
00906 
00907 /* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
00908    elements in place.  Return nonzero if out of memory, zero if successful.
00909    A slash is inserted between DIRNAME and each elt of ARRAY,
00910    unless DIRNAME is just "/".  Each old element of ARRAY is freed.  */
00911 static int
00912 prefix_array (const char *dirname, char **array, size_t n)
00913 {
00914   register size_t i;
00915   size_t dirlen = strlen (dirname);
00916 #if defined __MSDOS__ || defined WINDOWS32
00917   int sep_char = '/';
00918 # define DIRSEP_CHAR sep_char
00919 #else
00920 # define DIRSEP_CHAR '/'
00921 #endif
00922 
00923   if (dirlen == 1 && dirname[0] == '/')
00924     /* DIRNAME is just "/", so normal prepending would get us "//foo".
00925        We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
00926     dirlen = 0;
00927 #if defined __MSDOS__ || defined WINDOWS32
00928   else if (dirlen > 1)
00929     {
00930       if (dirname[dirlen - 1] == '/')
00931         /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
00932         --dirlen;
00933       else if (dirname[dirlen - 1] == ':')
00934         {
00935           /* DIRNAME is "d:".  Use `:' instead of `/'.  */
00936           --dirlen;
00937           sep_char = ':';
00938         }
00939     }
00940 #endif
00941 
00942   for (i = 0; i < n; ++i)
00943     {
00944       size_t eltlen = strlen (array[i]) + 1;
00945       char *new = (char *) xmalloc (dirlen + 1 + eltlen);
00946       if (new == NULL)
00947         {
00948           while (i > 0)
00949             free ((__ptr_t) array[--i]);
00950           return 1;
00951         }
00952 
00953 #ifdef HAVE_MEMPCPY
00954       {
00955         char *endp = (char *) mempcpy (new, dirname, dirlen);
00956         *endp++ = DIRSEP_CHAR;
00957         mempcpy (endp, array[i], eltlen);
00958       }
00959 #else
00960       memcpy (new, dirname, dirlen);
00961       new[dirlen] = DIRSEP_CHAR;
00962       memcpy (&new[dirlen + 1], array[i], eltlen);
00963 #endif
00964       free ((__ptr_t) array[i]);
00965       array[i] = new;
00966     }
00967 
00968   return 0;
00969 }
00970 
00971 
00972 /* We must not compile this function twice.  */
00973 #if !defined _LIBC || !defined NO_GLOB_PATTERN_P
00974 /* Return nonzero if PATTERN contains any metacharacters.
00975    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
00976 static int
00977 __glob_pattern_p (const char *pattern, int quote)
00978 {
00979   register const char *p;
00980   int open = 0;
00981 
00982   for (p = pattern; *p != '\0'; ++p)
00983     switch (*p)
00984       {
00985       case '?':
00986       case '*':
00987         return 1;
00988 
00989       case '\\':
00990         if (quote && p[1] != '\0')
00991           ++p;
00992         break;
00993 
00994       case '[':
00995         open = 1;
00996         break;
00997 
00998       case ']':
00999         if (open)
01000           return 1;
01001         break;
01002       }
01003 
01004   return 0;
01005 }
01006 # ifdef _LIBC
01007 weak_alias (__glob_pattern_p, glob_pattern_p)
01008 # endif
01009 #endif
01010 
01011 
01012 /* Like `glob', but PATTERN is a final pathname component,
01013    and matches are searched for in DIRECTORY.
01014    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
01015    The GLOB_APPEND flag is assumed to be set (always appends).  */
01016 static int
01017 glob_in_dir (const char *pattern, const char *directory, int flags,
01018                 int (*errfunc) __P ((const char *, int)), glob_t *pglob)
01019 {
01020   __ptr_t stream = NULL;
01021 
01022   struct globlink
01023     {
01024       struct globlink *next;
01025       char *name;
01026     };
01027   struct globlink *names = NULL;
01028   size_t nfound;
01029   int meta;
01030   int save;
01031 
01032   meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
01033   if (meta == 0)
01034     {
01035       if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))
01036         /* We need not do any tests.  The PATTERN contains no meta
01037            characters and we must not return an error therefore the
01038            result will always contain exactly one name.  */
01039         flags |= GLOB_NOCHECK;
01040       else
01041         {
01042           /* Since we use the normal file functions we can also use stat()
01043              to verify the file is there.  */
01044           struct stat st;
01045           size_t patlen = strlen (pattern);
01046           size_t dirlen = strlen (directory);
01047           char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);
01048 
01049 # ifdef HAVE_MEMPCPY
01050           mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
01051                             "/", 1),
01052                    pattern, patlen + 1);
01053 # else
01054           memcpy (fullname, directory, dirlen);
01055           fullname[dirlen] = '/';
01056           memcpy (&fullname[dirlen + 1], pattern, patlen + 1);
01057 # endif
01058           if (((flags & GLOB_ALTDIRFUNC)
01059                ? (*pglob->gl_stat) (fullname, &st)
01060                : __stat (fullname, &st)) == 0)
01061             /* We found this file to be existing.  Now tell the rest
01062                of the function to copy this name into the result.  */
01063             flags |= GLOB_NOCHECK;
01064         }
01065 
01066       nfound = 0;
01067     }
01068   else
01069     {
01070       if (pattern[0] == '\0')
01071         {
01072           /* This is a special case for matching directories like in
01073              "*a/".  */
01074           names = (struct globlink *) __alloca (sizeof (struct globlink));
01075           names->name = (char *) xmalloc (1);
01076           if (names->name == NULL)
01077             goto memory_error;
01078           names->name[0] = '\0';
01079           names->next = NULL;
01080           nfound = 1;
01081           meta = 0;
01082         }
01083       else
01084         {
01085           stream = ((flags & GLOB_ALTDIRFUNC)
01086                     ? (*pglob->gl_opendir) (directory)
01087                     : (__ptr_t) opendir (directory));
01088           if (stream == NULL)
01089             {
01090               if (errno != ENOTDIR
01091                   && ((errfunc != NULL && (*errfunc) (directory, errno))
01092                       || (flags & GLOB_ERR)))
01093                 return GLOB_ABORTED;
01094               nfound = 0;
01095               meta = 0;
01096             }
01097           else
01098             {
01099               int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
01100                                | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
01101 #if defined _AMIGA || defined VMS
01102                                    | FNM_CASEFOLD
01103 #endif
01104                                    );
01105               nfound = 0;
01106               flags |= GLOB_MAGCHAR;
01107 
01108               while (1)
01109                 {
01110                   const char *name;
01111                   size_t len;
01112 #ifdef _LARGEFILE64_SOURCE
01113                   struct dirent64 *d;
01114                   union
01115                     {
01116                         struct dirent64 d64;
01117                         char room [offsetof (struct dirent64, d_name[0])
01118                                    + NAME_MAX + 1];
01119                     }
01120                   d64buf;
01121 
01122                   if ((flags & GLOB_ALTDIRFUNC))
01123                     {
01124                         struct dirent *d32 = (*pglob->gl_readdir) (stream);
01125                         if (d32 != NULL)
01126                           {
01127                             CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
01128                             d = &d64buf.d64;
01129                           }
01130                         else
01131                           d = NULL;
01132                     }
01133                   else
01134                     d = readdir64 (stream);
01135 #else
01136                   struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
01137                                       ? (*pglob->gl_readdir) (stream)
01138                                       : readdir ((DIR *) stream));
01139 #endif
01140                   if (d == NULL)
01141                     break;
01142                   if (! REAL_DIR_ENTRY (d))
01143                     continue;
01144 
01145 #ifdef HAVE_D_TYPE
01146                   /* If we shall match only directories use the information
01147                      provided by the dirent call if possible.  */
01148                   if ((flags & GLOB_ONLYDIR)
01149                       && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
01150                     continue;
01151 #endif
01152 
01153                   name = d->d_name;
01154 
01155                   if (fnmatch (pattern, name, fnm_flags) == 0)
01156                     {
01157                       struct globlink *new = (struct globlink *)
01158                         __alloca (sizeof (struct globlink));
01159                       len = NAMLEN (d);
01160                       new->name = (char *) xmalloc (len + 1);
01161                       if (new->name == NULL)
01162                         goto memory_error;
01163 #ifdef HAVE_MEMPCPY
01164                       *((char *) mempcpy ((__ptr_t) new->name, name, len))
01165                         = '\0';
01166 #else
01167                       memcpy ((__ptr_t) new->name, name, len);
01168                       new->name[len] = '\0';
01169 #endif
01170                       new->next = names;
01171                       names = new;
01172                       ++nfound;
01173                     }
01174                 }
01175             }
01176         }
01177     }
01178 
01179   if (nfound == 0 && (flags & GLOB_NOCHECK))
01180     {
01181       size_t len = strlen (pattern);
01182       nfound = 1;
01183       names = (struct globlink *) __alloca (sizeof (struct globlink));
01184       names->next = NULL;
01185       names->name = (char *) xmalloc (len + 1);
01186       if (names->name == NULL)
01187         goto memory_error;
01188 #ifdef HAVE_MEMPCPY
01189       *((char *) mempcpy (names->name, pattern, len)) = '\0';
01190 #else
01191       memcpy (names->name, pattern, len);
01192       names->name[len] = '\0';
01193 #endif
01194     }
01195 
01196   if (nfound != 0)
01197     {
01198       pglob->gl_pathv
01199         = (char **) xrealloc (pglob->gl_pathv,
01200                              (pglob->gl_pathc +
01201                               ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +
01202                               nfound + 1) *
01203                              sizeof (char *));
01204       if (pglob->gl_pathv == NULL)
01205         goto memory_error;
01206 
01207       if (flags & GLOB_DOOFFS)
01208         while (pglob->gl_pathc < pglob->gl_offs)
01209           pglob->gl_pathv[pglob->gl_pathc++] = NULL;
01210 
01211       for (; names != NULL; names = names->next)
01212         pglob->gl_pathv[pglob->gl_pathc++] = names->name;
01213       pglob->gl_pathv[pglob->gl_pathc] = NULL;
01214 
01215       pglob->gl_flags = flags;
01216     }
01217 
01218   save = errno;
01219   if (stream != NULL)
01220     {
01221       if (flags & GLOB_ALTDIRFUNC)
01222         (*pglob->gl_closedir) (stream);
01223       else
01224         closedir ((DIR *) stream);
01225     }
01226   __set_errno (save);
01227 
01228   return nfound == 0 ? GLOB_NOMATCH : 0;
01229 
01230  memory_error:
01231   {
01232     save = errno;
01233     if (flags & GLOB_ALTDIRFUNC)
01234       (*pglob->gl_closedir) (stream);
01235     else
01236       closedir ((DIR *) stream);
01237     __set_errno (save);
01238   }
01239   while (names != NULL)
01240     {
01241       if (names->name != NULL)
01242         free ((__ptr_t) names->name);
01243       names = names->next;
01244     }
01245   return GLOB_NOSPACE;
01246 }
01247 /*@=unrecog@*/
01248 /*@=unqualifiedtrans@*/
01249 /*@=type@*/
01250 /*@=temptrans@*/
01251 /*@=sizeoftype@*/
01252 /*@=shadow@*/
01253 /*@=retvalint@*/
01254 /*@=retalias@*/
01255 /*@=protoparammatch@*/
01256 /*@=onlytrans@*/
01257 /*@=nullpass@*/
01258 /*@=noeffectuncon@*/
01259 /*@=modunconnomods@*/
01260 /*@=moduncon@*/
01261 /*@=mods@*/
01262 /*@=modnomods@*/
01263 /*@=loopswitchbreak@*/
01264 /*@=internalglobs@*/
01265 /*@=immediatetrans@*/
01266 /*@=compdef@*/
01267 /*@=branchstate@*/
01268 /*@=bounds@*/