@@ -15,8 +15,7 @@ static struct diff_rename_dst {
1515} * rename_dst ;
1616static int rename_dst_nr , rename_dst_alloc ;
1717
18- static struct diff_rename_dst * locate_rename_dst (struct diff_filespec * two ,
19- int insert_ok )
18+ static int find_rename_dst (struct diff_filespec * two )
2019{
2120 int first , last ;
2221
@@ -27,16 +26,33 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
2726 struct diff_rename_dst * dst = & (rename_dst [next ]);
2827 int cmp = strcmp (two -> path , dst -> two -> path );
2928 if (!cmp )
30- return dst ;
29+ return next ;
3130 if (cmp < 0 ) {
3231 last = next ;
3332 continue ;
3433 }
3534 first = next + 1 ;
3635 }
37- /* not found */
38- if (!insert_ok )
39- return NULL ;
36+ return - first - 1 ;
37+ }
38+
39+ static struct diff_rename_dst * locate_rename_dst (struct diff_filespec * two )
40+ {
41+ int ofs = find_rename_dst (two );
42+ return ofs < 0 ? NULL : & rename_dst [ofs ];
43+ }
44+
45+ /*
46+ * Returns 0 on success, -1 if we found a duplicate.
47+ */
48+ static int add_rename_dst (struct diff_filespec * two )
49+ {
50+ int first = find_rename_dst (two );
51+
52+ if (first >= 0 )
53+ return -1 ;
54+ first = - first - 1 ;
55+
4056 /* insert to make it at "first" */
4157 ALLOC_GROW (rename_dst , rename_dst_nr + 1 , rename_dst_alloc );
4258 rename_dst_nr ++ ;
@@ -46,7 +62,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
4662 rename_dst [first ].two = alloc_filespec (two -> path );
4763 fill_filespec (rename_dst [first ].two , two -> sha1 , two -> sha1_valid , two -> mode );
4864 rename_dst [first ].pair = NULL ;
49- return & ( rename_dst [ first ]) ;
65+ return 0 ;
5066}
5167
5268/* Table of rename/copy src files */
@@ -450,8 +466,12 @@ void diffcore_rename(struct diff_options *options)
450466 else if (!DIFF_OPT_TST (options , RENAME_EMPTY ) &&
451467 is_empty_blob_sha1 (p -> two -> sha1 ))
452468 continue ;
453- else
454- locate_rename_dst (p -> two , 1 );
469+ else if (add_rename_dst (p -> two ) < 0 ) {
470+ warning ("skipping rename detection, detected"
471+ " duplicate destination '%s'" ,
472+ p -> two -> path );
473+ goto cleanup ;
474+ }
455475 }
456476 else if (!DIFF_OPT_TST (options , RENAME_EMPTY ) &&
457477 is_empty_blob_sha1 (p -> one -> sha1 ))
@@ -582,8 +602,7 @@ void diffcore_rename(struct diff_options *options)
582602 * We would output this create record if it has
583603 * not been turned into a rename/copy already.
584604 */
585- struct diff_rename_dst * dst =
586- locate_rename_dst (p -> two , 0 );
605+ struct diff_rename_dst * dst = locate_rename_dst (p -> two );
587606 if (dst && dst -> pair ) {
588607 diff_q (& outq , dst -> pair );
589608 pair_to_free = p ;
@@ -613,8 +632,7 @@ void diffcore_rename(struct diff_options *options)
613632 */
614633 if (DIFF_PAIR_BROKEN (p )) {
615634 /* broken delete */
616- struct diff_rename_dst * dst =
617- locate_rename_dst (p -> one , 0 );
635+ struct diff_rename_dst * dst = locate_rename_dst (p -> one );
618636 if (dst && dst -> pair )
619637 /* counterpart is now rename/copy */
620638 pair_to_free = p ;
0 commit comments