diff options
-rw-r--r-- | include/glob.h | 5 | ||||
-rw-r--r-- | lib/libc/gen/glob.3 | 17 | ||||
-rw-r--r-- | lib/libc/gen/glob.c | 76 | ||||
-rw-r--r-- | regress/lib/libc/glob/Makefile | 5 | ||||
-rw-r--r-- | regress/lib/libc/glob/globtest.c | 39 | ||||
-rw-r--r-- | regress/lib/libc/glob/globtest.in | 52 |
6 files changed, 167 insertions, 27 deletions
diff --git a/include/glob.h b/include/glob.h index fdd33bcb297..f602e71edcb 100644 --- a/include/glob.h +++ b/include/glob.h @@ -1,4 +1,4 @@ -/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */ +/* $OpenBSD: glob.h,v 1.11 2010/09/24 13:32:55 djm Exp $ */ /* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ /* @@ -39,6 +39,7 @@ #define _GLOB_H_ #include <sys/cdefs.h> +#include <sys/stat.h> struct stat; typedef struct { @@ -47,6 +48,7 @@ typedef struct { int gl_offs; /* Reserved at beginning of gl_pathv. */ int gl_flags; /* Copy of flags parameter to glob. */ char **gl_pathv; /* List of paths matching pattern. */ + struct stat **gl_statv; /* Stat entries corresponding to gl_pathv */ /* Copy of errfunc parameter to glob. */ int (*gl_errfunc)(const char *, int); @@ -83,6 +85,7 @@ typedef struct { #define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ #define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ #define GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */ +#define GLOB_KEEPSTAT 0x4000 /* Retain stat data for paths in gl_statv. */ #define GLOB_ABEND GLOB_ABORTED /* backward compatibility */ #endif diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3 index 8f3bb81d53c..007a27bc280 100644 --- a/lib/libc/gen/glob.3 +++ b/lib/libc/gen/glob.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: glob.3,v 1.26 2010/07/15 20:51:38 schwarze Exp $ +.\" $OpenBSD: glob.3,v 1.27 2010/09/24 13:32:55 djm Exp $ .\" .\" Copyright (c) 1989, 1991, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: July 15 2010 $ +.Dd $Mdocdate: September 24 2010 $ .Dt GLOB 3 .Os .Sh NAME @@ -223,6 +223,19 @@ is left unexpanded for historical reasons. does the same thing to ease typing of .Xr find 1 patterns.) +.It Dv GLOB_KEEPSTAT +Retain a copy of the +.Xr stat 2 +information retrieved for matching paths in the +.Fa gl_statv +array: +.Bd -literal -offset indent +struct stat **gl_statv; +.Ed +.Pp +This option may be used to avoid +.Xr lstat 2 +lookups in cases where they are expensive. .It Dv GLOB_MAGCHAR Set by the .Fn glob diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index bee2cecee04..dd72970fcaf 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: glob.c,v 1.31 2010/05/19 14:53:06 chl Exp $ */ +/* $OpenBSD: glob.c,v 1.32 2010/09/24 13:32:55 djm Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -135,7 +135,7 @@ static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, glob_t *, size_t *); static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, Char *, glob_t *, size_t *); -static int globextend(const Char *, glob_t *, size_t *); +static int globextend(const Char *, glob_t *, size_t *, struct stat *); static const Char * globtilde(const Char *, Char *, size_t, glob_t *); static int globexp1(const Char *, glob_t *); @@ -157,6 +157,7 @@ glob(const char *pattern, int flags, int (*errfunc)(const char *, int), if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; + pglob->gl_statv = NULL; if (!(flags & GLOB_DOOFFS)) pglob->gl_offs = 0; } @@ -516,7 +517,7 @@ glob0(const Char *pattern, glob_t *pglob) if ((pglob->gl_flags & GLOB_NOCHECK) || ((pglob->gl_flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR))) - return(globextend(pattern, pglob, &limit)); + return(globextend(pattern, pglob, &limit, NULL)); else return(GLOB_NOMATCH); } @@ -579,7 +580,7 @@ glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, *pathend = EOS; } ++pglob->gl_matchc; - return(globextend(pathbuf, pglob, limitp)); + return(globextend(pathbuf, pglob, limitp, &sb)); } /* Find end of next segment, copy tentatively to pathend. */ @@ -702,24 +703,40 @@ glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ static int -globextend(const Char *path, glob_t *pglob, size_t *limitp) +globextend(const Char *path, glob_t *pglob, size_t *limitp, struct stat *sb) { char **pathv; - int i; - u_int newsize, len; - char *copy; + ssize_t i; + size_t newn, len; + char *copy = NULL; const Char *p; - - newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - pathv = realloc((char *)pglob->gl_pathv, newsize); - if (pathv == NULL) { + struct stat **statv; + + newn = 2 + pglob->gl_pathc + pglob->gl_offs; + if (SIZE_MAX / sizeof(*pathv) <= newn || + SIZE_MAX / sizeof(*statv) <= newn) { + nospace: + for (i = pglob->gl_offs; i < newn - 2; i++) { + if (pglob->gl_pathv && pglob->gl_pathv[i]) + free(pglob->gl_pathv[i]); + if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 && + pglob->gl_pathv && pglob->gl_pathv[i]) + free(pglob->gl_statv[i]); + } if (pglob->gl_pathv) { free(pglob->gl_pathv); pglob->gl_pathv = NULL; } + if (pglob->gl_statv) { + free(pglob->gl_statv); + pglob->gl_statv = NULL; + } return(GLOB_NOSPACE); } + pathv = realloc(pglob->gl_pathv, newn * sizeof(*pathv)); + if (pathv == NULL) + goto nospace; if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { /* first time around -- clear initial gl_offs items */ pathv += pglob->gl_offs; @@ -728,6 +745,29 @@ globextend(const Char *path, glob_t *pglob, size_t *limitp) } pglob->gl_pathv = pathv; + if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) { + statv = realloc(pglob->gl_statv, newn * sizeof(*statv)); + if (statv == NULL) + goto nospace; + if (pglob->gl_statv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + statv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--statv = NULL; + } + pglob->gl_statv = statv; + if (sb == NULL) + statv[pglob->gl_offs + pglob->gl_pathc] = NULL; + else { + if ((statv[pglob->gl_offs + pglob->gl_pathc] = + malloc(sizeof(**statv))) == NULL) + goto copy_error; + memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb, + sizeof(*sb)); + } + statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL; + } + for (p = path; *p++;) ; len = (size_t)(p - path); @@ -742,11 +782,11 @@ globextend(const Char *path, glob_t *pglob, size_t *limitp) pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; if ((pglob->gl_flags & GLOB_LIMIT) && - newsize + *limitp >= ARG_MAX) { + (newn * sizeof(*pathv)) + *limitp >= ARG_MAX) { errno = 0; return(GLOB_NOSPACE); } - + copy_error: return(copy == NULL ? GLOB_NOSPACE : 0); } @@ -824,6 +864,14 @@ globfree(glob_t *pglob) free(pglob->gl_pathv); pglob->gl_pathv = NULL; } + if (pglob->gl_statv != NULL) { + free(pglob->gl_statv); + for (i = 0; i < pglob->gl_pathc; i++) { + if (pglob->gl_statv[i] != NULL) + free(pglob->gl_statv[i]); + } + pglob->gl_statv = NULL; + } } static DIR * diff --git a/regress/lib/libc/glob/Makefile b/regress/lib/libc/glob/Makefile index 6b93edfc386..ef209a3e189 100644 --- a/regress/lib/libc/glob/Makefile +++ b/regress/lib/libc/glob/Makefile @@ -1,10 +1,13 @@ -# $OpenBSD: Makefile,v 1.2 2009/02/18 15:17:55 millert Exp $ +# $OpenBSD: Makefile,v 1.3 2010/09/24 13:32:55 djm Exp $ PROG= globtest run-regress-${PROG}: mkdir -p `sed 's@/[^/]*$$@@' ${.CURDIR}/files | sort -u` touch `cat ${.CURDIR}/files` + chmod 0755 `grep '/r[^/]*$$' ${.CURDIR}/files` + chmod 0444 `grep '/s[^/]*$$' ${.CURDIR}/files` + chmod 0711 `grep '/t[^/]*$$' ${.CURDIR}/files` ./${PROG} ${.CURDIR}/${PROG}.in clean: diff --git a/regress/lib/libc/glob/globtest.c b/regress/lib/libc/glob/globtest.c index f8f93573c65..e47a728da81 100644 --- a/regress/lib/libc/glob/globtest.c +++ b/regress/lib/libc/glob/globtest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: globtest.c,v 1.1 2008/10/01 23:04:36 millert Exp $ */ +/* $OpenBSD: globtest.c,v 1.2 2010/09/24 13:32:55 djm Exp $ */ /* * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com> @@ -17,6 +17,7 @@ struct gl_entry { int nresults; char pattern[1024]; char *results[MAX_RESULTS]; + long modes[MAX_RESULTS]; }; int test_glob(struct gl_entry *); @@ -27,7 +28,7 @@ main(int argc, char **argv) FILE *fp = stdin; char *buf, *cp, *want, *got, *last; const char *errstr; - int errors = 0, i, lineno; + int errors = 0, i, lineno, mode; struct gl_entry entry; size_t len; @@ -40,9 +41,9 @@ main(int argc, char **argv) * Read in test file, which is formatted thusly: * * [pattern] <flags> - * result1 - * result2 - * result3 + * result1 [mode] + * result2 [mode] + * result3 [mode] * ... * */ @@ -76,7 +77,7 @@ main(int argc, char **argv) if ((cp = strchr(buf, '>')) == NULL) errx(1, "invalid entry on line %d", lineno); entry.flags = (int)strtol(buf, &cp, 0); - if (*cp != '>' || entry.flags < 0 || entry.flags > 0x2000) + if (*cp != '>' || entry.flags < 0 || entry.flags > 0x4000) errx(1, "invalid flags: %s", buf); entry.nresults = 0; continue; @@ -88,6 +89,12 @@ main(int argc, char **argv) errx(1, "too many results for %s, max %d", entry.pattern, MAX_RESULTS); } + if ((cp = strchr(buf, ' ')) != NULL) { + *cp++ = '\0'; + mode = strtol(cp, NULL, 8); + } else + mode = -1; + entry.modes[entry.nresults] = mode; entry.results[entry.nresults++] = strdup(buf); } if (entry.pattern[0]) @@ -109,12 +116,26 @@ int test_glob(struct gl_entry *entry) for (i = 0; i < gl.gl_matchc; i++) { if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0) goto mismatch; + if ((entry->flags & GLOB_KEEPSTAT) != 0) { + if (entry->modes[i] == -1 || + gl.gl_statv[i] == NULL || + entry->modes[i] != gl.gl_statv[i]->st_mode) + goto badmode; + } free(entry->results[i]); } return (0); -mismatch: - warnx("mismatch for pattern %s, flags 0x%x", entry->pattern, - entry->flags); + badmode: + warnx("mismatch mode for pattern %s, flags 0x%x, file \"%s\" " + "(found %07o, expected %07o)", entry->pattern, entry->flags, + gl.gl_pathv[i], gl.gl_statv[i] ? gl.gl_statv[i]->st_mode : 0, + entry->modes[i]); + goto cleanup; + mismatch: + warnx("mismatch for pattern %s, flags 0x%x " + "(found \"%s\", expected \"%s\")", entry->pattern, entry->flags, + gl.gl_pathv[i], entry->results[i]); + cleanup: while (i < gl.gl_matchc) { free(entry->results[i++]); } diff --git a/regress/lib/libc/glob/globtest.in b/regress/lib/libc/glob/globtest.in index 5995fa4b31d..2ae3b4dfb26 100644 --- a/regress/lib/libc/glob/globtest.in +++ b/regress/lib/libc/glob/globtest.in @@ -46,6 +46,54 @@ fake/bin/systrace fake/bin/tar fake/bin/test +[fake/bin/[[:alpha:]]*] <0x4000> +fake/bin/cat 0100644 +fake/bin/chgrp 0100644 +fake/bin/chio 0100644 +fake/bin/chmod 0100644 +fake/bin/cksum 0100644 +fake/bin/cp 0100644 +fake/bin/cpio 0100644 +fake/bin/csh 0100644 +fake/bin/date 0100644 +fake/bin/dd 0100644 +fake/bin/df 0100644 +fake/bin/domainname 0100644 +fake/bin/echo 0100644 +fake/bin/ed 0100644 +fake/bin/eject 0100644 +fake/bin/expr 0100644 +fake/bin/hostname 0100644 +fake/bin/kill 0100644 +fake/bin/ksh 0100644 +fake/bin/ln 0100644 +fake/bin/ls 0100644 +fake/bin/md5 0100644 +fake/bin/mkdir 0100644 +fake/bin/mt 0100644 +fake/bin/mv 0100644 +fake/bin/pax 0100644 +fake/bin/ps 0100644 +fake/bin/pwd 0100644 +fake/bin/rcp 0100755 +fake/bin/rksh 0100755 +fake/bin/rm 0100755 +fake/bin/rmail 0100755 +fake/bin/rmd160 0100755 +fake/bin/rmdir 0100755 +fake/bin/sh 0100444 +fake/bin/sha1 0100444 +fake/bin/sha256 0100444 +fake/bin/sha384 0100444 +fake/bin/sha512 0100444 +fake/bin/sleep 0100444 +fake/bin/stty 0100444 +fake/bin/sum 0100444 +fake/bin/sync 0100444 +fake/bin/systrace 0100444 +fake/bin/tar 0100711 +fake/bin/test 0100711 + [fake/bin/rm{,dir,ail}] <0x80> fake/bin/rm fake/bin/rmdir @@ -62,3 +110,7 @@ fake/bin/sha512 [fake/bin/ca[a-z]] <0x0> fake/bin/cat + +[fake/b[a-z]*] <0x4000> +fake/bin 0040755 + |