diff options
Diffstat (limited to 'diffcore-rename.c')
| -rw-r--r-- | diffcore-rename.c | 61 | 
1 files changed, 39 insertions, 22 deletions
| diff --git a/diffcore-rename.c b/diffcore-rename.c index 749a35d2c2..af1fe08861 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -15,8 +15,7 @@ static struct diff_rename_dst {  } *rename_dst;  static int rename_dst_nr, rename_dst_alloc; -static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two, -						 int insert_ok) +static int find_rename_dst(struct diff_filespec *two)  {  	int first, last; @@ -27,16 +26,33 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,  		struct diff_rename_dst *dst = &(rename_dst[next]);  		int cmp = strcmp(two->path, dst->two->path);  		if (!cmp) -			return dst; +			return next;  		if (cmp < 0) {  			last = next;  			continue;  		}  		first = next+1;  	} -	/* not found */ -	if (!insert_ok) -		return NULL; +	return -first - 1; +} + +static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two) +{ +	int ofs = find_rename_dst(two); +	return ofs < 0 ? NULL : &rename_dst[ofs]; +} + +/* + * Returns 0 on success, -1 if we found a duplicate. + */ +static int add_rename_dst(struct diff_filespec *two) +{ +	int first = find_rename_dst(two); + +	if (first >= 0) +		return -1; +	first = -first - 1; +  	/* insert to make it at "first" */  	ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);  	rename_dst_nr++; @@ -46,7 +62,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,  	rename_dst[first].two = alloc_filespec(two->path);  	fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);  	rename_dst[first].pair = NULL; -	return &(rename_dst[first]); +	return 0;  }  /* Table of rename/copy src files */ @@ -147,9 +163,11 @@ static int estimate_similarity(struct diff_filespec *src,  	 * is a possible size - we really should have a flag to  	 * say whether the size is valid or not!)  	 */ -	if (!src->cnt_data && diff_populate_filespec(src, 1)) +	if (!src->cnt_data && +	    diff_populate_filespec(src, CHECK_SIZE_ONLY))  		return 0; -	if (!dst->cnt_data && diff_populate_filespec(dst, 1)) +	if (!dst->cnt_data && +	    diff_populate_filespec(dst, CHECK_SIZE_ONLY))  		return 0;  	max_size = ((src->size > dst->size) ? src->size : dst->size); @@ -242,14 +260,12 @@ struct file_similarity {  static unsigned int hash_filespec(struct diff_filespec *filespec)  { -	unsigned int hash;  	if (!filespec->sha1_valid) {  		if (diff_populate_filespec(filespec, 0))  			return 0;  		hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);  	} -	memcpy(&hash, filespec->sha1, sizeof(hash)); -	return hash; +	return sha1hash(filespec->sha1);  }  static int find_identical_files(struct hashmap *srcs, @@ -259,15 +275,14 @@ static int find_identical_files(struct hashmap *srcs,  	int renames = 0;  	struct diff_filespec *target = rename_dst[dst_index].two; -	struct file_similarity *p, *best, dst; +	struct file_similarity *p, *best = NULL;  	int i = 100, best_score = -1;  	/*  	 * Find the best source match for specified destination.  	 */ -	best = NULL; -	hashmap_entry_init(&dst, hash_filespec(target)); -	for (p = hashmap_get(srcs, &dst, NULL); p; p = hashmap_get_next(srcs, p)) { +	p = hashmap_get_from_hash(srcs, hash_filespec(target), NULL); +	for (; p; p = hashmap_get_next(srcs, p)) {  		int score;  		struct diff_filespec *source = p->filespec; @@ -451,8 +466,12 @@ void diffcore_rename(struct diff_options *options)  			else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&  				 is_empty_blob_sha1(p->two->sha1))  				continue; -			else -				locate_rename_dst(p->two, 1); +			else if (add_rename_dst(p->two) < 0) { +				warning("skipping rename detection, detected" +					" duplicate destination '%s'", +					p->two->path); +				goto cleanup; +			}  		}  		else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&  			 is_empty_blob_sha1(p->one->sha1)) @@ -583,8 +602,7 @@ void diffcore_rename(struct diff_options *options)  			 * We would output this create record if it has  			 * not been turned into a rename/copy already.  			 */ -			struct diff_rename_dst *dst = -				locate_rename_dst(p->two, 0); +			struct diff_rename_dst *dst = locate_rename_dst(p->two);  			if (dst && dst->pair) {  				diff_q(&outq, dst->pair);  				pair_to_free = p; @@ -614,8 +632,7 @@ void diffcore_rename(struct diff_options *options)  			 */  			if (DIFF_PAIR_BROKEN(p)) {  				/* broken delete */ -				struct diff_rename_dst *dst = -					locate_rename_dst(p->one, 0); +				struct diff_rename_dst *dst = locate_rename_dst(p->one);  				if (dst && dst->pair)  					/* counterpart is now rename/copy */  					pair_to_free = p; | 
