• 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@*/

Generated on Fri Dec 3 2010 20:54:19 for rpm by  doxygen 1.7.2