@@ -901,6 +901,34 @@ static int has_file_name(struct index_state *istate,
901
901
return retval ;
902
902
}
903
903
904
+ /*
905
+ * Like strcmp(), but also return the offset of the first change.
906
+ */
907
+ int strcmp_offset (const char * s1_in , const char * s2_in , int * first_change )
908
+ {
909
+ const unsigned char * s1 = (const unsigned char * )s1_in ;
910
+ const unsigned char * s2 = (const unsigned char * )s2_in ;
911
+ int diff = 0 ;
912
+ int k ;
913
+
914
+ * first_change = 0 ;
915
+ for (k = 0 ; s1 [k ]; k ++ )
916
+ if ((diff = (s1 [k ] - s2 [k ])))
917
+ goto found_it ;
918
+ if (!s2 [k ])
919
+ return 0 ;
920
+ diff = -1 ;
921
+
922
+ found_it :
923
+ * first_change = k ;
924
+ if (diff > 0 )
925
+ return 1 ;
926
+ else if (diff < 0 )
927
+ return -1 ;
928
+ else
929
+ return 0 ;
930
+ }
931
+
904
932
/*
905
933
* Do we have another file with a pathname that is a proper
906
934
* subset of the name we're trying to add?
@@ -912,6 +940,21 @@ static int has_dir_name(struct index_state *istate,
912
940
int stage = ce_stage (ce );
913
941
const char * name = ce -> name ;
914
942
const char * slash = name + ce_namelen (ce );
943
+ int len_eq_last ;
944
+ int cmp_last = 0 ;
945
+
946
+ if (istate -> cache_nr > 0 ) {
947
+ /*
948
+ * Compare the entry's full path with the last path in the index.
949
+ * If it sorts AFTER the last entry in the index and they have no
950
+ * common prefix, then there cannot be any F/D name conflicts.
951
+ */
952
+ cmp_last = strcmp_offset (name ,
953
+ istate -> cache [istate -> cache_nr - 1 ]-> name ,
954
+ & len_eq_last );
955
+ if (cmp_last > 0 && len_eq_last == 0 )
956
+ return retval ;
957
+ }
915
958
916
959
for (;;) {
917
960
int len ;
@@ -924,6 +967,24 @@ static int has_dir_name(struct index_state *istate,
924
967
}
925
968
len = slash - name ;
926
969
970
+ if (cmp_last > 0 ) {
971
+ /*
972
+ * If this part of the directory prefix (including the trailing
973
+ * slash) already appears in the path of the last entry in the
974
+ * index, then we cannot also have a file with this prefix (or
975
+ * any parent directory prefix).
976
+ */
977
+ if (len + 1 <= len_eq_last )
978
+ return retval ;
979
+ /*
980
+ * If this part of the directory prefix (excluding the trailing
981
+ * slash) is longer than the known equal portions, then this part
982
+ * of the prefix cannot collide with a file. Go on to the parent.
983
+ */
984
+ if (len > len_eq_last )
985
+ continue ;
986
+ }
987
+
927
988
pos = index_name_stage_pos (istate , name , len , stage );
928
989
if (pos >= 0 ) {
929
990
/*
@@ -1015,7 +1076,16 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
1015
1076
1016
1077
if (!(option & ADD_CACHE_KEEP_CACHE_TREE ))
1017
1078
cache_tree_invalidate_path (istate , ce -> name );
1018
- pos = index_name_stage_pos (istate , ce -> name , ce_namelen (ce ), ce_stage (ce ));
1079
+
1080
+ /*
1081
+ * If this entry's path sorts after the last entry in the index,
1082
+ * we can avoid searching for it.
1083
+ */
1084
+ if (istate -> cache_nr > 0 &&
1085
+ strcmp (ce -> name , istate -> cache [istate -> cache_nr - 1 ]-> name ) > 0 )
1086
+ pos = - istate -> cache_nr - 1 ;
1087
+ else
1088
+ pos = index_name_stage_pos (istate , ce -> name , ce_namelen (ce ), ce_stage (ce ));
1019
1089
1020
1090
/* existing match? Just replace it. */
1021
1091
if (pos >= 0 ) {
0 commit comments