static int read_directory_recursive(struct dir_struct *dir,
const char *path, const char *base, int baselen,
int check_only, const struct path_simplify *simplify);
+static int get_dtype(struct dirent *de, const char *path);
int common_prefix(const char **pathspec)
{
return prefix;
}
+static inline int special_char(unsigned char c1)
+{
+ return !c1 || c1 == '*' || c1 == '[' || c1 == '?';
+}
+
/*
* Does 'match' matches the given name?
* A match is found if
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 (special_char(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;
* Return 1 for exclude, 0 for include and -1 for undecided.
*/
static int excluded_1(const char *pathname,
- int pathlen, const char *basename, int dtype,
+ int pathlen, const char *basename, int *dtype,
struct exclude_list *el)
{
int i;
const char *exclude = x->pattern;
int to_exclude = x->to_exclude;
- if ((x->flags & EXC_FLAG_MUSTBEDIR) &&
- (dtype != DT_DIR))
- continue;
+ if (x->flags & EXC_FLAG_MUSTBEDIR) {
+ if (*dtype == DT_UNKNOWN)
+ *dtype = get_dtype(NULL, pathname);
+ if (*dtype != DT_DIR)
+ continue;
+ }
if (x->flags & EXC_FLAG_NODIR) {
/* match basename */
return -1; /* undecided */
}
-int excluded(struct dir_struct *dir, const char *pathname, int dtype)
+int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
{
int pathlen = strlen(pathname);
int st;
prep_exclude(dir, pathname, basename-pathname);
for (st = EXC_CMDL; st <= EXC_FILE; st++) {
switch (excluded_1(pathname, pathlen, basename,
- dtype, &dir->exclude_list[st])) {
+ dtype_p, &dir->exclude_list[st])) {
case 0:
return 0;
case 1:
struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
{
- if (cache_name_pos(pathname, len) >= 0)
+ if (cache_name_exists(pathname, len, ignore_case))
return NULL;
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
break;
if (endchar == '/')
return index_directory;
- if (!endchar && S_ISGITLINK(ntohl(ce->ce_mode)))
+ if (!endchar && S_ISGITLINK(ce->ce_mode))
return index_gitdir;
}
return index_nonexistent;
static int get_dtype(struct dirent *de, const char *path)
{
- int dtype = DTYPE(de);
+ int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;
if (dtype != DT_UNKNOWN)
if (simplify_away(fullname, baselen + len, simplify))
continue;
- dtype = get_dtype(de, fullname);
- exclude = excluded(dir, fullname, dtype);
+ dtype = DTYPE(de);
+ exclude = excluded(dir, fullname, &dtype);
if (exclude && dir->collect_ignored
&& in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len);
if (exclude && !dir->show_ignored)
continue;
+ if (dtype == DT_UNKNOWN)
+ dtype = get_dtype(de, fullname);
+
/*
* Do we want to see just the ignored files?
* We still need to recurse into directories,
static void free_simplify(struct path_simplify *simplify)
{
- if (simplify)
- free(simplify);
+ free(simplify);
}
int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)