Bug Summary

File:rpmio/rpmglob.c
Warning:line 717, column 6
Value stored to 'meta' is never read

Annotated Source Code

1#include "system.h"
2
3/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20/* AIX requires this to be the first thing in the file. */
21#if defined _AIX && !defined __GNUC__4
22#pragma alloca
23#endif
24
25#include "system.h"
26
27#include <stdlib.h>
28#include <string.h>
29#include <pwd.h>
30#include <assert.h>
31#include <sys/stat.h> /* S_ISDIR */
32
33/* Bits set in the FLAGS argument to `glob'. */
34#define GLOB_ERR(1 << 0) (1 << 0) /* Return on read errors. */
35#define GLOB_MARK(1 << 1) (1 << 1) /* Append a slash to each name. */
36#define GLOB_NOSORT(1 << 2) (1 << 2) /* Don't sort the names. */
37#define GLOB_DOOFFS(1 << 3) (1 << 3) /* Insert PGLOB->gl_offs NULLs. */
38#define GLOB_NOCHECK(1 << 4) (1 << 4) /* If nothing matches, return the pattern. */
39#define GLOB_APPEND(1 << 5) (1 << 5) /* Append to results of a previous call. */
40#define GLOB_NOESCAPE(1 << 6) (1 << 6) /* Backslashes don't quote metacharacters. */
41#define GLOB_PERIOD(1 << 7) (1 << 7) /* Leading `.' can be matched by metachars. */
42
43#define GLOB_MAGCHAR(1 << 8) (1 << 8) /* Set in gl_flags if any metachars seen. */
44#define GLOB_ALTDIRFUNC(1 << 9) (1 << 9) /* Use gl_opendir et al functions. */
45#define GLOB_BRACE(1 << 10) (1 << 10) /* Expand "{a,b}" to "a" "b". */
46#define GLOB_NOMAGIC(1 << 11) (1 << 11) /* If no magic chars, return the pattern. */
47#define GLOB_TILDE(1 << 12) (1 << 12) /* Expand ~user and ~ to home directories. */
48#define GLOB_ONLYDIR(1 << 13) (1 << 13) /* Match only directories. */
49#define GLOB_TILDE_CHECK(1 << 14) (1 << 14) /* Like GLOB_TILDE but return an error
50 if the user name is not available. */
51#define __GLOB_FLAGS((1 << 0)|(1 << 1)|(1 << 2)|(1 << 3)|
(1 << 6)|(1 << 4)|(1 << 5)| (1 << 7)
|(1 << 9)|(1 << 10)| (1 << 11)|(1 << 12
)|(1 << 13)|(1 << 14))
(GLOB_ERR(1 << 0)|GLOB_MARK(1 << 1)|GLOB_NOSORT(1 << 2)|GLOB_DOOFFS(1 << 3)| \
52 GLOB_NOESCAPE(1 << 6)|GLOB_NOCHECK(1 << 4)|GLOB_APPEND(1 << 5)| \
53 GLOB_PERIOD(1 << 7)|GLOB_ALTDIRFUNC(1 << 9)|GLOB_BRACE(1 << 10)| \
54 GLOB_NOMAGIC(1 << 11)|GLOB_TILDE(1 << 12)|GLOB_ONLYDIR(1 << 13)|GLOB_TILDE_CHECK(1 << 14))
55
56/* Error returns from `glob'. */
57#define GLOB_NOSPACE1 1 /* Ran out of memory. */
58#define GLOB_ABORTED2 2 /* Read error. */
59#define GLOB_NOMATCH3 3 /* No matches found. */
60#define GLOB_NOSYS4 4 /* Not implemented. */
61
62/* Structure describing a globbing run. */
63typedef struct {
64 size_t gl_pathc; /* Count of paths matched by the pattern. */
65 char **gl_pathv; /* List of matched pathnames. */
66 size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
67 int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
68
69 /* If the GLOB_ALTDIRFUNC flag is set, the following functions
70 are used instead of the normal file access functions. */
71 void (*gl_closedir)(void *);
72 struct dirent *(*gl_readdir)(void *);
73 void *(*gl_opendir)(const char *);
74 int (*gl_lstat)(const char *, struct stat *);
75 int (*gl_stat)(const char *, struct stat *);
76} glob_t;
77
78#define NAMLEN(_d)(strlen((_d)->d_name)) NLENGTH(_d)(strlen((_d)->d_name))
79
80#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__6
81/* Posix does not require that the d_ino field be present, and some
82 systems do not provide it. */
83#define REAL_DIR_ENTRY(dp)(dp->d_ino != 0) 1
84#else
85#define REAL_DIR_ENTRY(dp)(dp->d_ino != 0) (dp->d_ino != 0)
86#endif /* POSIX */
87
88#include <errno(*__errno_location ()).h>
89#ifndef __set_errno
90#define __set_errno(val)(*__errno_location ()) = (val) errno(*__errno_location ()) = (val)
91#endif
92
93#include <popt.h>
94#include <rpm/rpmfileutil.h>
95#include <rpm/rpmurl.h>
96
97#include "debug.h"
98
99/* Outcomment the following line for production quality code. */
100/* #define NDEBUG 1 */
101
102#define GLOB_INTERFACE_VERSION1 1
103
104static void globfree(glob_t * pglob);
105static inline const char *next_brace_sub(const char *begin);
106static int glob_in_dir(const char *pattern, const char *directory,
107 int flags,
108 int (*errfunc) (const char *, int),
109 glob_t * pglob);
110static int prefix_array(const char *prefix, char **array, size_t n);
111static int collated_compare(const void *, const void *);
112
113#ifndef HAVE_MEMPCPY1
114static void * mempcpy(void *dest, const void *src, size_t n)
115{
116 return (char *) memcpy(dest, src, n) + n;
117}
118#endif
119
120/* Find the end of the sub-pattern in a brace expression. We define
121 this as an inline function if the compiler permits. */
122static inline const char *next_brace_sub(const char *begin)
123{
124 unsigned int depth = 0;
125 const char *cp = begin;
126
127 while (*cp != '\0') {
128 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
129 break;
130
131 if (*cp++ == '{')
132 depth++;
133 }
134
135 return *cp != '\0' ? cp : NULL((void*)0);
136}
137
138static int __glob_pattern_p(const char *pattern, int quote);
139
140/* Do glob searching for PATTERN, placing results in PGLOB.
141 The bits defined above may be set in FLAGS.
142 If a directory cannot be opened or read and ERRFUNC is not nil,
143 it is called with the pathname that caused the error, and the
144 `errno' value from the failing call; if it returns non-zero
145 `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
146 If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
147 Otherwise, `glob' returns zero. */
148static int
149glob(const char *pattern, int flags,
150 int (*errfunc)(const char *, int), glob_t * pglob)
151{
152 const char *filename;
153 const char *dirname;
154 size_t dirlen;
155 int status;
156 int oldcount;
157
158 if (pattern == NULL((void*)0) || pglob == NULL((void*)0) || (flags & ~__GLOB_FLAGS((1 << 0)|(1 << 1)|(1 << 2)|(1 << 3)|
(1 << 6)|(1 << 4)|(1 << 5)| (1 << 7)
|(1 << 9)|(1 << 10)| (1 << 11)|(1 << 12
)|(1 << 13)|(1 << 14))
) != 0) {
159 __set_errno(EINVAL)(*__errno_location ()) = (22);
160 return -1;
161 }
162
163 if (flags & GLOB_BRACE(1 << 10)) {
164 const char *begin = strchr(pattern, '{');
165 if (begin != NULL((void*)0)) {
166 /* Allocate working buffer large enough for our work. Note that
167 we have at least an opening and closing brace. */
168 int firstc;
169 char *alt_start;
170 const char *p;
171 const char *next;
172 const char *rest;
173 size_t rest_len;
174 char onealt[strlen(pattern) - 1];
175
176 /* We know the prefix for all sub-patterns. */
177 alt_start = mempcpy(onealt, pattern, begin - pattern);
178
179 /* Find the first sub-pattern and at the same time find the
180 rest after the closing brace. */
181 next = next_brace_sub(begin + 1);
182 if (next == NULL((void*)0)) {
183 /* It is an illegal expression. */
184 return glob(pattern, flags & ~GLOB_BRACE(1 << 10), errfunc, pglob);
185 }
186
187 /* Now find the end of the whole brace expression. */
188 rest = next;
189 while (*rest != '}') {
190 rest = next_brace_sub(rest + 1);
191 if (rest == NULL((void*)0)) {
192 /* It is an illegal expression. */
193 return glob(pattern, flags & ~GLOB_BRACE(1 << 10), errfunc,
194 pglob);
195 }
196 }
197 /* Please note that we now can be sure the brace expression
198 is well-formed. */
199 rest_len = strlen(++rest) + 1;
200
201 /* We have a brace expression. BEGIN points to the opening {,
202 NEXT points past the terminator of the first element, and END
203 points past the final }. We will accumulate result names from
204 recursive runs for each brace alternative in the buffer using
205 GLOB_APPEND. */
206
207 if (!(flags & GLOB_APPEND(1 << 5))) {
208 /* This call is to set a new vector, so clear out the
209 vector so we can append to it. */
210 pglob->gl_pathc = 0;
211 pglob->gl_pathv = NULL((void*)0);
212 }
213 firstc = pglob->gl_pathc;
214
215 p = begin + 1;
216 while (1) {
217 int result;
218
219 /* Construct the new glob expression. */
220 mempcpy(mempcpy(alt_start, p, next - p), rest, rest_len);
221
222 result = glob(onealt,
223 ((flags & ~(GLOB_NOCHECK(1 << 4) | GLOB_NOMAGIC(1 << 11)))
224 | GLOB_APPEND(1 << 5)), errfunc, pglob);
225
226 /* If we got an error, return it. */
227 if (result && result != GLOB_NOMATCH3) {
228 if (!(flags & GLOB_APPEND(1 << 5)))
229 globfree(pglob);
230 return result;
231 }
232
233 if (*next == '}')
234 /* We saw the last entry. */
235 break;
236
237 p = next + 1;
238 next = next_brace_sub(p);
239 assert(next != NULL)({ if (next != ((void*)0)) ; else __assert_fail ("next != NULL"
, "rpmglob.c", 239, __PRETTY_FUNCTION__); })
;
240 }
241
242 if (pglob->gl_pathc != firstc)
243 /* We found some entries. */
244 return 0;
245 else if (!(flags & (GLOB_NOCHECK(1 << 4) | GLOB_NOMAGIC(1 << 11))))
246 return GLOB_NOMATCH3;
247 }
248 }
249
250 /* Find the filename. */
251 filename = strrchr(pattern, '/');
252 if (filename == NULL((void*)0)) {
253 /* This can mean two things: a simple name or "~name". The latter
254 case is nothing but a notation for a directory. */
255 if ((flags & (GLOB_TILDE(1 << 12) | GLOB_TILDE_CHECK(1 << 14))) && pattern[0] == '~') {
256 dirname = pattern;
257 dirlen = strlen(pattern);
258
259 /* Set FILENAME to NULL as a special flag. This is ugly but
260 other solutions would require much more code. We test for
261 this special case below. */
262 filename = NULL((void*)0);
263 } else {
264 filename = pattern;
265 dirname = ".";
266 dirlen = 0;
267 }
268 } else if (filename == pattern) {
269 /* "/pattern". */
270 dirname = "/";
271 dirlen = 1;
272 ++filename;
273 } else {
274 char *newp;
275 dirlen = filename - pattern;
276 newp = (char *) alloca(dirlen + 1)__builtin_alloca (dirlen + 1);
277 *((char *) mempcpy(newp, pattern, dirlen)) = '\0';
278 dirname = newp;
279 ++filename;
280
281 if (filename[0] == '\0' && dirlen > 1) {
282 /* "pattern/". Expand "pattern", appending slashes. */
283 int val = glob(dirname, flags | GLOB_MARK(1 << 1), errfunc, pglob);
284 if (val == 0)
285 pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK(1 << 1))
286 | (flags & GLOB_MARK(1 << 1)));
287 return val;
288 }
289 }
290
291 if (!(flags & GLOB_APPEND(1 << 5))) {
292 pglob->gl_pathc = 0;
293 pglob->gl_pathv = NULL((void*)0);
294 }
295
296 oldcount = pglob->gl_pathc;
297
298 if ((flags & (GLOB_TILDE(1 << 12) | GLOB_TILDE_CHECK(1 << 14))) && dirname[0] == '~') {
299 if (dirname[1] == '\0' || dirname[1] == '/') {
300 /* Look up home directory. */
301 const char *home_dir = getenv("HOME")secure_getenv("HOME");
302 if (home_dir == NULL((void*)0) || home_dir[0] == '\0') {
303 int success;
304 char *name;
305 success = (name = getlogin()) != NULL((void*)0);
306 if (success) {
307 struct passwd *p;
308 p = getpwnam(name);
309 if (p != NULL((void*)0))
310 home_dir = p->pw_dir;
311 }
312 }
313 if (home_dir == NULL((void*)0) || home_dir[0] == '\0') {
314 if (flags & GLOB_TILDE_CHECK(1 << 14))
315 return GLOB_NOMATCH3;
316 else
317 home_dir = "~"; /* No luck. */
318 }
319 /* Now construct the full directory. */
320 if (dirname[1] == '\0')
321 dirname = home_dir;
322 else {
323 char *newp;
324 size_t home_len = strlen(home_dir);
325 newp = (char *) alloca(home_len + dirlen)__builtin_alloca (home_len + dirlen);
326 mempcpy(mempcpy(newp, home_dir, home_len),
327 &dirname[1], dirlen);
328 dirname = newp;
329 }
330 }
331 else {
332 char *end_name = strchr(dirname, '/');
333 const char *user_name;
334 const char *home_dir;
335
336 if (end_name == NULL((void*)0))
337 user_name = dirname + 1;
338 else {
339 char *newp;
340 newp = (char *) alloca(end_name - dirname + 1)__builtin_alloca (end_name - dirname + 1);
341 *((char *) mempcpy(newp, dirname + 1, end_name - dirname))
342 = '\0';
343 user_name = newp;
344 }
345
346 /* Look up specific user's home directory. */
347 {
348 struct passwd *p;
349 p = getpwnam(user_name);
350 if (p != NULL((void*)0))
351 home_dir = p->pw_dir;
352 else
353 home_dir = NULL((void*)0);
354 }
355 /* If we found a home directory use this. */
356 if (home_dir != NULL((void*)0)) {
357 char *newp;
358 size_t home_len = strlen(home_dir);
359 size_t rest_len = end_name == NULL((void*)0) ? 0 : strlen(end_name);
360 newp = (char *) alloca(home_len + rest_len + 1)__builtin_alloca (home_len + rest_len + 1);
361 *((char *) mempcpy(mempcpy(newp, home_dir, home_len),
362 end_name, rest_len)) = '\0';
363 dirname = newp;
364 } else if (flags & GLOB_TILDE_CHECK(1 << 14))
365 /* We have to regard it as an error if we cannot find the
366 home directory. */
367 return GLOB_NOMATCH3;
368 }
369 }
370
371 /* Now test whether we looked for "~" or "~NAME". In this case we
372 can give the answer now. */
373 if (filename == NULL((void*)0)) {
374 struct stat st;
375
376 /* Return the directory if we don't check for error or if it exists. */
377 if ((flags & GLOB_NOCHECK(1 << 4))
378 || (((flags & GLOB_ALTDIRFUNC(1 << 9))
379 ? (*pglob->gl_stat) (dirname, &st)
380 : stat(dirname, &st)) == 0 && S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))) {
381 pglob->gl_pathv
382 = (char **) xrealloc(pglob->gl_pathv,rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + 1 + 1) * sizeof
(char *)))
383 (pglob->gl_pathc +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + 1 + 1) * sizeof
(char *)))
384 ((flags & GLOB_DOOFFS) ?rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + 1 + 1) * sizeof
(char *)))
385 pglob->gl_offs : 0) +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + 1 + 1) * sizeof
(char *)))
386 1 + 1) * sizeof(char *))rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + 1 + 1) * sizeof
(char *)))
;
387
388 if (flags & GLOB_DOOFFS(1 << 3))
389 while (pglob->gl_pathc < pglob->gl_offs)
390 pglob->gl_pathv[pglob->gl_pathc++] = NULL((void*)0);
391
392 pglob->gl_pathv[pglob->gl_pathc] = xstrdup(dirname)rstrdup((dirname));
393 if (pglob->gl_pathv[pglob->gl_pathc] == NULL((void*)0)) {
394 free(pglob->gl_pathv);
395 return GLOB_NOSPACE1;
396 }
397 pglob->gl_pathv[++pglob->gl_pathc] = NULL((void*)0);
398 pglob->gl_flags = flags;
399
400 return 0;
401 }
402
403 /* Not found. */
404 return GLOB_NOMATCH3;
405 }
406
407 if (__glob_pattern_p(dirname, !(flags & GLOB_NOESCAPE(1 << 6)))) {
408 /* The directory name contains metacharacters, so we
409 have to glob for the directory, and then glob for
410 the pattern in each directory found. */
411 glob_t dirs;
412 register int i;
413
414 if ((flags & GLOB_ALTDIRFUNC(1 << 9)) != 0) {
415 /* Use the alternative access functions also in the recursive
416 call. */
417 dirs.gl_opendir = pglob->gl_opendir;
418 dirs.gl_readdir = pglob->gl_readdir;
419 dirs.gl_closedir = pglob->gl_closedir;
420 dirs.gl_stat = pglob->gl_stat;
421 dirs.gl_lstat = pglob->gl_lstat;
422 }
423
424 status = glob(dirname,
425 ((flags & (GLOB_ERR(1 << 0) | GLOB_NOCHECK(1 << 4) | GLOB_NOESCAPE(1 << 6)
426 | GLOB_ALTDIRFUNC(1 << 9)))
427 | GLOB_NOSORT(1 << 2) | GLOB_ONLYDIR(1 << 13)), errfunc, &dirs);
428 if (status != 0)
429 return status;
430
431 /* We have successfully globbed the preceding directory name.
432 For each name we found, call glob_in_dir on it and FILENAME,
433 appending the results to PGLOB. */
434 for (i = 0; i < dirs.gl_pathc; ++i) {
435 int old_pathc = pglob->gl_pathc;
436 status = glob_in_dir(filename, dirs.gl_pathv[i],
437 ((flags | GLOB_APPEND(1 << 5))
438 & ~(GLOB_NOCHECK(1 << 4) | GLOB_ERR(1 << 0))),
439 errfunc, pglob);
440 if (status == GLOB_NOMATCH3)
441 /* No matches in this directory. Try the next. */
442 continue;
443
444 if (status != 0) {
445 globfree(&dirs);
446 globfree(pglob);
447 return status;
448 }
449
450 /* Stick the directory on the front of each name. */
451 if (prefix_array(dirs.gl_pathv[i],
452 &pglob->gl_pathv[old_pathc],
453 pglob->gl_pathc - old_pathc)) {
454 globfree(&dirs);
455 globfree(pglob);
456 return GLOB_NOSPACE1;
457 }
458 }
459
460 flags |= GLOB_MAGCHAR(1 << 8);
461
462 /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
463 But if we have not found any matching entry and thie GLOB_NOCHECK
464 flag was set we must return the list consisting of the disrectory
465 names followed by the filename. */
466 if (pglob->gl_pathc == oldcount) {
467 /* No matches. */
468 if (flags & GLOB_NOCHECK(1 << 4)) {
469 size_t filename_len = strlen(filename) + 1;
470 char **new_pathv;
471 struct stat st;
472
473 /* This is an pessimistic guess about the size. */
474 pglob->gl_pathv
475 = (char **) xrealloc(pglob->gl_pathv,rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
476 (pglob->gl_pathc +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
477 ((flags & GLOB_DOOFFS) ?rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
478 pglob->gl_offs : 0) +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
479 dirs.gl_pathc + 1) *rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
480 sizeof(char *))rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob->gl_offs : 0) + dirs.gl_pathc
+ 1) * sizeof(char *)))
;
481
482 if (flags & GLOB_DOOFFS(1 << 3))
483 while (pglob->gl_pathc < pglob->gl_offs)
484 pglob->gl_pathv[pglob->gl_pathc++] = NULL((void*)0);
485
486 for (i = 0; i < dirs.gl_pathc; ++i) {
487 const char *dir = dirs.gl_pathv[i];
488 size_t dir_len = strlen(dir);
489
490 /* First check whether this really is a directory. */
491 if (((flags & GLOB_ALTDIRFUNC(1 << 9))
492 ? (*pglob->gl_stat) (dir, &st) : stat(dir,
493 &st)) != 0
494 || !S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
495 /* No directory, ignore this entry. */
496 continue;
497
498 pglob->gl_pathv[pglob->gl_pathc] = xmalloc(dir_len + 1rmalloc((dir_len + 1 + filename_len))
499 +rmalloc((dir_len + 1 + filename_len))
500 filename_len)rmalloc((dir_len + 1 + filename_len));
501 mempcpy(mempcpy
502 (mempcpy
503 (pglob->gl_pathv[pglob->gl_pathc], dir,
504 dir_len), "/", 1), filename, filename_len);
505 ++pglob->gl_pathc;
506 }
507
508 pglob->gl_pathv[pglob->gl_pathc] = NULL((void*)0);
509 pglob->gl_flags = flags;
510
511 /* Now we know how large the gl_pathv vector must be. */
512 new_pathv = (char **) xrealloc(pglob->gl_pathv,rrealloc((pglob->gl_pathv), (((pglob->gl_pathc + 1) * sizeof
(char *))))
513 ((pglob->gl_pathc + 1)rrealloc((pglob->gl_pathv), (((pglob->gl_pathc + 1) * sizeof
(char *))))
514 * sizeof(char *)))rrealloc((pglob->gl_pathv), (((pglob->gl_pathc + 1) * sizeof
(char *))))
;
515 pglob->gl_pathv = new_pathv;
516 } else
517 return GLOB_NOMATCH3;
518 }
519
520 globfree(&dirs);
521 } else {
522 status = glob_in_dir(filename, dirname, flags, errfunc, pglob);
523 if (status != 0)
524 return status;
525
526 if (dirlen > 0) {
527 /* Stick the directory on the front of each name. */
528 int ignore = oldcount;
529
530 if ((flags & GLOB_DOOFFS(1 << 3)) && ignore < pglob->gl_offs)
531 ignore = pglob->gl_offs;
532
533 if (prefix_array(dirname,
534 &pglob->gl_pathv[ignore],
535 pglob->gl_pathc - ignore)) {
536 globfree(pglob);
537 return GLOB_NOSPACE1;
538 }
539 }
540 }
541
542 if (flags & GLOB_MARK(1 << 1)) {
543 /* Append slashes to directory names. */
544 int i;
545 struct stat st;
546 for (i = oldcount; i < pglob->gl_pathc; ++i)
547 if (((flags & GLOB_ALTDIRFUNC(1 << 9))
548 ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
549 : stat(pglob->gl_pathv[i], &st)) == 0
550 && S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) {
551 size_t len = strlen(pglob->gl_pathv[i]) + 2;
552 char *new = xrealloc(pglob->gl_pathv[i], len)rrealloc((pglob->gl_pathv[i]), (len));
553 strcpy(&new[len - 2], "/");
554 pglob->gl_pathv[i] = new;
555 }
556 }
557
558 if (!(flags & GLOB_NOSORT(1 << 2))) {
559 /* Sort the vector. */
560 int non_sort = oldcount;
561
562 if ((flags & GLOB_DOOFFS(1 << 3)) && pglob->gl_offs > oldcount)
563 non_sort = pglob->gl_offs;
564
565 qsort(& pglob->gl_pathv[non_sort],
566 pglob->gl_pathc - non_sort,
567 sizeof(char *), collated_compare);
568 }
569
570 return 0;
571}
572
573
574/* Free storage allocated in PGLOB by a previous `glob' call. */
575static void globfree(glob_t * pglob)
576{
577 if (pglob->gl_pathv != NULL((void*)0)) {
578 register int i;
579 for (i = 0; i < pglob->gl_pathc; ++i)
580 if (pglob->gl_pathv[i] != NULL((void*)0))
581 free(pglob->gl_pathv[i]);
582 free(pglob->gl_pathv);
583 }
584}
585
586
587/* Do a collated comparison of A and B. */
588static int collated_compare(const void * a, const void * b)
589{
590 const char *const s1 = *(const char *const *const) a;
591 const char *const s2 = *(const char *const *const) b;
592
593 if (s1 == s2)
594 return 0;
595 if (s1 == NULL((void*)0))
596 return 1;
597 if (s2 == NULL((void*)0))
598 return -1;
599 return strcoll(s1, s2);
600}
601
602
603/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
604 elements in place. Return nonzero if out of memory, zero if successful.
605 A slash is inserted between DIRNAME and each elt of ARRAY,
606 unless DIRNAME is just "/". Each old element of ARRAY is freed. */
607static int prefix_array(const char *dirname, char **array, size_t n)
608{
609 register size_t i;
610 size_t dirlen = strlen(dirname);
611
612 if (dirlen == 1 && dirname[0] == '/')
613 /* DIRNAME is just "/", so normal prepending would get us "//foo".
614 We want "/foo" instead, so don't prepend any chars from DIRNAME. */
615 dirlen = 0;
616
617 for (i = 0; i < n; ++i) {
618 size_t eltlen = strlen(array[i]) + 1;
619 char *new = (char *) xmalloc(dirlen + 1 + eltlen)rmalloc((dirlen + 1 + eltlen));
620 {
621 char *endp = (char *) mempcpy(new, dirname, dirlen);
622 *endp++ = '/';
623 mempcpy(endp, array[i], eltlen);
624 }
625 free(array[i]);
626 array[i] = new;
627 }
628
629 return 0;
630}
631
632/* Return nonzero if PATTERN contains any metacharacters.
633 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
634static int __glob_pattern_p(const char *pattern, int quote)
635{
636 register const char *p;
637 int openBrackets = 0;
638
639 for (p = pattern; *p != '\0'; ++p)
640 switch (*p) {
641 case '?':
642 case '*':
643 return 1;
644
645 case '\\':
646 if (quote && p[1] != '\0')
647 ++p;
648 break;
649
650 case '[':
651 openBrackets = 1;
652 break;
653
654 case ']':
655 if (openBrackets)
656 return 1;
657 break;
658 }
659
660 return 0;
661}
662
663/* Like `glob', but PATTERN is a final pathname component,
664 and matches are searched for in DIRECTORY.
665 The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
666 The GLOB_APPEND flag is assumed to be set (always appends). */
667static int
668glob_in_dir(const char *pattern, const char *directory, int flags,
669 int (*errfunc)(const char *, int), glob_t * pglob)
670{
671 void * stream = NULL((void*)0);
672
673 struct globlink {
674 struct globlink *next;
675 char *name;
676 };
677 struct globlink *names = NULL((void*)0);
678 size_t nfound;
679 int meta;
680 int save;
681
682 meta = __glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE(1 << 6)));
683 if (meta == 0) {
684 if (flags & (GLOB_NOCHECK(1 << 4) | GLOB_NOMAGIC(1 << 11)))
685 /* We need not do any tests. The PATTERN contains no meta
686 characters and we must not return an error therefore the
687 result will always contain exactly one name. */
688 flags |= GLOB_NOCHECK(1 << 4);
689 else {
690 /* Since we use the normal file functions we can also use stat()
691 to verify the file is there. */
692 struct stat st;
693 size_t patlen = strlen(pattern);
694 size_t dirlen = strlen(directory);
695 char *fullname = (char *) alloca(dirlen + 1 + patlen + 1)__builtin_alloca (dirlen + 1 + patlen + 1);
696
697 mempcpy(mempcpy(mempcpy(fullname, directory, dirlen),
698 "/", 1), pattern, patlen + 1);
699 if (((flags & GLOB_ALTDIRFUNC(1 << 9))
700 ? (*pglob->gl_stat) (fullname, &st)
701 : stat(fullname, &st)) == 0)
702 /* We found this file to be existing. Now tell the rest
703 of the function to copy this name into the result. */
704 flags |= GLOB_NOCHECK(1 << 4);
705 }
706
707 nfound = 0;
708 } else {
709 if (pattern[0] == '\0') {
710 /* This is a special case for matching directories like in
711 "*a/". */
712 names = (struct globlink *) alloca(sizeof(struct globlink))__builtin_alloca (sizeof(struct globlink));
713 names->name = (char *) xmalloc(1)rmalloc((1));
714 names->name[0] = '\0';
715 names->next = NULL((void*)0);
716 nfound = 1;
717 meta = 0;
Value stored to 'meta' is never read
718 } else {
719 stream = ((flags & GLOB_ALTDIRFUNC(1 << 9))
720 ? (*pglob->gl_opendir) (directory)
721 : opendir(directory));
722 if (stream == NULL((void*)0)) {
723 if (errno(*__errno_location ()) != ENOTDIR20
724 && ((errfunc != NULL((void*)0) && (*errfunc) (directory, errno(*__errno_location ())))
725 || (flags & GLOB_ERR(1 << 0))))
726 return GLOB_ABORTED2;
727 nfound = 0;
728 meta = 0;
729 } else {
730 int fnm_flags = ((!(flags & GLOB_PERIOD(1 << 7)) ? FNM_PERIOD(1 << 2) : 0) |
731 ((flags & GLOB_NOESCAPE(1 << 6)) ? FNM_NOESCAPE(1 << 1) : 0));
732 nfound = 0;
733 flags |= GLOB_MAGCHAR(1 << 8);
734
735 while (1) {
736 const char *name;
737 size_t len;
738 struct dirent *d = ((flags & GLOB_ALTDIRFUNC(1 << 9))
739 ? (*pglob->gl_readdir) (stream)
740 : readdir((DIR *) stream));
741 if (d == NULL((void*)0))
742 break;
743 if (!REAL_DIR_ENTRY(d)(d->d_ino != 0))
744 continue;
745
746#ifdef HAVE_STRUCT_DIRENT_D_TYPE1
747 /* If we shall match only directories use the information
748 provided by the dirent call if possible. */
749 if ((flags & GLOB_ONLYDIR(1 << 13))
750 && d->d_type != DT_UNKNOWNDT_UNKNOWN && d->d_type != DT_DIRDT_DIR)
751 continue;
752#endif
753
754 name = d->d_name;
755
756 if (fnmatch(pattern, name, fnm_flags) == 0) {
757 struct globlink *new = (struct globlink *)
758 alloca(sizeof(struct globlink))__builtin_alloca (sizeof(struct globlink));
759 len = NAMLEN(d)(strlen((d)->d_name));
760 new->name = (char *) xmalloc(len + 1)rmalloc((len + 1));
761 *((char *) mempcpy(new->name, name, len))
762 = '\0';
763 new->next = names;
764 names = new;
765 ++nfound;
766 }
767 }
768 }
769 }
770 }
771
772 if (nfound == 0 && (flags & GLOB_NOCHECK(1 << 4))) {
773 size_t len = strlen(pattern);
774 nfound = 1;
775 names = (struct globlink *) alloca(sizeof(struct globlink))__builtin_alloca (sizeof(struct globlink));
776 names->next = NULL((void*)0);
777 names->name = (char *) xmalloc(len + 1)rmalloc((len + 1));
778 *((char *) mempcpy(names->name, pattern, len)) = '\0';
779 }
780
781 if (nfound != 0) {
782 pglob->gl_pathv
783 = (char **) xrealloc(pglob->gl_pathv,rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob-> gl_offs : 0) + nfound + 1
) * sizeof(char *)))
784 (pglob->gl_pathc +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob-> gl_offs : 0) + nfound + 1
) * sizeof(char *)))
785 ((flags & GLOB_DOOFFS) ? pglob->rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob-> gl_offs : 0) + nfound + 1
) * sizeof(char *)))
786 gl_offs : 0) + nfound +rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob-> gl_offs : 0) + nfound + 1
) * sizeof(char *)))
787 1) * sizeof(char *))rrealloc((pglob->gl_pathv), ((pglob->gl_pathc + ((flags
& (1 << 3)) ? pglob-> gl_offs : 0) + nfound + 1
) * sizeof(char *)))
;
788
789 if (flags & GLOB_DOOFFS(1 << 3))
790 while (pglob->gl_pathc < pglob->gl_offs)
791 pglob->gl_pathv[pglob->gl_pathc++] = NULL((void*)0);
792
793 for (; names != NULL((void*)0); names = names->next)
794 pglob->gl_pathv[pglob->gl_pathc++] = names->name;
795 pglob->gl_pathv[pglob->gl_pathc] = NULL((void*)0);
796
797 pglob->gl_flags = flags;
798 }
799
800 save = errno(*__errno_location ());
801 if (stream != NULL((void*)0)) {
802 if (flags & GLOB_ALTDIRFUNC(1 << 9))
803 (*pglob->gl_closedir) (stream);
804 else
805 closedir((DIR *) stream);
806 }
807 __set_errno(save)(*__errno_location ()) = (save);
808
809 return nfound == 0 ? GLOB_NOMATCH3 : 0;
810}
811
812/* librpmio exported interfaces */
813
814int rpmGlob(const char * patterns, int * argcPtr, ARGV_t * argvPtr)
815{
816 int ac = 0;
817 const char ** av = NULL((void*)0);
818 int argc = 0;
819 ARGV_t argv = NULL((void*)0);
820 char * globRoot = NULL((void*)0);
821 const char *home = getenv("HOME")secure_getenv("HOME");
822 int gflags = 0;
823#ifdef ENABLE_NLS1
824 char * old_collate = NULL((void*)0);
825 char * old_ctype = NULL((void*)0);
826 const char * t;
827#endif
828 size_t maxb, nb;
829 int i, j;
830 int rc;
831
832 gflags |= GLOB_BRACE(1 << 10);
833
834 if (home != NULL((void*)0) && strlen(home) > 0)
835 gflags |= GLOB_TILDE(1 << 12);
836
837 /* Can't use argvSplit() here, it doesn't handle whitespace etc escapes */
838 rc = poptParseArgvString(patterns, &ac, &av);
839 if (rc)
840 return rc;
841
842#ifdef ENABLE_NLS1
843 t = setlocale(LC_COLLATE3, NULL((void*)0));
844 if (t)
845 old_collate = xstrdup(t)rstrdup((t));
846 t = setlocale(LC_CTYPE0, NULL((void*)0));
847 if (t)
848 old_ctype = xstrdup(t)rstrdup((t));
849 (void) setlocale(LC_COLLATE3, "C");
850 (void) setlocale(LC_CTYPE0, "C");
851#endif
852
853 if (av != NULL((void*)0))
854 for (j = 0; j < ac; j++) {
855 char * globURL;
856 const char * path;
857 int ut = urlPath(av[j], &path);
858 int local = (ut == URL_IS_PATH) || (ut == URL_IS_UNKNOWN);
859 size_t plen = strlen(path);
860 int flags = gflags;
861 int dir_only = (plen > 0 && path[plen-1] == '/');
862 glob_t gl;
863
864 if (!local || (!rpmIsGlob(av[j], 0) && strchr(path, '~') == NULL((void*)0))) {
865 argvAdd(&argv, av[j]);
866 continue;
867 }
868
869 if (dir_only)
870 flags |= GLOB_ONLYDIR(1 << 13);
871
872 gl.gl_pathc = 0;
873 gl.gl_pathv = NULL((void*)0);
874
875 rc = glob(av[j], flags, NULL((void*)0), &gl);
876 if (rc)
877 goto exit;
878
879 /* XXX Prepend the URL leader for globs that have stripped it off */
880 maxb = 0;
881 for (i = 0; i < gl.gl_pathc; i++) {
882 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
883 maxb = nb;
884 }
885
886 nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
887 maxb += nb;
888 maxb += 1;
889 globURL = globRoot = xmalloc(maxb)rmalloc((maxb));
890
891 switch (ut) {
892 case URL_IS_PATH:
893 case URL_IS_DASH:
894 strncpy(globRoot, av[j], nb);
895 break;
896 case URL_IS_HTTPS:
897 case URL_IS_HTTP:
898 case URL_IS_FTP:
899 case URL_IS_HKP:
900 case URL_IS_UNKNOWN:
901 default:
902 break;
903 }
904 globRoot += nb;
905 *globRoot = '\0';
906
907 for (i = 0; i < gl.gl_pathc; i++) {
908 const char * globFile = &(gl.gl_pathv[i][0]);
909
910 if (dir_only) {
911 struct stat sb;
912 if (lstat(gl.gl_pathv[i], &sb) || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000)))
913 continue;
914 }
915
916 if (globRoot > globURL && globRoot[-1] == '/')
917 while (*globFile == '/') globFile++;
918 strcpy(globRoot, globFile);
919 argvAdd(&argv, globURL);
920 }
921 globfree(&gl);
922 free(globURL);
923 }
924
925 argc = argvCount(argv);
926 if (argc > 0) {
927 if (argvPtr)
928 *argvPtr = argv;
929 if (argcPtr)
930 *argcPtr = argc;
931 rc = 0;
932 } else
933 rc = 1;
934
935
936exit:
937#ifdef ENABLE_NLS1
938 if (old_collate) {
939 (void) setlocale(LC_COLLATE3, old_collate);
940 free(old_collate);
941 }
942 if (old_ctype) {
943 (void) setlocale(LC_CTYPE0, old_ctype);
944 free(old_ctype);
945 }
946#endif
947 av = _free(av)rfree((av));
948 if (rc || argvPtr == NULL((void*)0)) {
949 argvFree(argv);
950 }
951 return rc;
952}
953
954int rpmIsGlob(const char * pattern, int quote)
955{
956 if (!__glob_pattern_p(pattern, quote)) {
957
958 const char *begin;
959 const char *next;
960 const char *rest;
961
962 begin = strchr(pattern, '{');
963 if (begin == NULL((void*)0))
964 return 0;
965 /*
966 * Find the first sub-pattern and at the same time find the
967 * rest after the closing brace.
968 */
969 next = next_brace_sub(begin + 1);
970 if (next == NULL((void*)0))
971 return 0;
972
973 /* Now find the end of the whole brace expression. */
974 rest = next;
975 while (*rest != '}') {
976 rest = next_brace_sub(rest + 1);
977 if (rest == NULL((void*)0))
978 return 0;
979 }
980 /* Now we can be sure that brace expression is well-foermed. */
981 }
982
983 return 1;
984}