@@ -824,12 +824,55 @@ static int add_excludes(const char *fname, const char *base, int baselen,
824
824
size_t size = 0 ;
825
825
char * buf ;
826
826
827
- fd = open (fname , O_RDONLY );
828
- if (fd < 0 || fstat (fd , & st ) < 0 ) {
829
- if (fd < 0 )
830
- warn_on_fopen_errors (fname );
831
- else
832
- close (fd );
827
+ /*
828
+ * A performance optimization for status.
829
+ *
830
+ * During a status scan, git looks in each directory for a .gitignore
831
+ * file before scanning the directory. Since .gitignore files are not
832
+ * that common, we can waste a lot of time looking for files that are
833
+ * not there. Fortunately, the fscache already knows if the directory
834
+ * contains a .gitignore file, since it has already read the directory
835
+ * and it already has the stat-data.
836
+ *
837
+ * If the fscache is enabled, use the fscache-lstat() interlude to see
838
+ * if the file exists (in the fscache hash maps) before trying to open()
839
+ * it.
840
+ *
841
+ * This causes problem when the .gitignore file is a symlink, because
842
+ * we call lstat() rather than stat() on the symlnk and the resulting
843
+ * stat-data is for the symlink itself rather than the target file.
844
+ * We CANNOT use stat() here because the fscache DOES NOT install an
845
+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
846
+ * on the file and defeats the purpose of the optimization here. Since
847
+ * symlinks are even more rare than .gitignore files, we force a fstat()
848
+ * after our open() to get stat-data for the target file.
849
+ */
850
+ if (is_fscache_enabled (fname )) {
851
+ if (lstat (fname , & st ) < 0 ) {
852
+ fd = -1 ;
853
+ } else {
854
+ fd = open (fname , O_RDONLY );
855
+ if (fd < 0 )
856
+ warn_on_fopen_errors (fname );
857
+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
858
+ warn_on_fopen_errors (fname );
859
+ close (fd );
860
+ fd = -1 ;
861
+ }
862
+ }
863
+ } else {
864
+ fd = open (fname , O_RDONLY );
865
+ if (fd < 0 || fstat (fd , & st ) < 0 ) {
866
+ if (fd < 0 )
867
+ warn_on_fopen_errors (fname );
868
+ else {
869
+ close (fd );
870
+ fd = -1 ;
871
+ }
872
+ }
873
+ }
874
+
875
+ if (fd < 0 ) {
833
876
if (!istate )
834
877
return -1 ;
835
878
r = read_skip_worktree_file_from_index (istate , fname ,
0 commit comments