Skip to content

Commit 0713442

Browse files
torvaldsspearce
authored andcommitted
Fix directory scanner to correctly ignore files without d_type
On Fri, 19 Oct 2007, Todd T. Fries wrote: > If DT_UNKNOWN exists, then we have to do a stat() of some form to > find out the right type. That happened in the case of a pathname that was ignored, and we did not ask for "dir->show_ignored". That test used to be *together* with the "DTYPE(de) != DT_DIR", but splitting the two tests up means that we can do that (common) test before we even bother to calculate the real dtype. Of course, that optimization only matters for systems that don't have, or don't fill in DTYPE properly. I also clarified the real relationship between "exclude" and "dir->show_ignored". It used to do if (exclude != dir->show_ignored) { .. which wasn't exactly obvious, because it triggers for two different cases: - the path is marked excluded, but we are not interested in ignored files: ignore it - the path is *not* excluded, but we *are* interested in ignored files: ignore it unless it's a directory, in which case we might have ignored files inside the directory and need to recurse into it). so this splits them into those two cases, since the first case doesn't even care about the type. I also made a the DT_UNKNOWN case a separate helper function, and added some commentary to the cases. Linus Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 parent 7468c29 commit 0713442

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

dir.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,24 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
443443
return 0;
444444
}
445445

446+
static int get_dtype(struct dirent *de, const char *path)
447+
{
448+
int dtype = DTYPE(de);
449+
struct stat st;
450+
451+
if (dtype != DT_UNKNOWN)
452+
return dtype;
453+
if (lstat(path, &st))
454+
return dtype;
455+
if (S_ISREG(st.st_mode))
456+
return DT_REG;
457+
if (S_ISDIR(st.st_mode))
458+
return DT_DIR;
459+
if (S_ISLNK(st.st_mode))
460+
return DT_LNK;
461+
return dtype;
462+
}
463+
446464
/*
447465
* Read a directory tree. We currently ignore anything but
448466
* directories, regular files and symlinks. That's because git
@@ -466,7 +484,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
466484
exclude_stk = push_exclude_per_directory(dir, base, baselen);
467485

468486
while ((de = readdir(fdir)) != NULL) {
469-
int len;
487+
int len, dtype;
470488
int exclude;
471489

472490
if ((de->d_name[0] == '.') &&
@@ -486,24 +504,30 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
486504
if (exclude && dir->collect_ignored
487505
&& in_pathspec(fullname, baselen + len, simplify))
488506
dir_add_ignored(dir, fullname, baselen + len);
489-
if (exclude != dir->show_ignored) {
490-
if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
507+
508+
/*
509+
* Excluded? If we don't explicitly want to show
510+
* ignored files, ignore it
511+
*/
512+
if (exclude && !dir->show_ignored)
513+
continue;
514+
515+
dtype = get_dtype(de, fullname);
516+
517+
/*
518+
* Do we want to see just the ignored files?
519+
* We still need to recurse into directories,
520+
* even if we don't ignore them, since the
521+
* directory may contain files that we do..
522+
*/
523+
if (!exclude && dir->show_ignored) {
524+
if (dtype != DT_DIR)
491525
continue;
492-
}
493526
}
494527

495-
switch (DTYPE(de)) {
496-
struct stat st;
528+
switch (dtype) {
497529
default:
498530
continue;
499-
case DT_UNKNOWN:
500-
if (lstat(fullname, &st))
501-
continue;
502-
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
503-
break;
504-
if (!S_ISDIR(st.st_mode))
505-
continue;
506-
/* fallthrough */
507531
case DT_DIR:
508532
memcpy(fullname + baselen + len, "/", 2);
509533
len++;

0 commit comments

Comments
 (0)