Module Name:    othersrc
Committed By:   christos
Date:           Sat Mar  2 17:11:31 UTC 2013

Modified Files:
        othersrc/usr.bin/tnftp/libnetbsd: ftpglob.h glob.c

Log Message:
replace glob with newer copy that does not suffer from DoS exhaustion attacks.
XXX: Needs more testing.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h
cvs rdiff -u -r1.8 -r1.9 othersrc/usr.bin/tnftp/libnetbsd/glob.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h
diff -u othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h:1.4 othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h:1.5
--- othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h:1.4	Sun Jul 22 07:41:57 2007
+++ othersrc/usr.bin/tnftp/libnetbsd/ftpglob.h	Sat Mar  2 12:11:31 2013
@@ -1,5 +1,5 @@
-/* $NetBSD: ftpglob.h,v 1.4 2007/07/22 11:41:57 lukem Exp $ */
-/* from NetBSD: glob.h,v 1.21 2006/03/26 18:11:22 christos Exp */
+/*	$NetBSD: ftpglob.h,v 1.5 2013/03/02 17:11:31 christos Exp $	*/
+/* from: NetBSD: glob.h,v 1.26 2010/09/06 14:38:56 christos Exp	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -38,6 +38,9 @@
 #ifndef _GLOB_H_
 #define	_GLOB_H_
 
+#include <sys/types.h>
+struct stat;
+
 #ifndef __gl_size_t
 #define __gl_size_t	size_t
 #endif
@@ -79,15 +82,21 @@ typedef struct {
 #define	GLOB_NOMATCH	(-3)	/* No match, and GLOB_NOCHECK was not set. */
 #define	GLOB_NOSYS	(-4)	/* Implementation does not support function. */
 
+#if defined(_NETBSD_SOURCE) || defined(HAVE_NBTOOL_CONFIG_H)
 #define	GLOB_ALTDIRFUNC	0x0040	/* Use alternately specified directory funcs. */
 #define	GLOB_BRACE	0x0080	/* Expand braces ala csh. */
 #define	GLOB_MAGCHAR	0x0100	/* Pattern had globbing characters. */
 #define	GLOB_NOMAGIC	0x0200	/* GLOB_NOCHECK without magic chars (csh). */
-#define GLOB_LIMIT	0x0400	/* Limit memory used by matches to ARG_MAX */
+#define	GLOB_LIMIT	0x0400	/* Limit memory used by matches to ARG_MAX */
 #define	GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
-#define	GLOB_QUOTE	0		/* source compatibility */
+/*	GLOB_NOESCAPE	0x1000	above */
+#define	GLOB_PERIOD	0x2000	/* Allow metachars to match leading periods. */
+#define	GLOB_NO_DOTDIRS	0x4000	/* Make . and .. vanish from wildcards. */
+#define	GLOB_STAR	0x8000	/* Use glob ** to recurse directories */
+#define	GLOB_QUOTE	0	/* source compatibility */
 
 #define	GLOB_ABEND	GLOB_ABORTED	/* source compatibility */
+#endif
 
 int	glob(const char *, int, int (*)(const char *, int), glob_t *);
 void	globfree(glob_t *);

Index: othersrc/usr.bin/tnftp/libnetbsd/glob.c
diff -u othersrc/usr.bin/tnftp/libnetbsd/glob.c:1.8 othersrc/usr.bin/tnftp/libnetbsd/glob.c:1.9
--- othersrc/usr.bin/tnftp/libnetbsd/glob.c:1.8	Tue Jan  5 04:08:29 2010
+++ othersrc/usr.bin/tnftp/libnetbsd/glob.c	Sat Mar  2 12:11:31 2013
@@ -1,5 +1,5 @@
-/* $NetBSD: glob.c,v 1.8 2010/01/05 09:08:29 lukem Exp $ */
-/* from	NetBSD: glob.c,v 1.16 2006/03/26 18:11:22 christos Exp */
+/*	$NetBSD: glob.c,v 1.9 2013/03/02 17:11:31 christos Exp $	*/
+/*	from: NetBSD: glob.c,v 1.34 2013/02/21 18:17:43 christos Exp	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -33,6 +33,8 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+
 /*
  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  *
@@ -51,17 +53,54 @@
  *	expand ~user/foo to the /home/dir/of/user/foo
  * GLOB_BRACE:
  *	expand {1,2}{a,b} to 1a 1b 2a 2b 
+ * GLOB_PERIOD:
+ *	allow metacharacters to match leading dots in filenames.
+ * GLOB_NO_DOTDIRS:
+ *	. and .. are hidden from wildcards, even if GLOB_PERIOD is set.
  * gl_matchc:
  *	Number of matches in the current invocation of glob.
  */
 
-#include "tnftp.h"
+#include <sys/param.h>
+#include <sys/stat.h>
 
-#if !defined(ARG_MAX)
-#define ARG_MAX sysconf(_SC_ARG_MAX)
-#endif
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ftpglob.h"
+
+#define NO_GETPW_R
+
+#define	GLOB_LIMIT_STRING	65536	/* number of readdirs */
+#define	GLOB_LIMIT_STAT		128	/* number of stat system calls */
+#define	GLOB_LIMIT_READDIR	16384	/* total buffer size of path strings */
+#define	GLOB_LIMIT_PATH		1024	/* number of path elements */
+#define GLOB_LIMIT_BRACE	128	/* Number of brace calls */
+
+struct glob_limit {
+	size_t l_string;
+	size_t l_stat;	
+	size_t l_readdir;	
+	size_t l_brace;
+};
 
-#undef	TILDE			/* XXX: AIX 4.1.5 has this in <sys/ioctl.h> */
+/*
+ * XXX: For NetBSD 1.4.x compatibility. (kill me l8r)
+ */
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(a)
+#endif
+#ifndef __UNCONST
+#define __UNCONST(a)	((void *)(unsigned long)(a))
+#endif
 
 #define	DOLLAR		'$'
 #define	DOT		'.'
@@ -88,7 +127,7 @@
 #define	M_MASK		0xffff
 #define	M_ASCII		0x00ff
 
-typedef unsigned short Char;
+typedef u_short Char;
 
 #else
 
@@ -115,33 +154,38 @@ typedef char Char;
 
 static int	 compare(const void *, const void *);
 static int	 g_Ctoc(const Char *, char *, size_t);
-static int	 g_lstat(Char *, __gl_stat_t *, glob_t *);
+static int	 g_lstat(Char *, __gl_stat_t  *, glob_t *);
 static DIR	*g_opendir(Char *, glob_t *);
 static Char	*g_strchr(const Char *, int);
 static int	 g_stat(Char *, __gl_stat_t *, glob_t *);
-static int	 glob0(const Char *, glob_t *);
-static int	 glob1(Char *, glob_t *, size_t *);
-static int	 glob2(Char *, Char *, Char *, Char *, glob_t *, size_t *);
-static int	 glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
-		    size_t *);
-static int	 globextend(const Char *, glob_t *, size_t *);
+static int	 glob0(const Char *, glob_t *, struct glob_limit *);
+static int	 glob1(Char *, glob_t *, struct glob_limit *);
+static int	 glob2(Char *, Char *, Char *, const Char *, glob_t *,
+    struct glob_limit *);
+static int	 glob3(Char *, Char *, Char *, const Char *, const Char *,
+    const Char *, glob_t *, struct glob_limit *);
+static int	 globextend(const Char *, glob_t *, struct glob_limit *);
 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
-static int	 globexp1(const Char *, glob_t *);
-static int	 globexp2(const Char *, const Char *, glob_t *, int *);
-static int	 match(Char *, Char *, Char *);
+static int	 globexp1(const Char *, glob_t *, struct glob_limit *);
+static int	 globexp2(const Char *, const Char *, glob_t *, int *,
+    struct glob_limit *);
+static int	 match(const Char *, const Char *, const Char *);
 #ifdef DEBUG
 static void	 qprintf(const char *, Char *);
 #endif
 
 int
-glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
-    glob_t *pglob)
+glob(const char * __restrict pattern, int flags, int (*errfunc)(const char *,
+    int), glob_t * __restrict pglob)
 {
-	const unsigned char *patnext;
+	const u_char *patnext;
 	int c;
 	Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
+	struct glob_limit limit = { 0, 0, 0, 0 };
+
+	_DIAGASSERT(pattern != NULL);
 
-	patnext = (const unsigned char *) pattern;
+	patnext = (const u_char *) pattern;
 	if (!(flags & GLOB_APPEND)) {
 		pglob->gl_pathc = 0;
 		pglob->gl_pathv = NULL;
@@ -173,9 +217,9 @@ glob(const char *pattern, int flags, int
 	*bufnext = EOS;
 
 	if (flags & GLOB_BRACE)
-	    return globexp1(patbuf, pglob);
+	    return globexp1(patbuf, pglob, &limit);
 	else
-	    return glob0(patbuf, pglob);
+	    return glob0(patbuf, pglob, &limit);
 }
 
 /*
@@ -184,20 +228,29 @@ glob(const char *pattern, int flags, int
  * characters
  */
 static int
-globexp1(const Char *pattern, glob_t *pglob)
+globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {
 	const Char* ptr = pattern;
 	int rv;
 
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(pglob != NULL);
+
+	if ((pglob->gl_flags & GLOB_LIMIT) &&
+	    limit->l_brace++ >= GLOB_LIMIT_BRACE) {
+		errno = 0;
+		return GLOB_NOSPACE;
+	}
+
 	/* Protect a single {}, for find(1), like csh */
 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
-		return glob0(pattern, pglob);
+		return glob0(pattern, pglob, limit);
 
 	while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
-		if (!globexp2(ptr, pattern, pglob, &rv))
+		if (!globexp2(ptr, pattern, pglob, &rv, limit))
 			return rv;
 
-	return glob0(pattern, pglob);
+	return glob0(pattern, pglob, limit);
 }
 
 
@@ -207,13 +260,19 @@ globexp1(const Char *pattern, glob_t *pg
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
 static int
-globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
+    struct glob_limit *limit)
 {
 	int     i;
 	Char   *lm, *ls;
 	const Char *pe, *pm, *pl;
 	Char    patbuf[MAXPATHLEN + 1];
 
+	_DIAGASSERT(ptr != NULL);
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(pglob != NULL);
+	_DIAGASSERT(rv != NULL);
+
 	/* copy part up to the brace */
 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
 		continue;
@@ -247,7 +306,7 @@ globexp2(const Char *ptr, const Char *pa
 		 * we use `pattern', not `patbuf' here so that that
 		 * unbalanced braces are passed to the match
 		 */
-		*rv = glob0(pattern, pglob);
+		*rv = glob0(pattern, pglob, limit);
 		return 0;
 	}
 
@@ -292,9 +351,9 @@ globexp2(const Char *ptr, const Char *pa
 
 				/* Expand the current pattern */
 #ifdef DEBUG
-				qprintf("globexp2:", patbuf);
+				qprintf("globexp2", patbuf);
 #endif
-				*rv = globexp1(patbuf, pglob);
+				*rv = globexp1(patbuf, pglob, limit);
 
 				/* move after the comma, to the next string */
 				pl = pm + 1;
@@ -323,9 +382,17 @@ globtilde(const Char *pattern, Char *pat
 	Char *b;
 	char *d;
 	Char *pend = &patbuf[patsize / sizeof(Char)];
+#ifndef NO_GETPW_R
+	struct passwd pwres;
+	char pwbuf[1024];
+#endif
 
 	pend--;
 
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(patbuf != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
 		return pattern;
 
@@ -347,7 +414,12 @@ globtilde(const Char *pattern, Char *pat
 		 * first and then trying the password file
 		 */
 		if ((h = getenv("HOME")) == NULL) {
+#ifdef NO_GETPW_R
 			if ((pwd = getpwuid(getuid())) == NULL)
+#else
+			if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf),
+			    &pwd) != 0 || pwd == NULL)
+#endif
 				return pattern;
 			else
 				h = pwd->pw_dir;
@@ -357,7 +429,12 @@ globtilde(const Char *pattern, Char *pat
 		/*
 		 * Expand a ~user
 		 */
+#ifdef NO_GETPW_R
 		if ((pwd = getpwnam(d)) == NULL)
+#else
+		if (getpwnam_r(d, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
+		    pwd == NULL)
+#endif
 			return pattern;
 		else
 			h = pwd->pw_dir;
@@ -389,13 +466,15 @@ globtilde(const Char *pattern, Char *pat
  * to find no matches.
  */
 static int
-glob0(const Char *pattern, glob_t *pglob)
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {
 	const Char *qpatnext;
 	int c, error;
 	__gl_size_t oldpathc;
 	Char *bufnext, patbuf[MAXPATHLEN+1];
-	size_t limit = 0;
+
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(pglob != NULL);
 
 	if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf),
 	    pglob)) == NULL)
@@ -439,10 +518,13 @@ glob0(const Char *pattern, glob_t *pglob
 			break;
 		case STAR:
 			pglob->gl_flags |= GLOB_MAGCHAR;
-			/* collapse adjacent stars to one, 
+			/* collapse adjacent stars to one [or three if globstar]
 			 * to avoid exponential behavior
 			 */
-			if (bufnext == patbuf || bufnext[-1] != M_ALL)
+			if (bufnext == patbuf || bufnext[-1] != M_ALL ||
+			    ((pglob->gl_flags & GLOB_STAR) != 0 && 
+			    (bufnext - 1 == patbuf || bufnext[-2] != M_ALL ||
+			    bufnext - 2 == patbuf || bufnext[-3] != M_ALL)))
 				*bufnext++ = M_ALL;
 			break;
 		default:
@@ -452,11 +534,11 @@ glob0(const Char *pattern, glob_t *pglob
 	}
 	*bufnext = EOS;
 #ifdef DEBUG
-	qprintf("glob0:", patbuf);
+	qprintf("glob0", patbuf);
 #endif
 
-	if ((error = glob1(patbuf, pglob, &limit)) != 0)
-		return(error);
+	if ((error = glob1(patbuf, pglob, limit)) != 0)
+		return error;
 
 	if (pglob->gl_pathc == oldpathc) {	
 		/*
@@ -469,9 +551,9 @@ glob0(const Char *pattern, glob_t *pglob
 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
 		    ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR))
 		     == GLOB_NOMAGIC)) {
-			return globextend(pattern, pglob, &limit);
+			return globextend(pattern, pglob, limit);
 		} else {
-			return (GLOB_NOMATCH);
+			return GLOB_NOMATCH;
 		}
 	} else if (!(pglob->gl_flags & GLOB_NOSORT)) {
 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
@@ -479,32 +561,37 @@ glob0(const Char *pattern, glob_t *pglob
 		    compare);
 	}
 
-	return(0);
+	return 0;
 }
 
 static int
 compare(const void *p, const void *q)
 {
 
-	return(strcoll(*(const char * const *)p, *(const char * const *)q));
+	_DIAGASSERT(p != NULL);
+	_DIAGASSERT(q != NULL);
+
+	return strcoll(*(const char * const *)p, *(const char * const *)q);
 }
 
 static int
-glob1(Char *pattern, glob_t *pglob, size_t *limit)
+glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {
 	Char pathbuf[MAXPATHLEN+1];
 
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
 	if (*pattern == EOS)
-		return(0);
+		return 0;
 	/*
 	 * we save one character so that we can use ptr >= limit,
 	 * in the general case when we are appending non nul chars only.
 	 */
-	return(glob2(pathbuf, pathbuf,
-		     pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1,
-		     pattern,
-	    pglob, limit));
+	return glob2(pathbuf, pathbuf,
+	    pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern,
+	    pglob, limit);
 }
 
 /*
@@ -513,13 +600,22 @@ glob1(Char *pattern, glob_t *pglob, size
  * meta characters.
  */
 static int
-glob2(Char *pathbuf, Char *pathend, Char *pathlim,
-	Char *pattern, glob_t *pglob, size_t *limit)
+glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    glob_t *pglob, struct glob_limit *limit)
 {
 	__gl_stat_t sb;
-	Char *p, *q;
+	const Char *p;
+	Char *q;
 	int anymeta;
 
+	_DIAGASSERT(pathbuf != NULL);
+	_DIAGASSERT(pathend != NULL);
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(pglob != NULL);
+
+#ifdef DEBUG
+	qprintf("glob2", pathbuf);
+#endif
 	/*
 	 * Loop over pattern segments until end of pattern or until
 	 * segment with meta character found.
@@ -528,20 +624,27 @@ glob2(Char *pathbuf, Char *pathend, Char
 		if (*pattern == EOS) {		/* End of pattern? */
 			*pathend = EOS;
 			if (g_lstat(pathbuf, &sb, pglob))
-				return(0);
+				return 0;
 		
+			if ((pglob->gl_flags & GLOB_LIMIT) &&
+			    limit->l_stat++ >= GLOB_LIMIT_STAT) {
+				errno = 0;
+				*pathend++ = SEP;
+				*pathend = EOS;
+				return GLOB_NOSPACE;
+			}
 			if (((pglob->gl_flags & GLOB_MARK) &&
 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
 			    (S_ISLNK(sb.st_mode) &&
 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
 			    S_ISDIR(sb.st_mode)))) {
 				if (pathend >= pathlim)
-					return (GLOB_ABORTED);
+					return GLOB_ABORTED;
 				*pathend++ = SEP;
 				*pathend = EOS;
 			}
 			++pglob->gl_matchc;
-			return(globextend(pathbuf, pglob, limit));
+			return globextend(pathbuf, pglob, limit);
 		}
 
 		/* Find end of next segment, copy tentatively to pathend. */
@@ -555,7 +658,7 @@ glob2(Char *pathbuf, Char *pathend, Char
 			*q++ = *p++;
 		}
 
-		if (!anymeta) {		/* No expansion, do next segment. */
+                if (!anymeta) {
 			pathend = q;
 			pattern = p;
 			while (*pattern == SEP) {
@@ -564,20 +667,25 @@ glob2(Char *pathbuf, Char *pathend, Char
 				*pathend++ = *pattern++;
 			}
 		} else			/* Need expansion, recurse. */
-			return(glob3(pathbuf, pathend, pathlim, pattern, p,
-			    pglob, limit));
+			return glob3(pathbuf, pathend, pathlim, pattern, p,
+			    pattern, pglob, limit);
 	}
 	/* NOTREACHED */
 }
 
 static int
-glob3(Char *pathbuf, Char *pathend, Char *pathlim,
-	Char *pattern, Char *restpattern, glob_t *pglob, size_t *limit)
+glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    const Char *restpattern, const Char *pglobstar, glob_t *pglob,
+    struct glob_limit *limit)
 {
 	struct dirent *dp;
 	DIR *dirp;
+	__gl_stat_t sbuf;
 	int error;
 	char buf[MAXPATHLEN];
+	int globstar = 0;
+	int chase_symlinks = 0;
+	const Char *termstar = NULL;
 
 	/*
 	 * The readdirfunc declaration can't be prototyped, because it is
@@ -587,16 +695,55 @@ glob3(Char *pathbuf, Char *pathend, Char
 	 */
 	struct dirent *(*readdirfunc)(void *);
 
+	_DIAGASSERT(pathbuf != NULL);
+	_DIAGASSERT(pathend != NULL);
+	_DIAGASSERT(pattern != NULL);
+	_DIAGASSERT(restpattern != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	*pathend = EOS;
 	errno = 0;
 	    
+	while (pglobstar < restpattern) {
+		if ((pglobstar[0] & M_MASK) == M_ALL &&
+		    (pglobstar[1] & M_MASK) == M_ALL) {
+			globstar = 1;
+			chase_symlinks = (pglobstar[2] & M_MASK) == M_ALL;
+			termstar = pglobstar + (2 + chase_symlinks);
+			break;
+		}
+		pglobstar++;
+	} 
+
+	if (globstar) {
+		error = pglobstar == pattern && termstar == restpattern ?
+		    *restpattern == EOS ?
+		    glob2(pathbuf, pathend, pathlim, restpattern - 1, pglob,
+		    limit) :
+		    glob2(pathbuf, pathend, pathlim, restpattern + 1, pglob,
+		    limit) :
+		    glob3(pathbuf, pathend, pathlim, pattern, restpattern,
+		    termstar, pglob, limit);
+		if (error)
+			return error;
+		*pathend = EOS;
+	}
+
+	if (*pathbuf && (g_lstat(pathbuf, &sbuf, pglob) ||
+	    !S_ISDIR(sbuf.st_mode)
+#ifdef S_IFLINK
+	     && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode))
+#endif
+	    ))
+		return 0;
+
 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
 		if (pglob->gl_errfunc) {
 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
-				return (GLOB_ABORTED);
+				return GLOB_ABORTED;
 			if (pglob->gl_errfunc(buf, errno) ||
 			    pglob->gl_flags & GLOB_ERR)
-				return (GLOB_ABORTED);
+				return GLOB_ABORTED;
 		}
 		/*
 		 * Posix/XOpen: glob should return when it encounters a
@@ -605,9 +752,9 @@ glob3(Char *pathbuf, Char *pathend, Char
 		 * I think that Posix had in mind EPERM...
 		 */
 		if (pglob->gl_flags & GLOB_ERR)
-			return (GLOB_ABORTED);
+			return GLOB_ABORTED;
 
-		return(0);
+		return 0;
 	}
 
 	error = 0;
@@ -618,17 +765,38 @@ glob3(Char *pathbuf, Char *pathend, Char
 	else
 		readdirfunc = (struct dirent *(*)(void *)) readdir;
 	while ((dp = (*readdirfunc)(dirp)) != NULL) {
-		unsigned char *sc;
+		u_char *sc;
 		Char *dc;
 
-		/* Initial DOT must be matched literally. */
-		if (dp->d_name[0] == DOT && *pattern != DOT)
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limit->l_readdir++ >= GLOB_LIMIT_READDIR) {
+			errno = 0;
+			*pathend++ = SEP;
+			*pathend = EOS;
+			error = GLOB_NOSPACE;
+			break;
+		}
+
+		/*
+		 * Initial DOT must be matched literally, unless we have
+		 * GLOB_PERIOD set.
+		 */
+		if ((pglob->gl_flags & GLOB_PERIOD) == 0)
+			if (dp->d_name[0] == DOT && *pattern != DOT)
+				continue;
+		/*
+		 * If GLOB_NO_DOTDIRS is set, . and .. vanish.
+		 */
+		if ((pglob->gl_flags & GLOB_NO_DOTDIRS) &&
+		    (dp->d_name[0] == DOT) &&
+		    ((dp->d_name[1] == EOS) ||
+		     ((dp->d_name[1] == DOT) && (dp->d_name[2] == EOS))))
 			continue;
 		/*
 		 * The resulting string contains EOS, so we can
 		 * use the pathlim character, if it is the nul
 		 */
-		for (sc = (unsigned char *) dp->d_name, dc = pathend; 
+		for (sc = (u_char *) dp->d_name, dc = pathend; 
 		     dc <= pathlim && (*dc++ = *sc++) != EOS;)
 			continue;
 
@@ -651,15 +819,36 @@ glob3(Char *pathbuf, Char *pathend, Char
 			}
 		}
 
-		if (!match(pathend, pattern, restpattern)) {
+		if (globstar) {
+#ifdef S_IFLNK
+			if (!chase_symlinks &&
+			    (g_lstat(pathbuf, &sbuf, pglob) ||
+			    S_ISLNK(sbuf.st_mode)))
+				continue;
+#endif
+
+			if (!match(pathend, pattern, termstar))
+				continue;
+	    
+			if (--dc < pathlim - 2)
+				*dc++ = SEP;
+			*dc = EOS;
+			error = glob2(pathbuf, dc, pathlim, pglobstar,
+			    pglob, limit);
+			if (error)
+				break;
 			*pathend = EOS;
-			continue;
+		} else {
+			if (!match(pathend, pattern, restpattern)) {
+				*pathend = EOS;
+				continue;
+			}
+			error = glob2(pathbuf, --dc, pathlim, restpattern,
+			    pglob, limit);
+			if (error)
+				break;
 		}
-		error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, limit);
-		if (error)
-			break;
 	}
-
 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 		(*pglob->gl_closedir)(dirp);
 	else
@@ -669,14 +858,14 @@ glob3(Char *pathbuf, Char *pathend, Char
 	 * Again Posix X/Open issue with regards to error handling.
 	 */
 	if ((error || errno) && (pglob->gl_flags & GLOB_ERR))
-		return (GLOB_ABORTED);
+		return GLOB_ABORTED;
 
-	return(error);
+	return error;
 }
 
 
 /*
- * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
  * add the new item, and update gl_pathc.
  *
  * This assumes the BSD realloc, which only copies the block when its size
@@ -690,18 +879,24 @@ glob3(Char *pathbuf, Char *pathend, Char
  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
 static int
-globextend(const Char *path, glob_t *pglob, size_t *limit)
+globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
 {
 	char **pathv;
 	size_t i, newsize, len;
 	char *copy;
 	const Char *p;
 
+	_DIAGASSERT(path != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+	if ((pglob->gl_flags & GLOB_LIMIT) &&
+	    newsize > GLOB_LIMIT_PATH * sizeof(*pathv))
+		goto nospace;
 	pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :
 	    malloc(newsize);
 	if (pathv == NULL)
-		return(GLOB_NOSPACE);
+		return GLOB_NOSPACE;
 
 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
 		/* first time around -- clear initial gl_offs items */
@@ -714,22 +909,24 @@ globextend(const Char *path, glob_t *pgl
 	for (p = path; *p++;)
 		continue;
 	len = (size_t)(p - path);
-	*limit += len;
+	limit->l_string += len;
 	if ((copy = malloc(len)) != NULL) {
 		if (g_Ctoc(path, copy, len)) {
 			free(copy);
-			return(GLOB_ABORTED);
+			return GLOB_ABORTED;
 		}
 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
 	}
 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
 
-	if ((pglob->gl_flags & GLOB_LIMIT) && (newsize + *limit) >= ARG_MAX) {
-		errno = 0;
-		return(GLOB_NOSPACE);
-	}
+	if ((pglob->gl_flags & GLOB_LIMIT) &&
+	    (newsize + limit->l_string) >= GLOB_LIMIT_STRING)
+		goto nospace;
 
-	return(copy == NULL ? GLOB_NOSPACE : 0);
+	return copy == NULL ? GLOB_NOSPACE : 0;
+nospace:
+	errno = 0;
+	return GLOB_NOSPACE;
 }
 
 
@@ -738,30 +935,35 @@ globextend(const Char *path, glob_t *pgl
  * pattern causes a recursion level.
  */
 static int
-match(Char *name, Char *pat, Char *patend)
+match(const Char *name, const Char *pat, const Char *patend)
 {
 	int ok, negate_range;
 	Char c, k;
 
+	_DIAGASSERT(name != NULL);
+	_DIAGASSERT(pat != NULL);
+	_DIAGASSERT(patend != NULL);
+
 	while (pat < patend) {
 		c = *pat++;
 		switch (c & M_MASK) {
 		case M_ALL:
+			while (pat < patend && (*pat & M_MASK) == M_ALL)
+				pat++;	/* eat consecutive '*' */
 			if (pat == patend)
-				return(1);
-			do 
-			    if (match(name, pat, patend))
-				    return(1);
-			while (*name++ != EOS);
-			return(0);
+				return 1;
+			for (; !match(name, pat, patend); name++)
+				if (*name == EOS)
+					return 0;
+			return 1;
 		case M_ONE:
 			if (*name++ == EOS)
-				return(0);
+				return 0;
 			break;
 		case M_SET:
 			ok = 0;
 			if ((k = *name++) == EOS)
-				return(0);
+				return 0;
 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
 				++pat;
 			while (((c = *pat++) & M_MASK) != M_END)
@@ -772,15 +974,15 @@ match(Char *name, Char *pat, Char *paten
 				} else if (c == k)
 					ok = 1;
 			if (ok == negate_range)
-				return(0);
+				return 0;
 			break;
 		default:
 			if (*name++ != c)
-				return(0);
+				return 0;
 			break;
 		}
 	}
-	return(*name == EOS);
+	return *name == EOS;
 }
 
 /* Free allocated data belonging to a glob_t structure. */
@@ -790,6 +992,8 @@ globfree(glob_t *pglob)
 	size_t i;
 	char **pp;
 
+	_DIAGASSERT(pglob != NULL);
+
 	if (pglob->gl_pathv != NULL) {
 		pp = pglob->gl_pathv + pglob->gl_offs;
 		for (i = pglob->gl_pathc; i--; ++pp)
@@ -801,11 +1005,47 @@ globfree(glob_t *pglob)
 	}
 }
 
+#ifndef __LIBC12_SOURCE__
+int
+glob_pattern_p(const char *pattern, int quote)
+{
+	int range = 0;
+
+	for (; *pattern; pattern++)
+		switch (*pattern) {
+		case QUESTION:
+		case STAR:
+			return 1;
+
+		case QUOTE:
+			if (quote && pattern[1] != EOS)
+			      ++pattern;
+			break;
+
+		case LBRACKET:
+			range = 1;
+			break;
+
+		case RBRACKET:
+			if (range)
+			      return 1;
+			break;
+		default:
+			break;
+		}
+
+	  return 0;
+}
+#endif
+
 static DIR *
 g_opendir(Char *str, glob_t *pglob)
 {
 	char buf[MAXPATHLEN];
 
+	_DIAGASSERT(str != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	if (!*str)
 		(void)strlcpy(buf, ".", sizeof(buf));
 	else {
@@ -814,9 +1054,9 @@ g_opendir(Char *str, glob_t *pglob)
 	}
 
 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
-		return((*pglob->gl_opendir)(buf));
+		return (*pglob->gl_opendir)(buf);
 
-	return(opendir(buf));
+	return opendir(buf);
 }
 
 static int
@@ -824,11 +1064,15 @@ g_lstat(Char *fn, __gl_stat_t *sb, glob_
 {
 	char buf[MAXPATHLEN];
 
+	_DIAGASSERT(fn != NULL);
+	_DIAGASSERT(sb != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	if (g_Ctoc(fn, buf, sizeof(buf)))
 		return -1;
 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
-		return((*pglob->gl_lstat)(buf, sb));
-	return(lstat(buf, sb));
+		return (*pglob->gl_lstat)(buf, sb);
+	return lstat(buf, sb);
 }
 
 static int
@@ -836,22 +1080,28 @@ g_stat(Char *fn, __gl_stat_t *sb, glob_t
 {
 	char buf[MAXPATHLEN];
 
+	_DIAGASSERT(fn != NULL);
+	_DIAGASSERT(sb != NULL);
+	_DIAGASSERT(pglob != NULL);
+
 	if (g_Ctoc(fn, buf, sizeof(buf)))
 		return -1;
 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
-		return((*pglob->gl_stat)(buf, sb));
-	return(stat(buf, sb));
+		return (*pglob->gl_stat)(buf, sb);
+	return stat(buf, sb);
 }
 
 static Char *
 g_strchr(const Char *str, int ch)
 {
+
+	_DIAGASSERT(str != NULL);
+
 	do {
 		if (*str == ch)
-			/* LINTED this is libc's definition! */
-			return (Char *)str;
+			return __UNCONST(str);
 	} while (*str++);
-	return (NULL);
+	return NULL;
 }
 
 static int
@@ -859,6 +1109,9 @@ g_Ctoc(const Char *str, char *buf, size_
 {
 	char *dc;
 
+	_DIAGASSERT(str != NULL);
+	_DIAGASSERT(buf != NULL);
+
 	if (len == 0)
 		return 1;
 
@@ -874,6 +1127,9 @@ qprintf(const char *str, Char *s)
 {
 	Char *p;
 
+	_DIAGASSERT(str != NULL);
+	_DIAGASSERT(s != NULL);
+
 	(void)printf("%s:\n", str);
 	for (p = s; *p; p++)
 		(void)printf("%c", CHAR(*p));

Reply via email to