]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
Bash-5.0 patch 3: improvements when globbing directory names containing backslashes
authorChet Ramey <chet.ramey@case.edu>
Tue, 19 Mar 2019 14:05:39 +0000 (10:05 -0400)
committerChet Ramey <chet.ramey@case.edu>
Tue, 19 Mar 2019 14:05:39 +0000 (10:05 -0400)
bashline.c
lib/glob/glob.c
lib/glob/glob.h
lib/glob/glob_loop.c
patchlevel.h
pathexp.c

index 75e79f1ab81a643350c211799ebc2cf76b27a0d0..824ea9d93996cacfecd7a99e9b2e57e5c90a47d1 100644 (file)
@@ -3752,7 +3752,7 @@ completion_glob_pattern (string)
          continue;
 
        case '\\':
-         if (*string == 0)
+         if (*string++ == 0)
            return (0);           
        }
 
index 22d90a5cdf9c6c579ac2c8c1f7b111e8d932d58c..398253b543fc37ae433749c0e2971360b138a818 100644 (file)
@@ -1061,7 +1061,7 @@ glob_filename (pathname, flags)
   char *directory_name, *filename, *dname, *fn;
   unsigned int directory_len;
   int free_dirname;                    /* flag */
-  int dflags;
+  int dflags, hasglob;
 
   result = (char **) malloc (sizeof (char *));
   result_size = 1;
@@ -1110,9 +1110,12 @@ glob_filename (pathname, flags)
       free_dirname = 1;
     }
 
+  hasglob = 0;
   /* If directory_name contains globbing characters, then we
-     have to expand the previous levels.  Just recurse. */
-  if (directory_len > 0 && glob_pattern_p (directory_name))
+     have to expand the previous levels.  Just recurse.
+     If glob_pattern_p returns != [0,1] we have a pattern that has backslash
+     quotes but no unquoted glob pattern characters. We dequote it below. */
+  if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1)
     {
       char **directories, *d, *p;
       register unsigned int i;
@@ -1175,7 +1178,7 @@ glob_filename (pathname, flags)
       if (d[directory_len - 1] == '/')
        d[directory_len - 1] = '\0';
 
-      directories = glob_filename (d, dflags);
+      directories = glob_filename (d, dflags|GX_RECURSE);
 
       if (free_dirname)
        {
@@ -1332,6 +1335,20 @@ only_filename:
            free (directory_name);
          return (NULL);
        }
+      /* If we have a directory name with quoted characters, and we are
+        being called recursively to glob the directory portion of a pathname,
+        we need to dequote the directory name before returning it so the
+        caller can read the directory */
+      if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) != 0)
+       {
+         dequote_pathname (directory_name);
+         directory_len = strlen (directory_name);
+       }
+
+      /* We could check whether or not the dequoted directory_name is a
+        directory and return it here, returning the original directory_name
+        if not, but we don't do that yet. I'm not sure it matters. */
+
       /* Handle GX_MARKDIRS here. */
       result[0] = (char *) malloc (directory_len + 1);
       if (result[0] == NULL)
index b94623336438b74b679076ef772b0dbcff75d7c8..56ac08ba6c26216941f7248b2c371ed8e4441175 100644 (file)
@@ -30,6 +30,7 @@
 #define GX_NULLDIR     0x100   /* internal -- no directory preceding pattern */
 #define GX_ADDCURDIR   0x200   /* internal -- add passed directory name */
 #define GX_GLOBSTAR    0x400   /* turn on special handling of ** */
+#define GX_RECURSE     0x800   /* internal -- glob_filename called recursively */
 
 extern int glob_pattern_p __P((const char *));
 extern char **glob_vector __P((char *, char *, int));
index 7d6ae2113c509ec64a9087b03ce4c04e67b217b9..3a4f4f1e86efec638c07d4f2471b9bf514897123 100644 (file)
@@ -26,10 +26,10 @@ INTERNAL_GLOB_PATTERN_P (pattern)
 {
   register const GCHAR *p;
   register GCHAR c;
-  int bopen;
+  int bopen, bsquote;
 
   p = pattern;
-  bopen = 0;
+  bopen = bsquote = 0;
 
   while ((c = *p++) != L('\0'))
     switch (c)
@@ -55,13 +55,22 @@ INTERNAL_GLOB_PATTERN_P (pattern)
 
       case L('\\'):
        /* Don't let the pattern end in a backslash (GMATCH returns no match
-          if the pattern ends in a backslash anyway), but otherwise return 1,
-          since the matching engine uses backslash as an escape character
-          and it can be removed. */
-       return (*p != L('\0'));
+          if the pattern ends in a backslash anyway), but otherwise note that 
+          we have seen this, since the matching engine uses backslash as an
+          escape character and it can be removed. We return 2 later if we
+          have seen only backslash-escaped characters, so interested callers
+          know they can shortcut and just dequote the pathname. */
+       if (*p != L('\0'))
+         {
+           p++;
+           bsquote = 1;
+           continue;
+         }
+       else    /* (*p == L('\0')) */
+         return 0;
       }
 
-  return 0;
+  return bsquote ? 2 : 0;
 }
 
 #undef INTERNAL_GLOB_PATTERN_P
index a988d852644985230969d343fdc0c88a3626f7a4..e7e960c1a28cc30fc0a3fa8257bb326b4140442c 100644 (file)
@@ -25,6 +25,6 @@
    regexp `^#define[   ]*PATCHLEVEL', since that's what support/mkversion.sh
    looks for to find the patch level (for the sccs version string). */
 
-#define PATCHLEVEL 2
+#define PATCHLEVEL 3
 
 #endif /* _PATCHLEVEL_H_ */
index b51729a7bd5683e43ed6450a658c462c9c9f3134..c1bf2d89b98d009467c6be8796325a3976317f57 100644 (file)
--- a/pathexp.c
+++ b/pathexp.c
@@ -65,11 +65,11 @@ unquoted_glob_pattern_p (string)
 {
   register int c;
   char *send;
-  int open;
+  int open, bsquote;
 
   DECLARE_MBSTATE;
 
-  open = 0;
+  open = bsquote = 0;
   send = string + strlen (string);
 
   while (c = *string++)
@@ -100,7 +100,14 @@ unquoted_glob_pattern_p (string)
           can be removed by the matching engine, so we have to run it through
           globbing. */
        case '\\':
-         return (*string != 0);
+         if (*string != '\0' && *string != '/')
+           {
+             bsquote = 1;
+             string++;
+             continue;
+           }
+         else if (*string == 0)
+           return (0);
                  
        case CTLESC:
          if (*string++ == '\0')
@@ -117,7 +124,8 @@ unquoted_glob_pattern_p (string)
       ADVANCE_CHAR_P (string, send - string);
 #endif
     }
-  return (0);
+
+  return (bsquote ? 2 : 0);
 }
 
 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to