summaryrefslogtreecommitdiff
path: root/sha1_name.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-12-15 20:54:00 (GMT)
committerJunio C Hamano <junkio@cox.net>2005-12-15 20:54:00 (GMT)
commit6677c4665af2d73f670bec382bc82d0f2e9513fb (patch)
tree7197059b14f5e6b820d2b8708434347160ef26e6 /sha1_name.c
parent8431c4eb0976b0558eaa1df475ce6de6b52ce484 (diff)
downloadgit-6677c4665af2d73f670bec382bc82d0f2e9513fb.zip
git-6677c4665af2d73f670bec382bc82d0f2e9513fb.tar.gz
git-6677c4665af2d73f670bec382bc82d0f2e9513fb.tar.bz2
get_sha1_basic(): corner case ambiguity fix
When .git/refs/heads/frotz and .git/refs/tags/frotz existed, and the object name stored in .git/refs/heads/frotz were corrupt, we ended up picking tags/frotz without complaining. Worse yet, if the corrupt .git/refs/heads/frotz was more than 40 bytes and began with hexadecimal characters, it silently overwritten the initial part of the returned result. This commit adds a couple of tests to demonstrate these cases, with a fix. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'sha1_name.c')
-rw-r--r--sha1_name.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/sha1_name.c b/sha1_name.c
index faac158..bf8f0f0 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -203,11 +203,12 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
return NULL;
}
-static int ambiguous_path(const char *path)
+static int ambiguous_path(const char *path, int len)
{
int slash = 1;
+ int cnt;
- for (;;) {
+ for (cnt = 0; cnt < len; cnt++) {
switch (*path++) {
case '\0':
break;
@@ -224,6 +225,7 @@ static int ambiguous_path(const char *path)
}
return slash;
}
+ return slash;
}
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -242,26 +244,41 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
return 0;
/* Accept only unambiguous ref paths. */
- if (ambiguous_path(str))
+ if (ambiguous_path(str, len))
return -1;
for (p = prefix; *p; p++) {
char *pathname = git_path("%s/%.*s", *p, len, str);
+
if (!read_ref(pathname, sha1)) {
/* Must be unique; i.e. when heads/foo and
* tags/foo are both present, reject "foo".
- * Note that read_ref() eventually calls
- * get_sha1_hex() which can smudge initial
- * part of the buffer even if what is read
- * is found to be invalid halfway.
*/
if (1 < found++)
return -1;
}
+
+ /* We want to allow .git/description file and
+ * "description" branch to exist at the same time.
+ * "git-rev-parse description" should silently skip
+ * .git/description file as a candidate for
+ * get_sha1(). However, having garbage file anywhere
+ * under refs/ is not OK, and we would not have caught
+ * ambiguous heads and tags with the above test.
+ */
+ else if (**p && !access(pathname, F_OK)) {
+ /* Garbage exists under .git/refs */
+ return error("garbage ref found '%s'", pathname);
+ }
}
- if (found == 1)
+ switch (found) {
+ case 0:
+ return -1;
+ case 1:
return 0;
- return -1;
+ default:
+ return error("ambiguous refname '%.*s'", len, str);
+ }
}
static int get_sha1_1(const char *name, int len, unsigned char *sha1);