@@ -805,13 +805,41 @@ static int add_excludes(const char *fname, const char *base, int baselen,
805
805
size_t size = 0 ;
806
806
char * buf ;
807
807
808
- if (is_fscache_enabled ()) {
808
+ /*
809
+ * A performance optimization for status.
810
+ *
811
+ * During a status scan, git looks in each directory for a .gitignore
812
+ * file before scanning the directory. Since .gitignore files are not
813
+ * that common, we can waste a lot of time looking for files that are
814
+ * not there. Fortunately, the fscache already knows if the directory
815
+ * contains a .gitignore file, since it has already read the directory
816
+ * and it already has the stat-data.
817
+ *
818
+ * If the fscache is enabled, use the fscache-lstat() interlude to see
819
+ * if the file exists (in the fscache hash maps) before trying to open()
820
+ * it.
821
+ *
822
+ * This causes problem when the .gitignore file is a symlink, because
823
+ * we call lstat() rather than stat() on the symlnk and the resulting
824
+ * stat-data is for the symlink itself rather than the target file.
825
+ * We CANNOT use stat() here because the fscache DOES NOT install an
826
+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
827
+ * on the file and defeats the purpose of the optimization here. Since
828
+ * symlinks are even more rare than .gitignore files, we force a fstat()
829
+ * after our open() to get stat-data for the target file.
830
+ */
831
+ if (is_fscache_enabled (fname )) {
809
832
if (lstat (fname , & st ) < 0 ) {
810
833
fd = -1 ;
811
834
} else {
812
835
fd = open (fname , O_RDONLY );
813
836
if (fd < 0 )
814
837
warn_on_fopen_errors (fname );
838
+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
839
+ warn_on_fopen_errors (fname );
840
+ close (fd );
841
+ fd = -1 ;
842
+ }
815
843
}
816
844
} else {
817
845
fd = open (fname , O_RDONLY );
0 commit comments