Petr Šabata 33fc6c
From fcf6ae7d069a64741e9484cf219d7fe95de9e796 Mon Sep 17 00:00:00 2001
Petr Šabata 33fc6c
From: Chet Ramey <chet.ramey@case.edu>
Petr Šabata 33fc6c
Date: Tue, 19 Mar 2019 10:05:39 -0400
Petr Šabata 33fc6c
Subject: [PATCH] Bash-5.0 patch 3: improvements when globbing directory names
Petr Šabata 33fc6c
 containing backslashes
Petr Šabata 33fc6c
Petr Šabata 33fc6c
---
Petr Šabata 33fc6c
 bashline.c           |  2 +-
Petr Šabata 33fc6c
 lib/glob/glob.c      | 25 +++++++++++++++++++++----
Petr Šabata 33fc6c
 lib/glob/glob.h      |  1 +
Petr Šabata 33fc6c
 lib/glob/glob_loop.c | 23 ++++++++++++++++-------
Petr Šabata 33fc6c
 patchlevel.h         |  2 +-
Petr Šabata 33fc6c
 pathexp.c            | 16 ++++++++++++----
Petr Šabata 33fc6c
 6 files changed, 52 insertions(+), 17 deletions(-)
Petr Šabata 33fc6c
Petr Šabata 33fc6c
diff --git a/bashline.c b/bashline.c
Petr Šabata 33fc6c
index 75e79f1a..824ea9d9 100644
Petr Šabata 33fc6c
--- a/bashline.c
Petr Šabata 33fc6c
+++ b/bashline.c
Petr Šabata 33fc6c
@@ -3752,7 +3752,7 @@ completion_glob_pattern (string)
Petr Šabata 33fc6c
 	  continue;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 	case '\\':
Petr Šabata 33fc6c
-	  if (*string == 0)
Petr Šabata 33fc6c
+	  if (*string++ == 0)
Petr Šabata 33fc6c
 	    return (0);	 	  
Petr Šabata 33fc6c
 	}
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
diff --git a/lib/glob/glob.c b/lib/glob/glob.c
Petr Šabata 33fc6c
index 22d90a5c..398253b5 100644
Petr Šabata 33fc6c
--- a/lib/glob/glob.c
Petr Šabata 33fc6c
+++ b/lib/glob/glob.c
Petr Šabata 33fc6c
@@ -1061,7 +1061,7 @@ glob_filename (pathname, flags)
Petr Šabata 33fc6c
   char *directory_name, *filename, *dname, *fn;
Petr Šabata 33fc6c
   unsigned int directory_len;
Petr Šabata 33fc6c
   int free_dirname;			/* flag */
Petr Šabata 33fc6c
-  int dflags;
Petr Šabata 33fc6c
+  int dflags, hasglob;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
   result = (char **) malloc (sizeof (char *));
Petr Šabata 33fc6c
   result_size = 1;
Petr Šabata 33fc6c
@@ -1110,9 +1110,12 @@ glob_filename (pathname, flags)
Petr Šabata 33fc6c
       free_dirname = 1;
Petr Šabata 33fc6c
     }
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
+  hasglob = 0;
Petr Šabata 33fc6c
   /* If directory_name contains globbing characters, then we
Petr Šabata 33fc6c
-     have to expand the previous levels.  Just recurse. */
Petr Šabata 33fc6c
-  if (directory_len > 0 && glob_pattern_p (directory_name))
Petr Šabata 33fc6c
+     have to expand the previous levels.  Just recurse.
Petr Šabata 33fc6c
+     If glob_pattern_p returns != [0,1] we have a pattern that has backslash
Petr Šabata 33fc6c
+     quotes but no unquoted glob pattern characters. We dequote it below. */
Petr Šabata 33fc6c
+  if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1)
Petr Šabata 33fc6c
     {
Petr Šabata 33fc6c
       char **directories, *d, *p;
Petr Šabata 33fc6c
       register unsigned int i;
Petr Šabata 33fc6c
@@ -1175,7 +1178,7 @@ glob_filename (pathname, flags)
Petr Šabata 33fc6c
       if (d[directory_len - 1] == '/')
Petr Šabata 33fc6c
 	d[directory_len - 1] = '\0';
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
-      directories = glob_filename (d, dflags);
Petr Šabata 33fc6c
+      directories = glob_filename (d, dflags|GX_RECURSE);
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
       if (free_dirname)
Petr Šabata 33fc6c
 	{
Petr Šabata 33fc6c
@@ -1332,6 +1335,20 @@ only_filename:
Petr Šabata 33fc6c
 	    free (directory_name);
Petr Šabata 33fc6c
 	  return (NULL);
Petr Šabata 33fc6c
 	}
Petr Šabata 33fc6c
+      /* If we have a directory name with quoted characters, and we are
Petr Šabata 33fc6c
+	 being called recursively to glob the directory portion of a pathname,
Petr Šabata 33fc6c
+	 we need to dequote the directory name before returning it so the
Petr Šabata 33fc6c
+	 caller can read the directory */
Petr Šabata 33fc6c
+      if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) != 0)
Petr Šabata 33fc6c
+	{
Petr Šabata 33fc6c
+	  dequote_pathname (directory_name);
Petr Šabata 33fc6c
+	  directory_len = strlen (directory_name);
Petr Šabata 33fc6c
+	}
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
+      /* We could check whether or not the dequoted directory_name is a
Petr Šabata 33fc6c
+	 directory and return it here, returning the original directory_name
Petr Šabata 33fc6c
+	 if not, but we don't do that yet. I'm not sure it matters. */
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
       /* Handle GX_MARKDIRS here. */
Petr Šabata 33fc6c
       result[0] = (char *) malloc (directory_len + 1);
Petr Šabata 33fc6c
       if (result[0] == NULL)
Petr Šabata 33fc6c
diff --git a/lib/glob/glob.h b/lib/glob/glob.h
Petr Šabata 33fc6c
index b9462333..56ac08ba 100644
Petr Šabata 33fc6c
--- a/lib/glob/glob.h
Petr Šabata 33fc6c
+++ b/lib/glob/glob.h
Petr Šabata 33fc6c
@@ -30,6 +30,7 @@
Petr Šabata 33fc6c
 #define GX_NULLDIR	0x100	/* internal -- no directory preceding pattern */
Petr Šabata 33fc6c
 #define GX_ADDCURDIR	0x200	/* internal -- add passed directory name */
Petr Šabata 33fc6c
 #define GX_GLOBSTAR	0x400	/* turn on special handling of ** */
Petr Šabata 33fc6c
+#define GX_RECURSE	0x800	/* internal -- glob_filename called recursively */
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 extern int glob_pattern_p __P((const char *));
Petr Šabata 33fc6c
 extern char **glob_vector __P((char *, char *, int));
Petr Šabata 33fc6c
diff --git a/lib/glob/glob_loop.c b/lib/glob/glob_loop.c
Petr Šabata 33fc6c
index 7d6ae211..3a4f4f1e 100644
Petr Šabata 33fc6c
--- a/lib/glob/glob_loop.c
Petr Šabata 33fc6c
+++ b/lib/glob/glob_loop.c
Petr Šabata 33fc6c
@@ -26,10 +26,10 @@ INTERNAL_GLOB_PATTERN_P (pattern)
Petr Šabata 33fc6c
 {
Petr Šabata 33fc6c
   register const GCHAR *p;
Petr Šabata 33fc6c
   register GCHAR c;
Petr Šabata 33fc6c
-  int bopen;
Petr Šabata 33fc6c
+  int bopen, bsquote;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
   p = pattern;
Petr Šabata 33fc6c
-  bopen = 0;
Petr Šabata 33fc6c
+  bopen = bsquote = 0;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
   while ((c = *p++) != L('\0'))
Petr Šabata 33fc6c
     switch (c)
Petr Šabata 33fc6c
@@ -55,13 +55,22 @@ INTERNAL_GLOB_PATTERN_P (pattern)
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
       case L('\\'):
Petr Šabata 33fc6c
 	/* Don't let the pattern end in a backslash (GMATCH returns no match
Petr Šabata 33fc6c
-	   if the pattern ends in a backslash anyway), but otherwise return 1,
Petr Šabata 33fc6c
-	   since the matching engine uses backslash as an escape character
Petr Šabata 33fc6c
-	   and it can be removed. */
Petr Šabata 33fc6c
-	return (*p != L('\0'));
Petr Šabata 33fc6c
+	   if the pattern ends in a backslash anyway), but otherwise note that 
Petr Šabata 33fc6c
+	   we have seen this, since the matching engine uses backslash as an
Petr Šabata 33fc6c
+	   escape character and it can be removed. We return 2 later if we
Petr Šabata 33fc6c
+	   have seen only backslash-escaped characters, so interested callers
Petr Šabata 33fc6c
+	   know they can shortcut and just dequote the pathname. */
Petr Šabata 33fc6c
+	if (*p != L('\0'))
Petr Šabata 33fc6c
+	  {
Petr Šabata 33fc6c
+	    p++;
Petr Šabata 33fc6c
+	    bsquote = 1;
Petr Šabata 33fc6c
+	    continue;
Petr Šabata 33fc6c
+	  }
Petr Šabata 33fc6c
+	else 	/* (*p == L('\0')) */
Petr Šabata 33fc6c
+	  return 0;
Petr Šabata 33fc6c
       }
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
-  return 0;
Petr Šabata 33fc6c
+  return bsquote ? 2 : 0;
Petr Šabata 33fc6c
 }
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 #undef INTERNAL_GLOB_PATTERN_P
Petr Šabata 33fc6c
diff --git a/patchlevel.h b/patchlevel.h
Petr Šabata 33fc6c
index a988d852..e7e960c1 100644
Petr Šabata 33fc6c
--- a/patchlevel.h
Petr Šabata 33fc6c
+++ b/patchlevel.h
Petr Šabata 33fc6c
@@ -25,6 +25,6 @@
Petr Šabata 33fc6c
    regexp `^#define[ 	]*PATCHLEVEL', since that's what support/mkversion.sh
Petr Šabata 33fc6c
    looks for to find the patch level (for the sccs version string). */
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
-#define PATCHLEVEL 2
Petr Šabata 33fc6c
+#define PATCHLEVEL 3
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 #endif /* _PATCHLEVEL_H_ */
Petr Šabata 33fc6c
diff --git a/pathexp.c b/pathexp.c
Petr Šabata 33fc6c
index b51729a7..c1bf2d89 100644
Petr Šabata 33fc6c
--- a/pathexp.c
Petr Šabata 33fc6c
+++ b/pathexp.c
Petr Šabata 33fc6c
@@ -65,11 +65,11 @@ unquoted_glob_pattern_p (string)
Petr Šabata 33fc6c
 {
Petr Šabata 33fc6c
   register int c;
Petr Šabata 33fc6c
   char *send;
Petr Šabata 33fc6c
-  int open;
Petr Šabata 33fc6c
+  int open, bsquote;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
   DECLARE_MBSTATE;
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
-  open = 0;
Petr Šabata 33fc6c
+  open = bsquote = 0;
Petr Šabata 33fc6c
   send = string + strlen (string);
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
   while (c = *string++)
Petr Šabata 33fc6c
@@ -100,7 +100,14 @@ unquoted_glob_pattern_p (string)
Petr Šabata 33fc6c
 	   can be removed by the matching engine, so we have to run it through
Petr Šabata 33fc6c
 	   globbing. */
Petr Šabata 33fc6c
 	case '\\':
Petr Šabata 33fc6c
-	  return (*string != 0);
Petr Šabata 33fc6c
+	  if (*string != '\0' && *string != '/')
Petr Šabata 33fc6c
+	    {
Petr Šabata 33fc6c
+	      bsquote = 1;
Petr Šabata 33fc6c
+	      string++;
Petr Šabata 33fc6c
+	      continue;
Petr Šabata 33fc6c
+	    }
Petr Šabata 33fc6c
+	  else if (*string == 0)
Petr Šabata 33fc6c
+	    return (0);
Petr Šabata 33fc6c
 	 	  
Petr Šabata 33fc6c
 	case CTLESC:
Petr Šabata 33fc6c
 	  if (*string++ == '\0')
Petr Šabata 33fc6c
@@ -117,7 +124,8 @@ unquoted_glob_pattern_p (string)
Petr Šabata 33fc6c
       ADVANCE_CHAR_P (string, send - string);
Petr Šabata 33fc6c
 #endif
Petr Šabata 33fc6c
     }
Petr Šabata 33fc6c
-  return (0);
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
+  return (bsquote ? 2 : 0);
Petr Šabata 33fc6c
 }
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
Petr Šabata 33fc6c
-- 
Petr Šabata 33fc6c
2.17.2
Petr Šabata 33fc6c