svn commit: r207944 - in head: bin/sh tools/regression/bin/sh/expansion

Jilles Tjoelker jilles at FreeBSD.org
Tue May 11 23:19:28 UTC 2010


Author: jilles
Date: Tue May 11 23:19:28 2010
New Revision: 207944
URL: http://svn.freebsd.org/changeset/base/207944

Log:
  sh: Fix pathname expansion with quoted slashes like *\/.
  
  These are git commits 36f0fa8fcbc8c7b2b194addd29100fb40e73e4e9 and
  d6d06ff5c2ea0fa44becc5ef4340e5f2f15073e4 in dash.
  
  Because this is the first code I'm importing from dash to expand.c, add the
  Herbert Xu copyright notice which is in dash's expand.c.
  
  When pathname expanding *\/, the CTLESC representing the quoted state was
  erroneously taken as part of the * pathname component. This CTLESC was then
  seen by the pattern matching code as escaping the '\0' terminating the
  string.
  
  The code is slightly different because dash converts the CTLESC characters
  to backslashes and removes all the other CTL* characters to allow
  substituting glob(3).
  
  The effect of the bug was also slightly different from dash (where nothing
  matched at all). Because a CTLESC can escape a '\0' in some way, whether
  files were included despite the bug depended on memory that should not be
  read. In particular, on many machines /*\/ expanded to a strict subset of
  what /*/ expanded to.
  
  Example:
    echo /*"/null"
  
  This should print /dev/null, not /*/null.
  
  PR:		bin/146378
  Obtained from:	dash

Added:
  head/tools/regression/bin/sh/expansion/pathname2.0   (contents, props changed)
Modified:
  head/bin/sh/expand.c

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c	Tue May 11 23:08:38 2010	(r207943)
+++ head/bin/sh/expand.c	Tue May 11 23:19:28 2010	(r207944)
@@ -1,6 +1,8 @@
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert at gondor.apana.org.au>.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
@@ -1150,10 +1152,11 @@ expmeta(char *enddir, char *name)
 	struct dirent *dp;
 	int atend;
 	int matchdot;
+	int esc;
 
 	metaflag = 0;
 	start = name;
-	for (p = name ; ; p++) {
+	for (p = name; esc = 0, *p; p += esc + 1) {
 		if (*p == '*' || *p == '?')
 			metaflag = 1;
 		else if (*p == '[') {
@@ -1178,12 +1181,14 @@ expmeta(char *enddir, char *name)
 			break;
 		else if (*p == CTLQUOTEMARK)
 			continue;
-		else if (*p == CTLESC)
-			p++;
-		if (*p == '/') {
-			if (metaflag)
-				break;
-			start = p + 1;
+		else {
+			if (*p == CTLESC)
+				esc++;
+			if (p[esc] == '/') {
+				if (metaflag)
+					break;
+				start = p + esc + 1;
+			}
 		}
 	}
 	if (metaflag == 0) {	/* we've reached the end of the file name */
@@ -1229,7 +1234,8 @@ expmeta(char *enddir, char *name)
 		atend = 1;
 	} else {
 		atend = 0;
-		*endname++ = '\0';
+		*endname = '\0';
+		endname += esc + 1;
 	}
 	matchdot = 0;
 	p = start;
@@ -1257,7 +1263,7 @@ expmeta(char *enddir, char *name)
 	}
 	closedir(dirp);
 	if (! atend)
-		endname[-1] = '/';
+		endname[-esc - 1] = esc ? CTLESC : '/';
 }
 
 

Added: head/tools/regression/bin/sh/expansion/pathname2.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/expansion/pathname2.0	Tue May 11 23:19:28 2010	(r207944)
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+failures=0
+
+check() {
+	testcase=$1
+	expect=$2
+	eval "set -- $testcase"
+	actual="$*"
+	if [ "$actual" != "$expect" ]; then
+		failures=$((failures+1))
+		printf '%s\n' "For $testcase, expected $expect actual $actual"
+	fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir testdir testdir2 'testdir/*' 'testdir/?' testdir/a testdir/b testdir2/b
+mkdir testdir2/.c
+touch testf 'testdir/*/1' 'testdir/?/1' testdir/a/1 testdir/b/1 testdir2/b/.a
+
+check '*\/' 'testdir/ testdir2/'
+check '"testdir/"*"/1"' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*\/*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir"*"/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+
+exit $((failures != 0))


More information about the svn-src-all mailing list