rpm
5.2.1
|
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@*/