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