@@ -758,13 +758,41 @@ static int add_excludes(const char *fname, const char *base, int baselen,
758
758
size_t size = 0 ;
759
759
char * buf , * entry ;
760
760
761
- if (is_fscache_enabled ()) {
761
+ /*
762
+ * A performance optimization for status.
763
+ *
764
+ * During a status scan, git looks in each directory for a .gitignore
765
+ * file before scanning the directory. Since .gitignore files are not
766
+ * that common, we can waste a lot of time looking for files that are
767
+ * not there. Fortunately, the fscache already knows if the directory
768
+ * contains a .gitignore file, since it has already read the directory
769
+ * and it already has the stat-data.
770
+ *
771
+ * If the fscache is enabled, use the fscache-lstat() interlude to see
772
+ * if the file exists (in the fscache hash maps) before trying to open()
773
+ * it.
774
+ *
775
+ * This causes problem when the .gitignore file is a symlink, because
776
+ * we call lstat() rather than stat() on the symlnk and the resulting
777
+ * stat-data is for the symlink itself rather than the target file.
778
+ * We CANNOT use stat() here because the fscache DOES NOT install an
779
+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
780
+ * on the file and defeats the purpose of the optimization here. Since
781
+ * symlinks are even more rare than .gitignore files, we force a fstat()
782
+ * after our open() to get stat-data for the target file.
783
+ */
784
+ if (is_fscache_enabled (fname )) {
762
785
if (lstat (fname , & st ) < 0 ) {
763
786
fd = -1 ;
764
787
} else {
765
788
fd = open (fname , O_RDONLY );
766
789
if (fd < 0 )
767
790
warn_on_fopen_errors (fname );
791
+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
792
+ warn_on_fopen_errors (fname );
793
+ close (fd );
794
+ fd = -1 ;
795
+ }
768
796
}
769
797
} else {
770
798
fd = open (fname , O_RDONLY );
0 commit comments