@@ -895,6 +895,34 @@ static int has_file_name(struct index_state *istate,
895
895
return retval ;
896
896
}
897
897
898
+ /*
899
+ * Like strcmp(), but also return the offset of the first change.
900
+ */
901
+ int strcmp_offset (const char * s1_in , const char * s2_in , int * first_change )
902
+ {
903
+ const unsigned char * s1 = (const unsigned char * )s1_in ;
904
+ const unsigned char * s2 = (const unsigned char * )s2_in ;
905
+ int diff = 0 ;
906
+ int k ;
907
+
908
+ * first_change = 0 ;
909
+ for (k = 0 ; s1 [k ]; k ++ )
910
+ if ((diff = (s1 [k ] - s2 [k ])))
911
+ goto found_it ;
912
+ if (!s2 [k ])
913
+ return 0 ;
914
+ diff = -1 ;
915
+
916
+ found_it :
917
+ * first_change = k ;
918
+ if (diff > 0 )
919
+ return 1 ;
920
+ else if (diff < 0 )
921
+ return -1 ;
922
+ else
923
+ return 0 ;
924
+ }
925
+
898
926
/*
899
927
* Do we have another file with a pathname that is a proper
900
928
* subset of the name we're trying to add?
@@ -906,6 +934,21 @@ static int has_dir_name(struct index_state *istate,
906
934
int stage = ce_stage (ce );
907
935
const char * name = ce -> name ;
908
936
const char * slash = name + ce_namelen (ce );
937
+ int len_eq_last ;
938
+ int cmp_last = 0 ;
939
+
940
+ if (istate -> cache_nr > 0 ) {
941
+ /*
942
+ * Compare the entry's full path with the last path in the index.
943
+ * If it sorts AFTER the last entry in the index and they have no
944
+ * common prefix, then there cannot be any F/D name conflicts.
945
+ */
946
+ cmp_last = strcmp_offset (name ,
947
+ istate -> cache [istate -> cache_nr - 1 ]-> name ,
948
+ & len_eq_last );
949
+ if (cmp_last > 0 && len_eq_last == 0 )
950
+ return retval ;
951
+ }
909
952
910
953
for (;;) {
911
954
int len ;
@@ -918,6 +961,24 @@ static int has_dir_name(struct index_state *istate,
918
961
}
919
962
len = slash - name ;
920
963
964
+ if (cmp_last > 0 ) {
965
+ /*
966
+ * If this part of the directory prefix (including the trailing
967
+ * slash) already appears in the path of the last entry in the
968
+ * index, then we cannot also have a file with this prefix (or
969
+ * any parent directory prefix).
970
+ */
971
+ if (len + 1 <= len_eq_last )
972
+ return retval ;
973
+ /*
974
+ * If this part of the directory prefix (excluding the trailing
975
+ * slash) is longer than the known equal portions, then this part
976
+ * of the prefix cannot collide with a file. Go on to the parent.
977
+ */
978
+ if (len > len_eq_last )
979
+ continue ;
980
+ }
981
+
921
982
pos = index_name_stage_pos (istate , name , len , stage );
922
983
if (pos >= 0 ) {
923
984
/*
@@ -1009,7 +1070,16 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
1009
1070
1010
1071
if (!(option & ADD_CACHE_KEEP_CACHE_TREE ))
1011
1072
cache_tree_invalidate_path (istate , ce -> name );
1012
- pos = index_name_stage_pos (istate , ce -> name , ce_namelen (ce ), ce_stage (ce ));
1073
+
1074
+ /*
1075
+ * If this entry's path sorts after the last entry in the index,
1076
+ * we can avoid searching for it.
1077
+ */
1078
+ if (istate -> cache_nr > 0 &&
1079
+ strcmp (ce -> name , istate -> cache [istate -> cache_nr - 1 ]-> name ) > 0 )
1080
+ pos = - istate -> cache_nr - 1 ;
1081
+ else
1082
+ pos = index_name_stage_pos (istate , ce -> name , ce_namelen (ce ), ce_stage (ce ));
1013
1083
1014
1084
/* existing match? Just replace it. */
1015
1085
if (pos >= 0 ) {
0 commit comments