File: | rpmio/rpmglob.c |
Warning: | line 717, column 6 Value stored to 'meta' is never read |
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. */ |
63 | typedef 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 | |
104 | static void globfree(glob_t * pglob); |
105 | static inline const char *next_brace_sub(const char *begin); |
106 | static int glob_in_dir(const char *pattern, const char *directory, |
107 | int flags, |
108 | int (*errfunc) (const char *, int), |
109 | glob_t * pglob); |
110 | static int prefix_array(const char *prefix, char **array, size_t n); |
111 | static int collated_compare(const void *, const void *); |
112 | |
113 | #ifndef HAVE_MEMPCPY1 |
114 | static 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. */ |
122 | static 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 | |
138 | static 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. */ |
148 | static int |
149 | glob(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. */ |
575 | static 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. */ |
588 | static 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. */ |
607 | static 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. */ |
634 | static 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). */ |
667 | static int |
668 | glob_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 | |
814 | int 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 | |
936 | exit: |
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 | |
954 | int 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 | } |