d83721
diff -up vsftpd-3.0.2/ls.c.sqb vsftpd-3.0.2/ls.c
d83721
--- vsftpd-3.0.2/ls.c.sqb	2014-07-04 13:41:16.421185690 +0200
d83721
+++ vsftpd-3.0.2/ls.c	2014-07-04 13:52:35.920369390 +0200
d83721
@@ -246,7 +246,7 @@ vsf_filename_passes_filter(const struct
d83721
   int ret = 0;
d83721
   char last_token = 0;
d83721
   int must_match_at_current_pos = 1;
d83721
-  
d83721
+  int matched = 0;
d83721
   
d83721
   str_copy(&filter_remain_str, p_filter_str);
d83721
   
d83721
@@ -276,7 +276,7 @@ vsf_filename_passes_filter(const struct
d83721
     static struct mystr s_match_needed_str;
d83721
     /* Locate next special token */
d83721
     struct str_locate_result locate_result =
d83721
-      str_locate_chars(&filter_remain_str, "*?{");
d83721
+      str_locate_chars(&filter_remain_str, "*?{[");
d83721
     (*iters)++;
d83721
     /* Isolate text leading up to token (if any) - needs to be matched */
d83721
     if (locate_result.found)
d83721
@@ -294,94 +294,172 @@ vsf_filename_passes_filter(const struct
d83721
       str_empty(&filter_remain_str);
d83721
       last_token = 0;
d83721
     }
d83721
-    if (!str_isempty(&s_match_needed_str))
d83721
-    {
d83721
-      /* Need to match something.. could be a match which has to start at
d83721
-       * current position, or we could allow it to start anywhere
d83721
-       */
d83721
-      unsigned int indexx;
d83721
-      locate_result = str_locate_str(&name_remain_str, &s_match_needed_str);
d83721
-      if (!locate_result.found)
d83721
+
d83721
+    matched = 0;
d83721
+    do {
d83721
+      if (!str_isempty(&s_match_needed_str))
d83721
       {
d83721
-        /* Fail */
d83721
-        goto out;
d83721
+        if (!matched)
d83721
+        {
d83721
+          matched = 1;
d83721
+        }
d83721
+        /* Need to match something.. could be a match which has to start at
d83721
+         * current position, or we could allow it to start anywhere
d83721
+         */
d83721
+        unsigned int indexx;
d83721
+        locate_result = str_locate_str(&name_remain_str, &s_match_needed_str);
d83721
+        if (!locate_result.found)
d83721
+        {
d83721
+          /* Fail */
d83721
+          goto out;
d83721
+        }
d83721
+        indexx = locate_result.index;
d83721
+        if (must_match_at_current_pos && indexx > 0)
d83721
+        {
d83721
+          goto out;
d83721
+        }
d83721
+        if (!must_match_at_current_pos && last_token == 0)
d83721
+        {
d83721
+          struct mystr last_str = INIT_MYSTR;
d83721
+          str_mid_to_end(&name_remain_str, &last_str,
d83721
+            str_getlen(&name_remain_str) - str_getlen(&s_match_needed_str));
d83721
+          locate_result = str_locate_str(&last_str, &s_match_needed_str);
d83721
+          str_free(&last_str);
d83721
+
d83721
+          if (locate_result.found)
d83721
+          {
d83721
+            ret = 1;
d83721
+          }
d83721
+          goto out;
d83721
+        }
d83721
+        /* Chop matched string out of remainder */
d83721
+        str_mid_to_end(&name_remain_str, &temp_str,
d83721
+                       indexx + str_getlen(&s_match_needed_str));
d83721
+        str_copy(&name_remain_str, &temp_str);
d83721
       }
d83721
-      indexx = locate_result.index;
d83721
-      if (must_match_at_current_pos && indexx > 0)
d83721
+      if (last_token == '?')
d83721
       {
d83721
-        goto out;
d83721
+        if (str_isempty(&name_remain_str))
d83721
+        {
d83721
+          goto out;
d83721
+        }
d83721
+        str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1);
d83721
+        str_copy(&name_remain_str, &temp_str);
d83721
+        must_match_at_current_pos = 1;
d83721
       }
d83721
-      if (!must_match_at_current_pos && last_token == 0)
d83721
+      else if (last_token == '{')
d83721
       {
d83721
-        struct mystr last_str = INIT_MYSTR;
d83721
-        str_mid_to_end(&name_remain_str, &last_str,
d83721
-          str_getlen(&name_remain_str) - str_getlen(&s_match_needed_str));
d83721
-        locate_result = str_locate_str(&last_str, &s_match_needed_str);
d83721
-        str_free(&last_str);
d83721
+        struct str_locate_result end_brace =
d83721
+          str_locate_char(&filter_remain_str, '}');
d83721
+        must_match_at_current_pos = 1;
d83721
+        if (end_brace.found)
d83721
+        {
d83721
+          int entire = (*iters == 1 && last_token == '{');
d83721
 
d83721
-        if (locate_result.found)
d83721
+          str_split_char(&filter_remain_str, &temp_str, '}');
d83721
+          str_copy(&brace_list_str, &filter_remain_str);
d83721
+          str_copy(&filter_remain_str, &temp_str);
d83721
+          str_split_char(&brace_list_str, &temp_str, ',');
d83721
+          while (!str_isempty(&brace_list_str))
d83721
+          {
d83721
+            str_empty(&new_filter_str);
d83721
+            if (!matched && !entire)
d83721
+            {
d83721
+              str_append_char(&new_filter_str, '*');
d83721
+            }
d83721
+            str_append_str(&new_filter_str, &brace_list_str);
d83721
+            str_append_str(&new_filter_str, &filter_remain_str);
d83721
+            if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str,
d83721
+                                           iters))
d83721
+            {
d83721
+              ret = 1;
d83721
+              goto out;
d83721
+            }
d83721
+            str_copy(&brace_list_str, &temp_str);
d83721
+            str_split_char(&brace_list_str, &temp_str, ',');
d83721
+          }
d83721
+          goto out;
d83721
+        }
d83721
+        else if (str_isempty(&name_remain_str) ||
d83721
+                 str_get_char_at(&name_remain_str, 0) != '{')
d83721
         {
d83721
-          ret = 1;
d83721
+          goto out;
d83721
+        }
d83721
+        else
d83721
+        {
d83721
+          str_right(&name_remain_str, &temp_str,
d83721
+                    str_getlen(&name_remain_str) - 1);
d83721
+          str_copy(&name_remain_str, &temp_str);
d83721
         }
d83721
-        goto out;
d83721
-      }
d83721
-      /* Chop matched string out of remainder */
d83721
-      str_mid_to_end(&name_remain_str, &temp_str,
d83721
-                     indexx + str_getlen(&s_match_needed_str));
d83721
-      str_copy(&name_remain_str, &temp_str);
d83721
-    }
d83721
-    if (last_token == '?')
d83721
-    {
d83721
-      if (str_isempty(&name_remain_str))
d83721
-      {
d83721
-        goto out;
d83721
       }
d83721
-      str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1);
d83721
-      str_copy(&name_remain_str, &temp_str);
d83721
-      must_match_at_current_pos = 1;
d83721
-    }
d83721
-    else if (last_token == '{')
d83721
-    {
d83721
-      struct str_locate_result end_brace =
d83721
-        str_locate_char(&filter_remain_str, '}');
d83721
-      must_match_at_current_pos = 1;
d83721
-      if (end_brace.found)
d83721
+      else if (last_token == '[')
d83721
       {
d83721
-        str_split_char(&filter_remain_str, &temp_str, '}');
d83721
-        str_copy(&brace_list_str, &filter_remain_str);
d83721
-        str_copy(&filter_remain_str, &temp_str);
d83721
-        str_split_char(&brace_list_str, &temp_str, ',');
d83721
-        while (!str_isempty(&brace_list_str))
d83721
-        {
d83721
-          str_copy(&new_filter_str, &brace_list_str);
d83721
-          str_append_str(&new_filter_str, &filter_remain_str);
d83721
-          if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str,
d83721
-                                         iters))
d83721
+        struct str_locate_result end_sqb =
d83721
+          str_locate_char(&filter_remain_str, ']');
d83721
+        must_match_at_current_pos = 1;
d83721
+        if (end_sqb.found)
d83721
+        {
d83721
+          unsigned int cur_pos;
d83721
+          char stch, ench;
d83721
+          const char *p_brace;
d83721
+
d83721
+          str_split_char(&filter_remain_str, &temp_str, ']');
d83721
+          str_copy(&brace_list_str, &filter_remain_str);
d83721
+          str_copy(&filter_remain_str, &temp_str);
d83721
+          p_brace = str_getbuf(&brace_list_str);
d83721
+          for (cur_pos = 0; cur_pos < str_getlen(&brace_list_str);)
d83721
           {
d83721
-            ret = 1;
d83721
-            goto out;
d83721
+            stch = p_brace[cur_pos];
d83721
+            // char vers. range
d83721
+            if (cur_pos + 2 < str_getlen(&brace_list_str) &&
d83721
+                p_brace[cur_pos+1] == '-')
d83721
+            {
d83721
+              ench = p_brace[cur_pos+2];
d83721
+              cur_pos += 3;
d83721
+            }
d83721
+            else
d83721
+            {
d83721
+              ench = stch;
d83721
+              cur_pos++;
d83721
+            }
d83721
+            // expand char[s]
d83721
+            for (;stch <= ench && !str_isempty(&brace_list_str); stch++)
d83721
+            {
d83721
+              str_empty(&new_filter_str);
d83721
+              if (!matched)
d83721
+              {
d83721
+                str_append_char(&new_filter_str, '*');
d83721
+              }
d83721
+              str_append_char(&new_filter_str, stch);
d83721
+              str_append_str(&new_filter_str, &filter_remain_str);
d83721
+              if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str,
d83721
+                                             iters))
d83721
+              {
d83721
+                ret = 1;
d83721
+                goto out;
d83721
+              }
d83721
+            }
d83721
           }
d83721
-          str_copy(&brace_list_str, &temp_str);
d83721
-          str_split_char(&brace_list_str, &temp_str, ',');
d83721
+          goto out;
d83721
+        }
d83721
+        else if (str_isempty(&name_remain_str) ||
d83721
+                 str_get_char_at(&name_remain_str, 0) != '[')
d83721
+        {
d83721
+          goto out;
d83721
+        }
d83721
+        else
d83721
+        {
d83721
+          str_right(&name_remain_str, &temp_str,
d83721
+                    str_getlen(&name_remain_str) - 1);
d83721
+          str_copy(&name_remain_str, &temp_str);
d83721
         }
d83721
-        goto out;
d83721
-      }
d83721
-      else if (str_isempty(&name_remain_str) ||
d83721
-               str_get_char_at(&name_remain_str, 0) != '{')
d83721
-      {
d83721
-        goto out;
d83721
       }
d83721
       else
d83721
       {
d83721
-        str_right(&name_remain_str, &temp_str,
d83721
-                  str_getlen(&name_remain_str) - 1);
d83721
-        str_copy(&name_remain_str, &temp_str);
d83721
+        must_match_at_current_pos = 0;
d83721
       }
d83721
-    }
d83721
-    else
d83721
-    {
d83721
-      must_match_at_current_pos = 0;
d83721
-    }
d83721
+    } while (locate_result.found &&
d83721
+             str_getlen(&name_remain_str) > 0 && last_token != '*');
d83721
   }
d83721
   /* Any incoming string left means no match unless we ended on the correct
d83721
    * type of wildcard.