Commit bf4c39f92958b42f626fbf1d7fd95a74e62f3409

nulltoken 2011-03-30T22:30:55

Prevent tag_create() from creating a conflicting reference

diff --git a/include/git2/tag.h b/include/git2/tag.h
index ee92cd5..b83d447 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -140,7 +140,8 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t);
  * @param repo Repository where to store the tag
  *
  * @param tag_name Name for the tag; this name is validated
- * for consistency
+ * for consistency. It should also not conflict with an 
+ * already existing tag name
  *
  * @param target OID to which this tag points; note that no
  *	validation is done on this OID. Use the _o version of this
diff --git a/src/tag.c b/src/tag.c
index 7baabab..9a00694 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -182,10 +182,18 @@ int git_tag_create(
 
 	const char *type_str;
 	char *tagger_str;
+	git_reference *new_ref;
+
+	char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
 
 	int type_str_len, tag_name_len, tagger_str_len, message_len;
 	int error;
 
+	/** Ensure the tag name doesn't conflict with an already existing reference **/
+	git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
+	if (!git_reference_lookup(&new_ref, repo, ref_name))
+		return GIT_EEXISTS;	
+
 
 	type_str = git_object_type2string(target_type);
 
@@ -223,14 +231,10 @@ int git_tag_create(
 	error = stream->finalize_write(oid, stream);
 	stream->free(stream);
 
-	if (error == GIT_SUCCESS) {
-		char ref_name[512];
-		git_reference *new_ref;
-		git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
-		error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
-	}
+	if (error < GIT_SUCCESS)
+		return error;
 
-	return error;
+	return git_reference_create_oid(&new_ref, repo, ref_name, oid);
 }
 
 
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index 7b3c886..371f862 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -156,9 +156,38 @@ BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid
 
 END_TEST
 
+BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag")
+	git_repository *repo;
+	git_oid target_id, tag_id;
+	const git_signature *tagger;
+
+	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+	git_oid_mkstr(&target_id, tagged_commit);
+
+	/* create signature */
+	tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+	must_be_true(tagger != NULL);
+
+	must_fail(git_tag_create(
+		&tag_id, /* out id */
+		repo,
+		"very-simple",
+		&target_id,
+		GIT_OBJ_COMMIT,
+		tagger,
+		TAGGER_MESSAGE));
+
+	git_signature_free((git_signature *)tagger);
+
+	git_repository_free(repo);
+
+END_TEST
+
 
 BEGIN_SUITE(tag)
 	ADD_TEST(read0);
 	ADD_TEST(write0); 
 	ADD_TEST(write1); 
+	ADD_TEST(write2); 
 END_SUITE