rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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