Hi,

In sftp we use a few of the BSD extensions to glob(3), most notably the
alternate open/readdir and stat functions so we can replace local fs
access with remote operations tunnelled over sftp.

In sftp these remote operations are slow, so we would like to do as few
of them as possible. Unfortunately, glob(3) throws away some information
that we have to refetch - it performs lstat() operations in the course
of building its output, but doesn't save them anywhere. sftp happens
to need these and so has to perform slow remote operations to retrieve
them.

This patch adds a new BSD_VISIBLE extension to retain these data in an
glob->gl_statv array that corresponds to the the main glob->gl_pathv
output.

This changes the glob structure so it would need to go in along with
other major number-cranking changes.

-d

Index: include/glob.h
===================================================================
RCS file: /cvs/src/include/glob.h,v
retrieving revision 1.10
diff -u -p -r1.10 glob.h
--- include/glob.h      13 Dec 2005 00:35:22 -0000      1.10
+++ include/glob.h      23 Sep 2010 00:15:26 -0000
@@ -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
 
Index: lib/libc/gen/glob.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/glob.c,v
retrieving revision 1.31
diff -u -p -r1.31 glob.c
--- lib/libc/gen/glob.c 19 May 2010 14:53:06 -0000      1.31
+++ lib/libc/gen/glob.c 23 Sep 2010 00:15:26 -0000
@@ -135,7 +135,7 @@ static int   glob2(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
        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,
                                *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,33 @@ glob3(Char *pathbuf, Char *pathbuf_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;
+       size_t newn, len;
        char *copy;
        const Char *p;
+       struct stat *statv;
 
-       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
-       pathv = realloc((char *)pglob->gl_pathv, newsize);
-       if (pathv == NULL) {
+       newn = 2 + pglob->gl_pathc + pglob->gl_offs;
+       if (SIZE_MAX / sizeof(*pathv) <= newn ||
+           SIZE_MAX / sizeof(*statv) <= newn) {
+ nospace:
                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((char *)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 +738,22 @@ globextend(const Char *path, glob_t *pgl
        }
        pglob->gl_pathv = pathv;
 
+       if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
+               statv = realloc((char *)pglob->gl_statv, newn * sizeof(*statv));
+               if (statv == NULL)
+                       goto nospace;
+               if (pglob->gl_statv == NULL && pglob->gl_offs > 0)
+                       bzero(statv, newn * sizeof(*statv));
+               pglob->gl_statv = statv;
+               if (sb == NULL) {
+                       bzero(&statv[pglob->gl_offs + pglob->gl_pathc],
+                           sizeof(*statv));
+               } else
+                       statv[pglob->gl_offs + pglob->gl_pathc] = *sb;
+               bzero(&statv[pglob->gl_offs + pglob->gl_pathc + 1],
+                   sizeof(*statv));
+       }
+
        for (p = path; *p++;)
                ;
        len = (size_t)(p - path);
@@ -742,7 +768,7 @@ globextend(const Char *path, glob_t *pgl
        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);
        }
@@ -823,6 +849,10 @@ globfree(glob_t *pglob)
                                free(*pp);
                free(pglob->gl_pathv);
                pglob->gl_pathv = NULL;
+       }
+       if (pglob->gl_statv != NULL) {
+               free(pglob->gl_statv);
+               pglob->gl_statv = NULL;
        }
 }
 
Index: regress/lib/libc/glob/Makefile
===================================================================
RCS file: /cvs/src/regress/lib/libc/glob/Makefile,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile
--- regress/lib/libc/glob/Makefile      18 Feb 2009 15:17:55 -0000      1.2
+++ regress/lib/libc/glob/Makefile      23 Sep 2010 00:15:26 -0000
@@ -5,6 +5,9 @@ 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:
Index: regress/lib/libc/glob/globtest.c
===================================================================
RCS file: /cvs/src/regress/lib/libc/glob/globtest.c,v
retrieving revision 1.1
diff -u -p -r1.1 globtest.c
--- regress/lib/libc/glob/globtest.c    1 Oct 2008 23:04:36 -0000       1.1
+++ regress/lib/libc/glob/globtest.c    23 Sep 2010 00:15:26 -0000
@@ -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,23 @@ 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 &&
+                   entry->modes[i] != -1 &&
+                   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].st_mode, 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++]);
        }
Index: regress/lib/libc/glob/globtest.in
===================================================================
RCS file: /cvs/src/regress/lib/libc/glob/globtest.in,v
retrieving revision 1.2
diff -u -p -r1.2 globtest.in
--- regress/lib/libc/glob/globtest.in   18 Feb 2009 15:24:55 -0000      1.2
+++ regress/lib/libc/glob/globtest.in   23 Sep 2010 00:15:26 -0000
@@ -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
+

Reply via email to