summaryrefslogtreecommitdiff
path: root/openbsd-compat/glob.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-10-07 21:39:17 +1100
committerDamien Miller <djm@mindrot.org>2010-10-07 21:39:17 +1100
commita6e121aaa0ab61965db2dcfe8e2ba5d719fbe1e6 (patch)
tree4583d2a94482493f21537611187bd119f496807c /openbsd-compat/glob.c
parentaa18063baf35e303832d9ec58204ffaab221de85 (diff)
- djm@cvs.openbsd.org 2010/09/25 09:30:16
[sftp.c configure.ac openbsd-compat/glob.c openbsd-compat/glob.h] make use of new glob(3) GLOB_KEEPSTAT extension to save extra server rountrips to fetch per-file stat(2) information. NB. update openbsd-compat/ glob(3) implementation from OpenBSD libc to match.
Diffstat (limited to 'openbsd-compat/glob.c')
-rw-r--r--openbsd-compat/glob.c232
1 files changed, 170 insertions, 62 deletions
diff --git a/openbsd-compat/glob.c b/openbsd-compat/glob.c
index 74b506403..7bbe6c71a 100644
--- a/openbsd-compat/glob.c
+++ b/openbsd-compat/glob.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */ 1/* $OpenBSD: glob.c,v 1.33 2010/09/26 22:15:39 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1989, 1993 3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved. 4 * The Regents of the University of California. All rights reserved.
@@ -33,6 +33,31 @@
33 33
34/* OPENBSD ORIGINAL: lib/libc/gen/glob.c */ 34/* OPENBSD ORIGINAL: lib/libc/gen/glob.c */
35 35
36/*
37 * glob(3) -- a superset of the one defined in POSIX 1003.2.
38 *
39 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
40 *
41 * Optional extra services, controlled by flags not defined by POSIX:
42 *
43 * GLOB_QUOTE:
44 * Escaping convention: \ inhibits any special meaning the following
45 * character might have (except \ at end of string is retained).
46 * GLOB_MAGCHAR:
47 * Set in gl_flags if pattern contained a globbing character.
48 * GLOB_NOMAGIC:
49 * Same as GLOB_NOCHECK, but it will only append pattern if it did
50 * not contain any magic characters. [Used in csh style globbing]
51 * GLOB_ALTDIRFUNC:
52 * Use alternately specified directory access functions.
53 * GLOB_TILDE:
54 * expand ~user/foo to the /home/dir/of/user/foo
55 * GLOB_BRACE:
56 * expand {1,2}{a,b} to 1a 1b 2a 2b
57 * gl_matchc:
58 * Number of matches in the current invocation of glob.
59 */
60
36#include "includes.h" 61#include "includes.h"
37 62
38#include <sys/types.h> 63#include <sys/types.h>
@@ -47,7 +72,7 @@
47#include <unistd.h> 72#include <unistd.h>
48 73
49#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \ 74#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
50 !defined(GLOB_HAS_GL_MATCHC) || \ 75 !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
51 !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \ 76 !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
52 defined(BROKEN_GLOB) 77 defined(BROKEN_GLOB)
53 78
@@ -63,31 +88,7 @@ get_arg_max(void)
63#endif 88#endif
64} 89}
65 90
66/* 91#include "charclass.h"
67 * glob(3) -- a superset of the one defined in POSIX 1003.2.
68 *
69 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
70 *
71 * Optional extra services, controlled by flags not defined by POSIX:
72 *
73 * GLOB_QUOTE:
74 * Escaping convention: \ inhibits any special meaning the following
75 * character might have (except \ at end of string is retained).
76 * GLOB_MAGCHAR:
77 * Set in gl_flags if pattern contained a globbing character.
78 * GLOB_NOMAGIC:
79 * Same as GLOB_NOCHECK, but it will only append pattern if it did
80 * not contain any magic characters. [Used in csh style globbing]
81 * GLOB_ALTDIRFUNC:
82 * Use alternately specified directory access functions.
83 * GLOB_TILDE:
84 * expand ~user/foo to the /home/dir/of/user/foo
85 * GLOB_BRACE:
86 * expand {1,2}{a,b} to 1a 1b 2a 2b
87 * gl_matchc:
88 * Number of matches in the current invocation of glob.
89 */
90
91 92
92#define DOLLAR '$' 93#define DOLLAR '$'
93#define DOT '.' 94#define DOT '.'
@@ -100,7 +101,6 @@ get_arg_max(void)
100#define RBRACKET ']' 101#define RBRACKET ']'
101#define SEP '/' 102#define SEP '/'
102#define STAR '*' 103#define STAR '*'
103#undef TILDE /* Some platforms may already define it */
104#define TILDE '~' 104#define TILDE '~'
105#define UNDERSCORE '_' 105#define UNDERSCORE '_'
106#define LBRACE '{' 106#define LBRACE '{'
@@ -137,6 +137,7 @@ typedef char Char;
137#define M_ONE META('?') 137#define M_ONE META('?')
138#define M_RNG META('-') 138#define M_RNG META('-')
139#define M_SET META('[') 139#define M_SET META('[')
140#define M_CLASS META(':')
140#define ismeta(c) (((c)&M_QUOTE) != 0) 141#define ismeta(c) (((c)&M_QUOTE) != 0)
141 142
142 143
@@ -144,7 +145,8 @@ static int compare(const void *, const void *);
144static int g_Ctoc(const Char *, char *, u_int); 145static int g_Ctoc(const Char *, char *, u_int);
145static int g_lstat(Char *, struct stat *, glob_t *); 146static int g_lstat(Char *, struct stat *, glob_t *);
146static DIR *g_opendir(Char *, glob_t *); 147static DIR *g_opendir(Char *, glob_t *);
147static Char *g_strchr(Char *, int); 148static Char *g_strchr(const Char *, int);
149static int g_strncmp(const Char *, const char *, size_t);
148static int g_stat(Char *, struct stat *, glob_t *); 150static int g_stat(Char *, struct stat *, glob_t *);
149static int glob0(const Char *, glob_t *); 151static int glob0(const Char *, glob_t *);
150static int glob1(Char *, Char *, glob_t *, size_t *); 152static int glob1(Char *, Char *, glob_t *, size_t *);
@@ -152,11 +154,11 @@ static int glob2(Char *, Char *, Char *, Char *, Char *, Char *,
152 glob_t *, size_t *); 154 glob_t *, size_t *);
153static int glob3(Char *, Char *, Char *, Char *, Char *, 155static int glob3(Char *, Char *, Char *, Char *, Char *,
154 Char *, Char *, glob_t *, size_t *); 156 Char *, Char *, glob_t *, size_t *);
155static int globextend(const Char *, glob_t *, size_t *); 157static int globextend(const Char *, glob_t *, size_t *, struct stat *);
156static const Char * 158static const Char *
157 globtilde(const Char *, Char *, size_t, glob_t *); 159 globtilde(const Char *, Char *, size_t, glob_t *);
158static int globexp1(const Char *, glob_t *); 160static int globexp1(const Char *, glob_t *);
159static int globexp2(const Char *, const Char *, glob_t *, int *); 161static int globexp2(const Char *, const Char *, glob_t *);
160static int match(Char *, Char *, Char *); 162static int match(Char *, Char *, Char *);
161#ifdef DEBUG 163#ifdef DEBUG
162static void qprintf(const char *, Char *); 164static void qprintf(const char *, Char *);
@@ -174,6 +176,7 @@ glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
174 if (!(flags & GLOB_APPEND)) { 176 if (!(flags & GLOB_APPEND)) {
175 pglob->gl_pathc = 0; 177 pglob->gl_pathc = 0;
176 pglob->gl_pathv = NULL; 178 pglob->gl_pathv = NULL;
179 pglob->gl_statv = NULL;
177 if (!(flags & GLOB_DOOFFS)) 180 if (!(flags & GLOB_DOOFFS))
178 pglob->gl_offs = 0; 181 pglob->gl_offs = 0;
179 } 182 }
@@ -215,15 +218,13 @@ static int
215globexp1(const Char *pattern, glob_t *pglob) 218globexp1(const Char *pattern, glob_t *pglob)
216{ 219{
217 const Char* ptr = pattern; 220 const Char* ptr = pattern;
218 int rv;
219 221
220 /* Protect a single {}, for find(1), like csh */ 222 /* Protect a single {}, for find(1), like csh */
221 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) 223 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
222 return glob0(pattern, pglob); 224 return glob0(pattern, pglob);
223 225
224 while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) 226 if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
225 if (!globexp2(ptr, pattern, pglob, &rv)) 227 return globexp2(ptr, pattern, pglob);
226 return rv;
227 228
228 return glob0(pattern, pglob); 229 return glob0(pattern, pglob);
229} 230}
@@ -235,9 +236,9 @@ globexp1(const Char *pattern, glob_t *pglob)
235 * If it fails then it tries to glob the rest of the pattern and returns. 236 * If it fails then it tries to glob the rest of the pattern and returns.
236 */ 237 */
237static int 238static int
238globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv) 239globexp2(const Char *ptr, const Char *pattern, glob_t *pglob)
239{ 240{
240 int i; 241 int i, rv;
241 Char *lm, *ls; 242 Char *lm, *ls;
242 const Char *pe, *pm, *pl; 243 const Char *pe, *pm, *pl;
243 Char patbuf[MAXPATHLEN]; 244 Char patbuf[MAXPATHLEN];
@@ -270,10 +271,8 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
270 } 271 }
271 272
272 /* Non matching braces; just glob the pattern */ 273 /* Non matching braces; just glob the pattern */
273 if (i != 0 || *pe == EOS) { 274 if (i != 0 || *pe == EOS)
274 *rv = glob0(patbuf, pglob); 275 return glob0(patbuf, pglob);
275 return 0;
276 }
277 276
278 for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 277 for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
279 switch (*pm) { 278 switch (*pm) {
@@ -319,7 +318,9 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
319#ifdef DEBUG 318#ifdef DEBUG
320 qprintf("globexp2:", patbuf); 319 qprintf("globexp2:", patbuf);
321#endif 320#endif
322 *rv = globexp1(patbuf, pglob); 321 rv = globexp1(patbuf, pglob);
322 if (rv && rv != GLOB_NOMATCH)
323 return rv;
323 324
324 /* move after the comma, to the next string */ 325 /* move after the comma, to the next string */
325 pl = pm + 1; 326 pl = pm + 1;
@@ -330,7 +331,6 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
330 break; 331 break;
331 } 332 }
332 } 333 }
333 *rv = 0;
334 return 0; 334 return 0;
335} 335}
336 336
@@ -399,6 +399,47 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
399 return patbuf; 399 return patbuf;
400} 400}
401 401
402static int
403g_strncmp(const Char *s1, const char *s2, size_t n)
404{
405 int rv = 0;
406
407 while (n--) {
408 rv = *(Char *)s1 - *(const unsigned char *)s2++;
409 if (rv)
410 break;
411 if (*s1++ == '\0')
412 break;
413 }
414 return rv;
415}
416
417static int
418g_charclass(const Char **patternp, Char **bufnextp)
419{
420 const Char *pattern = *patternp + 1;
421 Char *bufnext = *bufnextp;
422 const Char *colon;
423 struct cclass *cc;
424 size_t len;
425
426 if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
427 return 1; /* not a character class */
428
429 len = (size_t)(colon - pattern);
430 for (cc = cclasses; cc->name != NULL; cc++) {
431 if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
432 break;
433 }
434 if (cc->name == NULL)
435 return -1; /* invalid character class */
436 *bufnext++ = M_CLASS;
437 *bufnext++ = (Char)(cc - &cclasses[0]);
438 *bufnextp = bufnext;
439 *patternp += len + 3;
440
441 return 0;
442}
402 443
403/* 444/*
404 * The main glob() routine: compiles the pattern (optionally processing 445 * The main glob() routine: compiles the pattern (optionally processing
@@ -427,7 +468,7 @@ glob0(const Char *pattern, glob_t *pglob)
427 if (c == NOT) 468 if (c == NOT)
428 ++qpatnext; 469 ++qpatnext;
429 if (*qpatnext == EOS || 470 if (*qpatnext == EOS ||
430 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { 471 g_strchr(qpatnext+1, RBRACKET) == NULL) {
431 *bufnext++ = LBRACKET; 472 *bufnext++ = LBRACKET;
432 if (c == NOT) 473 if (c == NOT)
433 --qpatnext; 474 --qpatnext;
@@ -438,6 +479,20 @@ glob0(const Char *pattern, glob_t *pglob)
438 *bufnext++ = M_NOT; 479 *bufnext++ = M_NOT;
439 c = *qpatnext++; 480 c = *qpatnext++;
440 do { 481 do {
482 if (c == LBRACKET && *qpatnext == ':') {
483 do {
484 err = g_charclass(&qpatnext,
485 &bufnext);
486 if (err)
487 break;
488 c = *qpatnext++;
489 } while (c == LBRACKET && *qpatnext == ':');
490 if (err == -1 &&
491 !(pglob->gl_flags & GLOB_NOCHECK))
492 return GLOB_NOMATCH;
493 if (c == RBRACKET)
494 break;
495 }
441 *bufnext++ = CHAR(c); 496 *bufnext++ = CHAR(c);
442 if (*qpatnext == RANGE && 497 if (*qpatnext == RANGE &&
443 (c = qpatnext[1]) != RBRACKET) { 498 (c = qpatnext[1]) != RBRACKET) {
@@ -484,7 +539,7 @@ glob0(const Char *pattern, glob_t *pglob)
484 if ((pglob->gl_flags & GLOB_NOCHECK) || 539 if ((pglob->gl_flags & GLOB_NOCHECK) ||
485 ((pglob->gl_flags & GLOB_NOMAGIC) && 540 ((pglob->gl_flags & GLOB_NOMAGIC) &&
486 !(pglob->gl_flags & GLOB_MAGCHAR))) 541 !(pglob->gl_flags & GLOB_MAGCHAR)))
487 return(globextend(pattern, pglob, &limit)); 542 return(globextend(pattern, pglob, &limit, NULL));
488 else 543 else
489 return(GLOB_NOMATCH); 544 return(GLOB_NOMATCH);
490 } 545 }
@@ -547,7 +602,7 @@ glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
547 *pathend = EOS; 602 *pathend = EOS;
548 } 603 }
549 ++pglob->gl_matchc; 604 ++pglob->gl_matchc;
550 return(globextend(pathbuf, pglob, limitp)); 605 return(globextend(pathbuf, pglob, limitp, &sb));
551 } 606 }
552 607
553 /* Find end of next segment, copy tentatively to pathend. */ 608 /* Find end of next segment, copy tentatively to pathend. */
@@ -670,25 +725,40 @@ glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
670 * gl_pathv points to (gl_offs + gl_pathc + 1) items. 725 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
671 */ 726 */
672static int 727static int
673globextend(const Char *path, glob_t *pglob, size_t *limitp) 728globextend(const Char *path, glob_t *pglob, size_t *limitp, struct stat *sb)
674{ 729{
675 char **pathv; 730 char **pathv;
676 int i; 731 ssize_t i;
677 u_int newsize, len; 732 size_t newn, len;
678 char *copy; 733 char *copy = NULL;
679 const Char *p; 734 const Char *p;
680 735 struct stat **statv;
681 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 736
682 pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) : 737 newn = 2 + pglob->gl_pathc + pglob->gl_offs;
683 malloc(newsize); 738 if (SIZE_MAX / sizeof(*pathv) <= newn ||
684 if (pathv == NULL) { 739 SIZE_MAX / sizeof(*statv) <= newn) {
740 nospace:
741 for (i = pglob->gl_offs; i < newn - 2; i++) {
742 if (pglob->gl_pathv && pglob->gl_pathv[i])
743 free(pglob->gl_pathv[i]);
744 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
745 pglob->gl_pathv && pglob->gl_pathv[i])
746 free(pglob->gl_statv[i]);
747 }
685 if (pglob->gl_pathv) { 748 if (pglob->gl_pathv) {
686 free(pglob->gl_pathv); 749 free(pglob->gl_pathv);
687 pglob->gl_pathv = NULL; 750 pglob->gl_pathv = NULL;
688 } 751 }
752 if (pglob->gl_statv) {
753 free(pglob->gl_statv);
754 pglob->gl_statv = NULL;
755 }
689 return(GLOB_NOSPACE); 756 return(GLOB_NOSPACE);
690 } 757 }
691 758
759 pathv = realloc(pglob->gl_pathv, newn * sizeof(*pathv));
760 if (pathv == NULL)
761 goto nospace;
692 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 762 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
693 /* first time around -- clear initial gl_offs items */ 763 /* first time around -- clear initial gl_offs items */
694 pathv += pglob->gl_offs; 764 pathv += pglob->gl_offs;
@@ -697,6 +767,29 @@ globextend(const Char *path, glob_t *pglob, size_t *limitp)
697 } 767 }
698 pglob->gl_pathv = pathv; 768 pglob->gl_pathv = pathv;
699 769
770 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
771 statv = realloc(pglob->gl_statv, newn * sizeof(*statv));
772 if (statv == NULL)
773 goto nospace;
774 if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
775 /* first time around -- clear initial gl_offs items */
776 statv += pglob->gl_offs;
777 for (i = pglob->gl_offs; --i >= 0; )
778 *--statv = NULL;
779 }
780 pglob->gl_statv = statv;
781 if (sb == NULL)
782 statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
783 else {
784 if ((statv[pglob->gl_offs + pglob->gl_pathc] =
785 malloc(sizeof(**statv))) == NULL)
786 goto copy_error;
787 memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
788 sizeof(*sb));
789 }
790 statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
791 }
792
700 for (p = path; *p++;) 793 for (p = path; *p++;)
701 ; 794 ;
702 len = (size_t)(p - path); 795 len = (size_t)(p - path);
@@ -711,11 +804,11 @@ globextend(const Char *path, glob_t *pglob, size_t *limitp)
711 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 804 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
712 805
713 if ((pglob->gl_flags & GLOB_LIMIT) && 806 if ((pglob->gl_flags & GLOB_LIMIT) &&
714 newsize + *limitp >= (u_int) get_arg_max()) { 807 (newn * sizeof(*pathv)) + *limitp >= ARG_MAX) {
715 errno = 0; 808 errno = 0;
716 return(GLOB_NOSPACE); 809 return(GLOB_NOSPACE);
717 } 810 }
718 811 copy_error:
719 return(copy == NULL ? GLOB_NOSPACE : 0); 812 return(copy == NULL ? GLOB_NOSPACE : 0);
720} 813}
721 814
@@ -751,13 +844,21 @@ match(Char *name, Char *pat, Char *patend)
751 return(0); 844 return(0);
752 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) 845 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
753 ++pat; 846 ++pat;
754 while (((c = *pat++) & M_MASK) != M_END) 847 while (((c = *pat++) & M_MASK) != M_END) {
848 if ((c & M_MASK) == M_CLASS) {
849 int idx = *pat & M_MASK;
850 if (idx < NCCLASSES &&
851 cclasses[idx].isctype(k))
852 ok = 1;
853 ++pat;
854 }
755 if ((*pat & M_MASK) == M_RNG) { 855 if ((*pat & M_MASK) == M_RNG) {
756 if (c <= k && k <= pat[1]) 856 if (c <= k && k <= pat[1])
757 ok = 1; 857 ok = 1;
758 pat += 2; 858 pat += 2;
759 } else if (c == k) 859 } else if (c == k)
760 ok = 1; 860 ok = 1;
861 }
761 if (ok == negate_range) 862 if (ok == negate_range)
762 return(0); 863 return(0);
763 break; 864 break;
@@ -785,6 +886,14 @@ globfree(glob_t *pglob)
785 free(pglob->gl_pathv); 886 free(pglob->gl_pathv);
786 pglob->gl_pathv = NULL; 887 pglob->gl_pathv = NULL;
787 } 888 }
889 if (pglob->gl_statv != NULL) {
890 for (i = 0; i < pglob->gl_pathc; i++) {
891 if (pglob->gl_statv[i] != NULL)
892 free(pglob->gl_statv[i]);
893 }
894 free(pglob->gl_statv);
895 pglob->gl_statv = NULL;
896 }
788} 897}
789 898
790static DIR * 899static DIR *
@@ -830,11 +939,11 @@ g_stat(Char *fn, struct stat *sb, glob_t *pglob)
830} 939}
831 940
832static Char * 941static Char *
833g_strchr(Char *str, int ch) 942g_strchr(const Char *str, int ch)
834{ 943{
835 do { 944 do {
836 if (*str == ch) 945 if (*str == ch)
837 return (str); 946 return ((Char *)str);
838 } while (*str++); 947 } while (*str++);
839 return (NULL); 948 return (NULL);
840} 949}
@@ -870,5 +979,4 @@ qprintf(const char *str, Char *s)
870#endif 979#endif
871 980
872#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || 981#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
873 !defined(GLOB_HAS_GL_MATCHC) */ 982 !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) */
874