@ -1784,7 +1784,10 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
@@ -1784,7 +1784,10 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
dir_state = state;
/* recurse into subdir if instructed by treat_path */
if (state == path_recurse) {
if ((state == path_recurse) ||
((state == path_untracked) &&
(dir->flags & DIR_SHOW_IGNORED_TOO) &&
(get_dtype(cdir.de, path.buf, path.len) == DT_DIR))) {
struct untracked_cache_dir *ud;
ud = lookup_untracked(dir->untracked, untracked,
path.buf + baselen,
@ -1839,7 +1842,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
@@ -1839,7 +1842,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
return dir_state;
}
static int cmp_name(const void *p1, const void *p2)
int cmp_dir_entry(const void *p1, const void *p2)
{
const struct dir_entry *e1 = *(const struct dir_entry **)p1;
const struct dir_entry *e2 = *(const struct dir_entry **)p2;
@ -1847,6 +1850,14 @@ static int cmp_name(const void *p1, const void *p2)
@@ -1847,6 +1850,14 @@ static int cmp_name(const void *p1, const void *p2)
return name_compare(e1->name, e1->len, e2->name, e2->len);
}
/* check if *out lexically strictly contains *in */
int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in)
{
return (out->len < in->len) &&
(out->name[out->len - 1] == '/') &&
!memcmp(out->name, in->name, out->len);
}
static int treat_leading_path(struct dir_struct *dir,
const char *path, int len,
const struct pathspec *pathspec)
@ -2060,8 +2071,32 @@ int read_directory(struct dir_struct *dir, const char *path,
@@ -2060,8 +2071,32 @@ int read_directory(struct dir_struct *dir, const char *path,
dir->untracked = NULL;
if (!len || treat_leading_path(dir, path, len, pathspec))
read_directory_recursive(dir, path, len, untracked, 0, pathspec);
QSORT(dir->entries, dir->nr, cmp_name);
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
QSORT(dir->entries, dir->nr, cmp_dir_entry);
QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
/*
* If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will
* also pick up untracked contents of untracked dirs; by default
* we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not.
*/
if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
!(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
int i, j;
/* remove from dir->entries untracked contents of untracked dirs */
for (i = j = 0; j < dir->nr; j++) {
if (i &&
check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {
free(dir->entries[j]);
dir->entries[j] = NULL;
} else {
dir->entries[i++] = dir->entries[j];
}
}
dir->nr = i;
}
if (dir->untracked) {
static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
trace_printf_key(&trace_untracked_stats,