int matchlen;
 
        /* If the match was just the prefix, we matched */
-       matchlen = strlen(match);
-       if (!matchlen)
+       if (!*match)
                return MATCHED_RECURSIVELY;
 
+       for (;;) {
+               unsigned char c1 = *match;
+               unsigned char c2 = *name;
+               if (isspecial(c1))
+                       break;
+               if (c1 != c2)
+                       return 0;
+               match++;
+               name++;
+               namelen--;
+       }
+
+
        /*
         * If we don't match the matchstring exactly,
         * we need to match by fnmatch
         */
+       matchlen = strlen(match);
        if (strncmp(match, name, matchlen))
                return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;
 
-       if (!name[matchlen])
+       if (namelen == matchlen)
                return MATCHED_EXACTLY;
        if (match[matchlen-1] == '/' || name[matchlen] == '/')
                return MATCHED_RECURSIVELY;
  */
 static int simple_length(const char *match)
 {
-       const char special[256] = {
-               [0] = 1, ['?'] = 1,
-               ['\\'] = 1, ['*'] = 1,
-               ['['] = 1
-       };
        int len = -1;
 
        for (;;) {
                unsigned char c = *match++;
                len++;
-               if (special[c])
+               if (isspecial(c))
                        return len;
        }
 }
 
 int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
 {
-       struct path_simplify *simplify = create_simplify(pathspec);
+       struct path_simplify *simplify;
+
+       if (has_symlink_leading_path(strlen(path), path))
+               return dir->nr;
 
+       simplify = create_simplify(pathspec);
        read_directory_recursive(dir, path, base, baselen, 0, simplify);
        free_simplify(simplify);
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);