File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / glob.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:11 2013 UTC (11 years ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, v1_8_7p0, v1_8_7, v1_8_10p3_0, v1_8_10p3, HEAD
1.8.7

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

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