Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / rpmio / rpmglob.c
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__
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)        /* Return on read errors.  */
35 #define GLOB_MARK       (1 << 1)        /* Append a slash to each name.  */
36 #define GLOB_NOSORT     (1 << 2)        /* Don't sort the names.  */
37 #define GLOB_DOOFFS     (1 << 3)        /* Insert PGLOB->gl_offs NULLs.  */
38 #define GLOB_NOCHECK    (1 << 4)        /* If nothing matches, return the pattern.  */
39 #define GLOB_APPEND     (1 << 5)        /* Append to results of a previous call.  */
40 #define GLOB_NOESCAPE   (1 << 6)        /* Backslashes don't quote metacharacters.  */
41 #define GLOB_PERIOD     (1 << 7)        /* Leading `.' can be matched by metachars.  */
42
43 #define GLOB_MAGCHAR     (1 << 8)       /* Set in gl_flags if any metachars seen.  */
44 #define GLOB_ALTDIRFUNC (1 << 9)        /* Use gl_opendir et al functions.  */
45 #define GLOB_BRACE       (1 << 10)      /* Expand "{a,b}" to "a" "b".  */
46 #define GLOB_NOMAGIC     (1 << 11)      /* If no magic chars, return the pattern.  */
47 #define GLOB_TILDE       (1 << 12)      /* Expand ~user and ~ to home directories. */
48 #define GLOB_ONLYDIR     (1 << 13)      /* Match only directories.  */
49 #define GLOB_TILDE_CHECK (1 << 14)      /* Like GLOB_TILDE but return an error
50                                            if the user name is not available.  */
51 #define __GLOB_FLAGS    (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
52                          GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND|     \
53                          GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE|     \
54                          GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
55
56 /* Error returns from `glob'.  */
57 #define GLOB_NOSPACE    1       /* Ran out of memory.  */
58 #define GLOB_ABORTED    2       /* Read error.  */
59 #define GLOB_NOMATCH    3       /* No matches found.  */
60 #define GLOB_NOSYS      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)      NLENGTH(_d)
79
80 #if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
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) 1
84 #else
85 #define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
86 #endif                          /* POSIX */
87
88 #include <errno.h>
89 #ifndef __set_errno
90 #define __set_errno(val) errno = (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_VERSION 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_MEMPCPY
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;
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 || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) {
159         __set_errno(EINVAL);
160         return -1;
161     }
162
163     if (flags & GLOB_BRACE) {
164         const char *begin = strchr(pattern, '{');
165         if (begin != NULL) {
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) {
183                 /* It is an illegal expression.  */
184                 return glob(pattern, flags & ~GLOB_BRACE, 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) {
192                     /* It is an illegal expression.  */
193                     return glob(pattern, flags & ~GLOB_BRACE, 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)) {
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;
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 | GLOB_NOMAGIC))
224                                | GLOB_APPEND), errfunc, pglob);
225
226                 /* If we got an error, return it.  */
227                 if (result && result != GLOB_NOMATCH) {
228                     if (!(flags & GLOB_APPEND))
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);
240             }
241
242             if (pglob->gl_pathc != firstc)
243                 /* We found some entries.  */
244                 return 0;
245             else if (!(flags & (GLOB_NOCHECK | GLOB_NOMAGIC)))
246                 return GLOB_NOMATCH;
247         }
248     }
249
250     /* Find the filename.  */
251     filename = strrchr(pattern, '/');
252     if (filename == NULL) {
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 | GLOB_TILDE_CHECK)) && 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;
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);
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, errfunc, pglob);
284             if (val == 0)
285                 pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
286                                    | (flags & GLOB_MARK));
287             return val;
288         }
289     }
290
291     if (!(flags & GLOB_APPEND)) {
292         pglob->gl_pathc = 0;
293         pglob->gl_pathv = NULL;
294     }
295
296     oldcount = pglob->gl_pathc;
297
298     if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && dirname[0] == '~') {
299         if (dirname[1] == '\0' || dirname[1] == '/') {
300             /* Look up home directory.  */
301             const char *home_dir = getenv("HOME");
302             if (home_dir == NULL || home_dir[0] == '\0') {
303                 int success;
304                 char *name;
305                 success = (name = getlogin()) != NULL;
306                 if (success) {
307                     struct passwd *p;
308                     p = getpwnam(name);
309                     if (p != NULL)
310                         home_dir = p->pw_dir;
311                 }
312             }
313             if (home_dir == NULL || home_dir[0] == '\0') {
314                 if (flags & GLOB_TILDE_CHECK)
315                     return GLOB_NOMATCH;
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);
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)
337                 user_name = dirname + 1;
338             else {
339                 char *newp;
340                 newp = (char *) 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)
351                     home_dir = p->pw_dir;
352                 else
353                     home_dir = NULL;
354             }
355             /* If we found a home directory use this.  */
356             if (home_dir != NULL) {
357                 char *newp;
358                 size_t home_len = strlen(home_dir);
359                 size_t rest_len = end_name == NULL ? 0 : strlen(end_name);
360                 newp = (char *) 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)
365                 /* We have to regard it as an error if we cannot find the
366                    home directory.  */
367                 return GLOB_NOMATCH;
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) {
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)
378             || (((flags & GLOB_ALTDIRFUNC)
379                  ? (*pglob->gl_stat) (dirname, &st)
380                  : stat(dirname, &st)) == 0 && S_ISDIR(st.st_mode))) {
381             pglob->gl_pathv
382                 = (char **) xrealloc(pglob->gl_pathv,
383                                      (pglob->gl_pathc +
384                                       ((flags & GLOB_DOOFFS) ?
385                                        pglob->gl_offs : 0) +
386                                       1 + 1) * sizeof(char *));
387
388             if (flags & GLOB_DOOFFS)
389                 while (pglob->gl_pathc < pglob->gl_offs)
390                     pglob->gl_pathv[pglob->gl_pathc++] = NULL;
391
392             pglob->gl_pathv[pglob->gl_pathc] = xstrdup(dirname);
393             if (pglob->gl_pathv[pglob->gl_pathc] == NULL) {
394                 free(pglob->gl_pathv);
395                 return GLOB_NOSPACE;
396             }
397             pglob->gl_pathv[++pglob->gl_pathc] = NULL;
398             pglob->gl_flags = flags;
399
400             return 0;
401         }
402
403         /* Not found.  */
404         return GLOB_NOMATCH;
405     }
406
407     if (__glob_pattern_p(dirname, !(flags & GLOB_NOESCAPE))) {
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) != 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 | GLOB_NOCHECK | GLOB_NOESCAPE
426                                  | GLOB_ALTDIRFUNC))
427                        | GLOB_NOSORT | GLOB_ONLYDIR), 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)
438                                   & ~(GLOB_NOCHECK | GLOB_ERR)),
439                                  errfunc, pglob);
440             if (status == GLOB_NOMATCH)
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_NOSPACE;
457             }
458         }
459
460         flags |= GLOB_MAGCHAR;
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) {
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,
476                                          (pglob->gl_pathc +
477                                           ((flags & GLOB_DOOFFS) ?
478                                            pglob->gl_offs : 0) +
479                                           dirs.gl_pathc + 1) *
480                                          sizeof(char *));
481
482                 if (flags & GLOB_DOOFFS)
483                     while (pglob->gl_pathc < pglob->gl_offs)
484                         pglob->gl_pathv[pglob->gl_pathc++] = NULL;
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)
492                          ? (*pglob->gl_stat) (dir, &st) : stat(dir,
493                                                                  &st)) != 0
494                         || !S_ISDIR(st.st_mode))
495                         /* No directory, ignore this entry.  */
496                         continue;
497
498                     pglob->gl_pathv[pglob->gl_pathc] = xmalloc(dir_len + 1
499                                                                +
500                                                                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;
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,
513                                                ((pglob->gl_pathc + 1)
514                                                 * sizeof(char *)));
515                 pglob->gl_pathv = new_pathv;
516             } else
517                 return GLOB_NOMATCH;
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) && 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_NOSPACE;
538             }
539         }
540     }
541
542     if (flags & GLOB_MARK) {
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)
548                  ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
549                  : stat(pglob->gl_pathv[i], &st)) == 0
550                 && S_ISDIR(st.st_mode)) {
551                 size_t len = strlen(pglob->gl_pathv[i]) + 2;
552                 char *new = xrealloc(pglob->gl_pathv[i], len);
553                 strcpy(&new[len - 2], "/");
554                 pglob->gl_pathv[i] = new;
555             }
556     }
557
558     if (!(flags & GLOB_NOSORT)) {
559         /* Sort the vector.  */
560         int non_sort = oldcount;
561
562         if ((flags & GLOB_DOOFFS) && 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) {
578         register int i;
579         for (i = 0; i < pglob->gl_pathc; ++i)
580             if (pglob->gl_pathv[i] != NULL)
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)
596         return 1;
597     if (s2 == NULL)
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);
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;
672
673     struct globlink {
674         struct globlink *next;
675         char *name;
676     };
677     struct globlink *names = NULL;
678     size_t nfound;
679     int meta;
680     int save;
681
682     meta = __glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE));
683     if (meta == 0) {
684         if (flags & (GLOB_NOCHECK | GLOB_NOMAGIC))
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;
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);
696
697             mempcpy(mempcpy(mempcpy(fullname, directory, dirlen),
698                             "/", 1), pattern, patlen + 1);
699             if (((flags & GLOB_ALTDIRFUNC)
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;
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));
713             names->name = (char *) xmalloc(1);
714             names->name[0] = '\0';
715             names->next = NULL;
716             nfound = 1;
717             meta = 0;
718         } else {
719             stream = ((flags & GLOB_ALTDIRFUNC)
720                       ? (*pglob->gl_opendir) (directory)
721                       : opendir(directory));
722             if (stream == NULL) {
723                 if (errno != ENOTDIR
724                     && ((errfunc != NULL && (*errfunc) (directory, errno))
725                         || (flags & GLOB_ERR)))
726                     return GLOB_ABORTED;
727                 nfound = 0;
728                 meta = 0;
729             } else {
730                 int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
731                                  ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
732                 nfound = 0;
733                 flags |= GLOB_MAGCHAR;
734
735                 while (1) {
736                     const char *name;
737                     size_t len;
738                     struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
739                                         ? (*pglob->gl_readdir) (stream)
740                                         : readdir((DIR *) stream));
741                     if (d == NULL)
742                         break;
743                     if (!REAL_DIR_ENTRY(d))
744                         continue;
745
746 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
747                     /* If we shall match only directories use the information
748                        provided by the dirent call if possible.  */
749                     if ((flags & GLOB_ONLYDIR)
750                         && d->d_type != DT_UNKNOWN && d->d_type != DT_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));
759                         len = NAMLEN(d);
760                         new->name = (char *) xmalloc(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)) {
773         size_t len = strlen(pattern);
774         nfound = 1;
775         names = (struct globlink *) alloca(sizeof(struct globlink));
776         names->next = NULL;
777         names->name = (char *) xmalloc(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,
784                                  (pglob->gl_pathc +
785                                   ((flags & GLOB_DOOFFS) ? pglob->
786                                    gl_offs : 0) + nfound +
787                                   1) * sizeof(char *));
788
789         if (flags & GLOB_DOOFFS)
790             while (pglob->gl_pathc < pglob->gl_offs)
791                 pglob->gl_pathv[pglob->gl_pathc++] = NULL;
792
793         for (; names != NULL; names = names->next)
794             pglob->gl_pathv[pglob->gl_pathc++] = names->name;
795         pglob->gl_pathv[pglob->gl_pathc] = NULL;
796
797         pglob->gl_flags = flags;
798     }
799
800     save = errno;
801     if (stream != NULL) {
802         if (flags & GLOB_ALTDIRFUNC)
803             (*pglob->gl_closedir) (stream);
804         else
805             closedir((DIR *) stream);
806     }
807     __set_errno(save);
808
809     return nfound == 0 ? GLOB_NOMATCH : 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;
818     int argc = 0;
819     ARGV_t argv = NULL;
820     char * globRoot = NULL;
821     const char *home = getenv("HOME");
822     int gflags = 0;
823 #ifdef ENABLE_NLS
824     char * old_collate = NULL;
825     char * old_ctype = NULL;
826     const char * t;
827 #endif
828     size_t maxb, nb;
829     int i, j;
830     int rc;
831
832     gflags |= GLOB_BRACE;
833
834     if (home != NULL && strlen(home) > 0) 
835         gflags |= GLOB_TILDE;
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_NLS
843     t = setlocale(LC_COLLATE, NULL);
844     if (t)
845         old_collate = xstrdup(t);
846     t = setlocale(LC_CTYPE, NULL);
847     if (t)
848         old_ctype = xstrdup(t);
849     (void) setlocale(LC_COLLATE, "C");
850     (void) setlocale(LC_CTYPE, "C");
851 #endif
852         
853     if (av != NULL)
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)) {
865             argvAdd(&argv, av[j]);
866             continue;
867         }
868
869         if (dir_only)
870             flags |= GLOB_ONLYDIR;
871         
872         gl.gl_pathc = 0;
873         gl.gl_pathv = NULL;
874         
875         rc = glob(av[j], flags, NULL, &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);
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))
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_NLS       
938     if (old_collate) {
939         (void) setlocale(LC_COLLATE, old_collate);
940         free(old_collate);
941     }
942     if (old_ctype) {
943         (void) setlocale(LC_CTYPE, old_ctype);
944         free(old_ctype);
945     }
946 #endif
947     av = _free(av);
948     if (rc || argvPtr == NULL) {
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)
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)
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)
978                 return 0;
979         }
980         /* Now we can be sure that brace expression is well-foermed. */
981     }
982
983     return 1;
984 }