diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2010-09-24 13:32:56 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2010-09-24 13:32:56 +0000 |
commit | 898c385370762cd3fd1a6fa08058a30f7511fa79 (patch) | |
tree | c9c36ef54367699bdaf54b8bd9581c3f8736cb86 /lib/libc/gen | |
parent | 0df142c814e864e0da4dbc09c556d9632501d2ee (diff) |
add a GLOB_KEEPSTAT option that retains a copy of the struct stat
information that is looked up while matching glob(3)s
Keeping this information around can make a big difference when
fetching it is expensive, e.g. in sftp which uses GLOB_ALTDIRFUNC
feedback millert@ jmc@
"get it in before the libc crank" deraadt@
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/glob.3 | 17 | ||||
-rw-r--r-- | lib/libc/gen/glob.c | 76 |
2 files changed, 77 insertions, 16 deletions
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 * |