File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / glob.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 4 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_5p1, v1_8_3p2, HEAD
sudo

    1: /*
    2:  * Copyright (c) 2008-2010 Todd C. Miller <Todd.Miller@courtesan.com>
    3:  * Copyright (c) 1989, 1993
    4:  *	The Regents of the University of California.  All rights reserved.
    5:  *
    6:  * This code is derived from software contributed to Berkeley by
    7:  * Guido van Rossum.
    8:  *
    9:  * Redistribution and use in source and binary forms, with or without
   10:  * modification, are permitted provided that the following conditions
   11:  * are met:
   12:  * 1. Redistributions of source code must retain the above copyright
   13:  *    notice, this list of conditions and the following disclaimer.
   14:  * 2. Redistributions in binary form must reproduce the above copyright
   15:  *    notice, this list of conditions and the following disclaimer in the
   16:  *    documentation and/or other materials provided with the distribution.
   17:  * 3. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  *	@(#)glob.c	8.3 (Berkeley) 10/13/93
   34:  */
   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_MAGCHAR:
   44:  *	Set in gl_flags if pattern contained a globbing character.
   45:  * GLOB_TILDE:
   46:  *	expand ~user/foo to the /home/dir/of/user/foo
   47:  * GLOB_BRACE:
   48:  *	expand {1,2}{a,b} to 1a 1b 2a 2b
   49:  * gl_matchc:
   50:  *	Number of matches in the current invocation of glob.
   51:  */
   52: 
   53: #include <config.h>
   54: 
   55: #include <sys/param.h>
   56: #include <sys/stat.h>
   57: 
   58: #include <stdio.h>
   59: #ifdef STDC_HEADERS
   60: # include <stdlib.h>
   61: # include <stddef.h>
   62: #else
   63: # ifdef HAVE_STDLIB_H
   64: #  include <stdlib.h>
   65: # endif
   66: #endif /* STDC_HEADERS */
   67: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
   68: # include <malloc.h>
   69: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
   70: #ifdef HAVE_STRING_H
   71: # include <string.h>
   72: #endif /* HAVE_STRING_H */
   73: #ifdef HAVE_STRINGS_H
   74: # include <strings.h>
   75: #endif /* HAVE_STRINGS_H */
   76: #ifdef HAVE_UNISTD_H
   77: # include <unistd.h>
   78: #endif /* HAVE_UNISTD_H */
   79: #include <ctype.h>
   80: #ifdef HAVE_DIRENT_H
   81: # include <dirent.h>
   82: #else
   83: # define dirent direct
   84: # ifdef HAVE_SYS_NDIR_H
   85: #  include <sys/ndir.h>
   86: # endif
   87: # ifdef HAVE_SYS_DIR_H
   88: #  include <sys/dir.h>
   89: # endif
   90: # ifdef HAVE_NDIR_H
   91: #  include <ndir.h>
   92: # endif
   93: #endif
   94: #include <errno.h>
   95: #include <limits.h>
   96: #include <pwd.h>
   97: 
   98: #include "missing.h"
   99: #include "compat/glob.h"
  100: #include "compat/charclass.h"
  101: 
  102: #define	DOLLAR		'$'
  103: #define	DOT		'.'
  104: #define	EOS		'\0'
  105: #define	LBRACKET	'['
  106: #define	NOT		'!'
  107: #define	QUESTION	'?'
  108: #define	QUOTE		'\\'
  109: #define	RANGE		'-'
  110: #define	RBRACKET	']'
  111: #define	SEP		'/'
  112: #define	STAR		'*'
  113: #define	TILDE		'~'
  114: #define	UNDERSCORE	'_'
  115: #define	LBRACE		'{'
  116: #define	RBRACE		'}'
  117: #define	SLASH		'/'
  118: #define	COMMA		','
  119: 
  120: #ifndef DEBUG
  121: 
  122: #define	M_QUOTE		0x8000
  123: #define	M_PROTECT	0x4000
  124: #define	M_MASK		0xffff
  125: #define	M_ASCII		0x00ff
  126: 
  127: typedef unsigned short Char;
  128: 
  129: #else
  130: 
  131: #define	M_QUOTE		0x80
  132: #define	M_PROTECT	0x40
  133: #define	M_MASK		0xff
  134: #define	M_ASCII		0x7f
  135: 
  136: typedef char Char;
  137: 
  138: #endif
  139: 
  140: 
  141: #define	CHAR(c)		((Char)((c)&M_ASCII))
  142: #define	META(c)		((Char)((c)|M_QUOTE))
  143: #define	M_ALL		META('*')
  144: #define	M_END		META(']')
  145: #define	M_NOT		META('!')
  146: #define	M_ONE		META('?')
  147: #define	M_RNG		META('-')
  148: #define	M_SET		META('[')
  149: #define	M_CLASS		META(':')
  150: #define	ismeta(c)	(((c)&M_QUOTE) != 0)
  151: 
  152: 
  153: static int	 compare(const void *, const void *);
  154: static int	 g_Ctoc(const Char *, char *, unsigned int);
  155: static int	 g_lstat(Char *, struct stat *, glob_t *);
  156: static DIR	*g_opendir(Char *, glob_t *);
  157: static Char	*g_strchr(const Char *, int);
  158: static int	 g_strncmp(const Char *, const char *, size_t);
  159: static int	 g_stat(Char *, struct stat *, glob_t *);
  160: static int	 glob0(const Char *, glob_t *);
  161: static int	 glob1(Char *, Char *, glob_t *);
  162: static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
  163: 		    glob_t *);
  164: static int	 glob3(Char *, Char *, Char *, Char *, Char *, Char *,
  165: 		    Char *, Char *, glob_t *);
  166: static int	 globextend(const Char *, glob_t *);
  167: static const Char *
  168: 		 globtilde(const Char *, Char *, size_t, glob_t *);
  169: static int	 globexp1(const Char *, glob_t *);
  170: static int	 globexp2(const Char *, const Char *, glob_t *, int *);
  171: static int	 match(Char *, Char *, Char *);
  172: #ifdef DEBUG
  173: static void	 qprintf(const char *, Char *);
  174: #endif
  175: 
  176: int
  177: rpl_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
  178: 	glob_t *pglob)
  179: {
  180: 	const unsigned char *patnext;
  181: 	int c;
  182: 	Char *bufnext, *bufend, patbuf[PATH_MAX];
  183: 
  184: 	patnext = (unsigned char *) pattern;
  185: 	if (!(flags & GLOB_APPEND)) {
  186: 		pglob->gl_pathc = 0;
  187: 		pglob->gl_pathv = NULL;
  188: 		if (!(flags & GLOB_DOOFFS))
  189: 			pglob->gl_offs = 0;
  190: 	}
  191: 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  192: 	pglob->gl_errfunc = errfunc;
  193: 	pglob->gl_matchc = 0;
  194: 
  195: 	bufnext = patbuf;
  196: 	bufend = bufnext + PATH_MAX - 1;
  197: 	if (flags & GLOB_NOESCAPE)
  198: 		while (bufnext < bufend && (c = *patnext++) != EOS)
  199: 			*bufnext++ = c;
  200: 	else {
  201: 		/* Protect the quoted characters. */
  202: 		while (bufnext < bufend && (c = *patnext++) != EOS)
  203: 			if (c == QUOTE) {
  204: 				if ((c = *patnext++) == EOS) {
  205: 					c = QUOTE;
  206: 					--patnext;
  207: 				}
  208: 				*bufnext++ = c | M_PROTECT;
  209: 			} else
  210: 				*bufnext++ = c;
  211: 	}
  212: 	*bufnext = EOS;
  213: 
  214: 	if (flags & GLOB_BRACE)
  215: 		return globexp1(patbuf, pglob);
  216: 	else
  217: 		return glob0(patbuf, pglob);
  218: }
  219: 
  220: /*
  221:  * Expand recursively a glob {} pattern. When there is no more expansion
  222:  * invoke the standard globbing routine to glob the rest of the magic
  223:  * characters
  224:  */
  225: static int
  226: globexp1(const Char *pattern, glob_t *pglob)
  227: {
  228: 	const Char* ptr = pattern;
  229: 	int rv;
  230: 
  231: 	/* Protect a single {}, for find(1), like csh */
  232: 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
  233: 		return glob0(pattern, pglob);
  234: 
  235: 	while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
  236: 		if (!globexp2(ptr, pattern, pglob, &rv))
  237: 			return rv;
  238: 
  239: 	return glob0(pattern, pglob);
  240: }
  241: 
  242: 
  243: /*
  244:  * Recursive brace globbing helper. Tries to expand a single brace.
  245:  * If it succeeds then it invokes globexp1 with the new pattern.
  246:  * If it fails then it tries to glob the rest of the pattern and returns.
  247:  */
  248: static int
  249: globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
  250: {
  251: 	int     i;
  252: 	Char   *lm, *ls;
  253: 	const Char *pe, *pm, *pl;
  254: 	Char    patbuf[PATH_MAX];
  255: 
  256: 	/* copy part up to the brace */
  257: 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  258: 		continue;
  259: 	*lm = EOS;
  260: 	ls = lm;
  261: 
  262: 	/* Find the balanced brace */
  263: 	for (i = 0, pe = ++ptr; *pe; pe++)
  264: 		if (*pe == LBRACKET) {
  265: 			/* Ignore everything between [] */
  266: 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
  267: 				continue;
  268: 			if (*pe == EOS) {
  269: 				/*
  270: 				 * We could not find a matching RBRACKET.
  271: 				 * Ignore and just look for RBRACE
  272: 				 */
  273: 				pe = pm;
  274: 			}
  275: 		} else if (*pe == LBRACE)
  276: 			i++;
  277: 		else if (*pe == RBRACE) {
  278: 			if (i == 0)
  279: 				break;
  280: 			i--;
  281: 		}
  282: 
  283: 	/* Non matching braces; just glob the pattern */
  284: 	if (i != 0 || *pe == EOS) {
  285: 		*rv = glob0(patbuf, pglob);
  286: 		return 0;
  287: 	}
  288: 
  289: 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
  290: 		switch (*pm) {
  291: 		case LBRACKET:
  292: 			/* Ignore everything between [] */
  293: 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
  294: 				continue;
  295: 			if (*pm == EOS) {
  296: 				/*
  297: 				 * We could not find a matching RBRACKET.
  298: 				 * Ignore and just look for RBRACE
  299: 				 */
  300: 				pm = pl;
  301: 			}
  302: 			break;
  303: 
  304: 		case LBRACE:
  305: 			i++;
  306: 			break;
  307: 
  308: 		case RBRACE:
  309: 			if (i) {
  310: 				i--;
  311: 				break;
  312: 			}
  313: 			/* FALLTHROUGH */
  314: 		case COMMA:
  315: 			if (i && *pm == COMMA)
  316: 				break;
  317: 			else {
  318: 				/* Append the current string */
  319: 				for (lm = ls; (pl < pm); *lm++ = *pl++)
  320: 					continue;
  321: 
  322: 				/*
  323: 				 * Append the rest of the pattern after the
  324: 				 * closing brace
  325: 				 */
  326: 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
  327: 					continue;
  328: 
  329: 				/* Expand the current pattern */
  330: #ifdef DEBUG
  331: 				qprintf("globexp2:", patbuf);
  332: #endif
  333: 				*rv = globexp1(patbuf, pglob);
  334: 
  335: 				/* move after the comma, to the next string */
  336: 				pl = pm + 1;
  337: 			}
  338: 			break;
  339: 
  340: 		default:
  341: 			break;
  342: 		}
  343: 	}
  344: 	*rv = 0;
  345: 	return 0;
  346: }
  347: 
  348: 
  349: 
  350: /*
  351:  * expand tilde from the passwd file.
  352:  */
  353: static const Char *
  354: globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
  355: {
  356: 	struct passwd *pwd;
  357: 	char *h;
  358: 	const Char *p;
  359: 	Char *b, *eb;
  360: 
  361: 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
  362: 		return pattern;
  363: 
  364: 	/* Copy up to the end of the string or / */
  365: 	eb = &patbuf[patbuf_len - 1];
  366: 	for (p = pattern + 1, h = (char *) patbuf;
  367: 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
  368: 		continue;
  369: 
  370: 	*h = EOS;
  371: 
  372: 	if (((char *) patbuf)[0] == EOS) {
  373: 		/*
  374: 		 * handle a plain ~ or ~/ by expanding $HOME
  375: 		 * first and then trying the password file
  376: 		 */
  377: 		if ((h = getenv("HOME")) == NULL) {
  378: 			if ((pwd = getpwuid(getuid())) == NULL)
  379: 				return pattern;
  380: 			else
  381: 				h = pwd->pw_dir;
  382: 		}
  383: 	} else {
  384: 		/*
  385: 		 * Expand a ~user
  386: 		 */
  387: 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
  388: 			return pattern;
  389: 		else
  390: 			h = pwd->pw_dir;
  391: 	}
  392: 
  393: 	/* Copy the home directory */
  394: 	for (b = patbuf; b < eb && *h; *b++ = *h++)
  395: 		continue;
  396: 
  397: 	/* Append the rest of the pattern */
  398: 	while (b < eb && (*b++ = *p++) != EOS)
  399: 		continue;
  400: 	*b = EOS;
  401: 
  402: 	return patbuf;
  403: }
  404: 
  405: static int
  406: g_strncmp(const Char *s1, const char *s2, size_t n)
  407: {
  408: 	int rv = 0;
  409: 
  410: 	while (n--) {
  411: 		rv = *(Char *)s1 - *(const unsigned char *)s2++;
  412: 		if (rv)
  413: 			break;
  414: 		if (*s1++ == '\0')
  415: 			break;
  416: 	}
  417: 	return rv;
  418: }
  419: 
  420: static int
  421: g_charclass(const Char **patternp, Char **bufnextp)
  422: {
  423: 	const Char *pattern = *patternp + 1;
  424: 	Char *bufnext = *bufnextp;
  425: 	const Char *colon;
  426: 	struct cclass *cc;
  427: 	size_t len;
  428: 
  429: 	if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
  430: 		return 1;	/* not a character class */
  431: 
  432: 	len = (size_t)(colon - pattern);
  433: 	for (cc = cclasses; cc->name != NULL; cc++) {
  434: 		if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
  435: 			break;
  436: 	}
  437: 	if (cc->name == NULL)
  438: 		return -1;	/* invalid character class */
  439: 	*bufnext++ = M_CLASS;
  440: 	*bufnext++ = (Char)(cc - &cclasses[0]);
  441: 	*bufnextp = bufnext;
  442: 	*patternp += len + 3;
  443: 
  444: 	return 0;
  445: }
  446: 
  447: /*
  448:  * The main glob() routine: compiles the pattern (optionally processing
  449:  * quotes), calls glob1() to do the real pattern matching, and finally
  450:  * sorts the list (unless unsorted operation is requested).  Returns 0
  451:  * if things went well, nonzero if errors occurred.  It is not an error
  452:  * to find no matches.
  453:  */
  454: static int
  455: glob0(const Char *pattern, glob_t *pglob)
  456: {
  457: 	const Char *qpatnext;
  458: 	int c, err, oldpathc;
  459: 	Char *bufnext, patbuf[PATH_MAX];
  460: 
  461: 	qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
  462: 	oldpathc = pglob->gl_pathc;
  463: 	bufnext = patbuf;
  464: 
  465: 	/* We don't need to check for buffer overflow any more. */
  466: 	while ((c = *qpatnext++) != EOS) {
  467: 		switch (c) {
  468: 		case LBRACKET:
  469: 			c = *qpatnext;
  470: 			if (c == NOT)
  471: 				++qpatnext;
  472: 			if (*qpatnext == EOS ||
  473: 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
  474: 				*bufnext++ = LBRACKET;
  475: 				if (c == NOT)
  476: 					--qpatnext;
  477: 				break;
  478: 			}
  479: 			*bufnext++ = M_SET;
  480: 			if (c == NOT)
  481: 				*bufnext++ = M_NOT;
  482: 			c = *qpatnext++;
  483: 			do {
  484: 				if (c == LBRACKET && *qpatnext == ':') {
  485: 					do {
  486: 						err = g_charclass(&qpatnext,
  487: 						    &bufnext);
  488: 						if (err)
  489: 							break;
  490: 						c = *qpatnext++;
  491: 					} while (c == LBRACKET && *qpatnext == ':');
  492: 					if (err == -1 &&
  493: 					    !(pglob->gl_flags & GLOB_NOCHECK))
  494: 						return GLOB_NOMATCH;
  495: 					if (c == RBRACKET)
  496: 						break;
  497: 				}
  498: 				*bufnext++ = CHAR(c);
  499: 				if (*qpatnext == RANGE &&
  500: 				    (c = qpatnext[1]) != RBRACKET) {
  501: 					*bufnext++ = M_RNG;
  502: 					*bufnext++ = CHAR(c);
  503: 					qpatnext += 2;
  504: 				}
  505: 			} while ((c = *qpatnext++) != RBRACKET);
  506: 			pglob->gl_flags |= GLOB_MAGCHAR;
  507: 			*bufnext++ = M_END;
  508: 			break;
  509: 		case QUESTION:
  510: 			pglob->gl_flags |= GLOB_MAGCHAR;
  511: 			*bufnext++ = M_ONE;
  512: 			break;
  513: 		case STAR:
  514: 			pglob->gl_flags |= GLOB_MAGCHAR;
  515: 			/* collapse adjacent stars to one,
  516: 			 * to avoid exponential behavior
  517: 			 */
  518: 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
  519: 				*bufnext++ = M_ALL;
  520: 			break;
  521: 		default:
  522: 			*bufnext++ = CHAR(c);
  523: 			break;
  524: 		}
  525: 	}
  526: 	*bufnext = EOS;
  527: #ifdef DEBUG
  528: 	qprintf("glob0:", patbuf);
  529: #endif
  530: 
  531: 	if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0)
  532: 		return err;
  533: 
  534: 	/*
  535: 	 * If there was no match we are going to append the pattern
  536: 	 * if GLOB_NOCHECK was specified.
  537: 	 */
  538: 	if (pglob->gl_pathc == oldpathc) {
  539: 		if (pglob->gl_flags & GLOB_NOCHECK)
  540: 			return globextend(pattern, pglob);
  541: 		else
  542: 			return GLOB_NOMATCH;
  543: 	}
  544: 	if (!(pglob->gl_flags & GLOB_NOSORT))
  545: 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  546: 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
  547: 	return 0;
  548: }
  549: 
  550: static int
  551: compare(const void *p, const void *q)
  552: {
  553: 	return strcmp(*(char **)p, *(char **)q);
  554: }
  555: 
  556: static int
  557: glob1(Char *pattern, Char *pattern_last, glob_t *pglob)
  558: {
  559: 	Char pathbuf[PATH_MAX];
  560: 
  561: 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  562: 	if (*pattern == EOS)
  563: 		return 0;
  564: 	return glob2(pathbuf, pathbuf + PATH_MAX - 1,
  565: 	    pathbuf, pathbuf + PATH_MAX - 1,
  566: 	    pattern, pattern_last, pglob);
  567: }
  568: 
  569: /*
  570:  * The functions glob2 and glob3 are mutually recursive; there is one level
  571:  * of recursion for each segment in the pattern that contains one or more
  572:  * meta characters.
  573:  */
  574: static int
  575: glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
  576: 	Char *pattern, Char *pattern_last, glob_t *pglob)
  577: {
  578: 	struct stat sb;
  579: 	Char *p, *q;
  580: 	int anymeta;
  581: 
  582: 	/*
  583: 	 * Loop over pattern segments until end of pattern or until
  584: 	 * segment with meta character found.
  585: 	 */
  586: 	for (anymeta = 0;;) {
  587: 		if (*pattern == EOS) {		/* End of pattern? */
  588: 			*pathend = EOS;
  589: 			if (g_lstat(pathbuf, &sb, pglob))
  590: 				return 0;
  591: 
  592: 			if (((pglob->gl_flags & GLOB_MARK) &&
  593: 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
  594: 			    (S_ISLNK(sb.st_mode) &&
  595: 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
  596: 			    S_ISDIR(sb.st_mode)))) {
  597: 				if (pathend+1 > pathend_last)
  598: 					return 1;
  599: 				*pathend++ = SEP;
  600: 				*pathend = EOS;
  601: 			}
  602: 			++pglob->gl_matchc;
  603: 			return globextend(pathbuf, pglob);
  604: 		}
  605: 
  606: 		/* Find end of next segment, copy tentatively to pathend. */
  607: 		q = pathend;
  608: 		p = pattern;
  609: 		while (*p != EOS && *p != SEP) {
  610: 			if (ismeta(*p))
  611: 				anymeta = 1;
  612: 			if (q+1 > pathend_last)
  613: 				return 1;
  614: 			*q++ = *p++;
  615: 		}
  616: 
  617: 		if (!anymeta) {		/* No expansion, do next segment. */
  618: 			pathend = q;
  619: 			pattern = p;
  620: 			while (*pattern == SEP) {
  621: 				if (pathend+1 > pathend_last)
  622: 					return 1;
  623: 				*pathend++ = *pattern++;
  624: 			}
  625: 		} else
  626: 			/* Need expansion, recurse. */
  627: 			return glob3(pathbuf, pathbuf_last, pathend,
  628: 			    pathend_last, pattern, pattern_last,
  629: 			    p, pattern_last, pglob);
  630: 	}
  631: 	/* NOTREACHED */
  632: }
  633: 
  634: static int
  635: glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
  636: 	Char *pattern, Char *pattern_last, Char *restpattern,
  637: 	Char *restpattern_last, glob_t *pglob)
  638: {
  639: 	struct dirent *dp;
  640: 	DIR *dirp;
  641: 	int err;
  642: 	char buf[PATH_MAX];
  643: 
  644: 	if (pathend > pathend_last)
  645: 		return 1;
  646: 	*pathend = EOS;
  647: 	errno = 0;
  648: 
  649: 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  650: 		/* TODO: don't call for ENOENT or ENOTDIR? */
  651: 		if (pglob->gl_errfunc) {
  652: 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
  653: 				return GLOB_ABORTED;
  654: 			if (pglob->gl_errfunc(buf, errno) ||
  655: 			    pglob->gl_flags & GLOB_ERR)
  656: 				return GLOB_ABORTED;
  657: 		}
  658: 		return 0;
  659: 	}
  660: 
  661: 	err = 0;
  662: 
  663: 	/* Search directory for matching names. */
  664: 	while ((dp = readdir(dirp))) {
  665: 		unsigned char *sc;
  666: 		Char *dc;
  667: 
  668: 		/* Initial DOT must be matched literally. */
  669: 		if (dp->d_name[0] == DOT && *pattern != DOT)
  670: 			continue;
  671: 		dc = pathend;
  672: 		sc = (unsigned char *) dp->d_name;
  673: 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
  674: 			continue;
  675: 		if (dc >= pathend_last) {
  676: 			*dc = EOS;
  677: 			err = 1;
  678: 			break;
  679: 		}
  680: 
  681: 		if (!match(pathend, pattern, restpattern)) {
  682: 			*pathend = EOS;
  683: 			continue;
  684: 		}
  685: 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
  686: 		    restpattern, restpattern_last, pglob);
  687: 		if (err)
  688: 			break;
  689: 	}
  690: 
  691: 	closedir(dirp);
  692: 	return err;
  693: }
  694: 
  695: /*
  696:  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
  697:  * add the new item, and update gl_pathc.
  698:  *
  699:  * This assumes the BSD realloc, which only copies the block when its size
  700:  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  701:  * behavior.
  702:  *
  703:  * Return 0 if new item added, error code if memory couldn't be allocated.
  704:  *
  705:  * Invariant of the glob_t structure:
  706:  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  707:  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  708:  */
  709: static int
  710: globextend(const Char *path, glob_t *pglob)
  711: {
  712: 	char **pathv;
  713: 	int i;
  714: 	unsigned int newsize, len;
  715: 	char *copy;
  716: 	const Char *p;
  717: 
  718: 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  719: 	pathv = pglob->gl_pathv ?
  720: 	    (char **)realloc((char *)pglob->gl_pathv, newsize) :
  721: 	    (char **)malloc(newsize);
  722: 	if (pathv == NULL) {
  723: 		if (pglob->gl_pathv) {
  724: 			free(pglob->gl_pathv);
  725: 			pglob->gl_pathv = NULL;
  726: 		}
  727: 		return GLOB_NOSPACE;
  728: 	}
  729: 
  730: 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  731: 		/* first time around -- clear initial gl_offs items */
  732: 		pathv += pglob->gl_offs;
  733: 		for (i = pglob->gl_offs; --i >= 0; )
  734: 			*--pathv = NULL;
  735: 	}
  736: 	pglob->gl_pathv = pathv;
  737: 
  738: 	for (p = path; *p++;)
  739: 		continue;
  740: 	len = (size_t)(p - path);
  741: 	if ((copy = malloc(len)) != NULL) {
  742: 		if (g_Ctoc(path, copy, len)) {
  743: 			free(copy);
  744: 			return GLOB_NOSPACE;
  745: 		}
  746: 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  747: 	}
  748: 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  749: 
  750: 	return copy == NULL ? GLOB_NOSPACE : 0;
  751: }
  752: 
  753: /*
  754:  * pattern matching function for filenames.  Each occurrence of the *
  755:  * pattern causes a recursion level.
  756:  */
  757: static int
  758: match(Char *name, Char *pat, Char *patend)
  759: {
  760: 	int ok, negate_range;
  761: 	Char c, k;
  762: 
  763: 	while (pat < patend) {
  764: 		c = *pat++;
  765: 		switch (c & M_MASK) {
  766: 		case M_ALL:
  767: 			if (pat == patend)
  768: 				return 1;
  769: 			do {
  770: 			    if (match(name, pat, patend))
  771: 				    return 1;
  772: 			} while (*name++ != EOS);
  773: 			return 0;
  774: 		case M_ONE:
  775: 			if (*name++ == EOS)
  776: 				return 0;
  777: 			break;
  778: 		case M_SET:
  779: 			ok = 0;
  780: 			if ((k = *name++) == EOS)
  781: 				return 0;
  782: 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
  783: 				++pat;
  784: 			while (((c = *pat++) & M_MASK) != M_END) {
  785: 				if ((c & M_MASK) == M_CLASS) {
  786: 					int idx = *pat & M_MASK;
  787: 					if (idx < NCCLASSES &&
  788: 					    cclasses[idx].isctype(k))
  789: 						ok = 1;
  790: 					++pat;
  791: 				}
  792: 				if ((*pat & M_MASK) == M_RNG) {
  793: 					if (c <= k && k <= pat[1])
  794: 						ok = 1;
  795: 					pat += 2;
  796: 				} else if (c == k)
  797: 					ok = 1;
  798: 			}
  799: 			if (ok == negate_range)
  800: 				return 0;
  801: 			break;
  802: 		default:
  803: 			if (*name++ != c)
  804: 				return 0;
  805: 			break;
  806: 		}
  807: 	}
  808: 	return *name == EOS;
  809: }
  810: 
  811: /* Free allocated data belonging to a glob_t structure. */
  812: void
  813: rpl_globfree(glob_t *pglob)
  814: {
  815: 	int i;
  816: 	char **pp;
  817: 
  818: 	if (pglob->gl_pathv != NULL) {
  819: 		pp = pglob->gl_pathv + pglob->gl_offs;
  820: 		for (i = pglob->gl_pathc; i--; ++pp)
  821: 			if (*pp)
  822: 				free(*pp);
  823: 		free(pglob->gl_pathv);
  824: 		pglob->gl_pathv = NULL;
  825: 	}
  826: }
  827: 
  828: static DIR *
  829: g_opendir(Char *str, glob_t *pglob)
  830: {
  831: 	char buf[PATH_MAX];
  832: 
  833: 	if (!*str) {
  834: 		buf[0] = '.';
  835: 		buf[1] = '\0';
  836: 	} else {
  837: 		if (g_Ctoc(str, buf, sizeof(buf)))
  838: 			return NULL;
  839: 	}
  840: 	return opendir(buf);
  841: }
  842: 
  843: static int
  844: g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
  845: {
  846: 	char buf[PATH_MAX];
  847: 
  848: 	if (g_Ctoc(fn, buf, sizeof(buf)))
  849: 		return -1;
  850: 	return lstat(buf, sb);
  851: }
  852: 
  853: static int
  854: g_stat(Char *fn, struct stat *sb, glob_t *pglob)
  855: {
  856: 	char buf[PATH_MAX];
  857: 
  858: 	if (g_Ctoc(fn, buf, sizeof(buf)))
  859: 		return -1;
  860: 	return stat(buf, sb);
  861: }
  862: 
  863: static Char *
  864: g_strchr(const Char *str, int ch)
  865: {
  866: 	do {
  867: 		if (*str == ch)
  868: 			return (Char *)str;
  869: 	} while (*str++);
  870: 	return NULL;
  871: }
  872: 
  873: static int
  874: g_Ctoc(const Char *str, char *buf, unsigned int len)
  875: {
  876: 
  877: 	while (len--) {
  878: 		if ((*buf++ = *str++) == EOS)
  879: 			return 0;
  880: 	}
  881: 	return 1;
  882: }
  883: 
  884: #ifdef DEBUG
  885: static void
  886: qprintf(const char *str, Char *s)
  887: {
  888: 	Char *p;
  889: 
  890: 	(void)printf("%s:\n", str);
  891: 	for (p = s; *p; p++)
  892: 		(void)printf("%c", CHAR(*p));
  893: 	(void)printf("\n");
  894: 	for (p = s; *p; p++)
  895: 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
  896: 	(void)printf("\n");
  897: 	for (p = s; *p; p++)
  898: 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
  899: 	(void)printf("\n");
  900: }
  901: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>