Skip to content

Commit

Permalink
fsck: check tag objects' headers
Browse files Browse the repository at this point in the history
We inspect commit objects pretty much in detail in git-fsck, but we just
glanced over the tag objects. Let's be stricter.

Since we do not want to limit 'tag' lines unduly, values that would fail
the refname check only result in warnings, not errors.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Johannes Schindelin authored and Junio C Hamano committed Sep 11, 2014
1 parent 4d0d897 commit cec097b
Showing 1 changed file with 85 additions and 1 deletion.
86 changes: 85 additions & 1 deletion fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "commit.h"
#include "tag.h"
#include "fsck.h"
#include "refs.h"

static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
{
Expand Down Expand Up @@ -355,14 +356,97 @@ static int fsck_commit(struct commit *commit, const char *data,
return ret;
}

static int fsck_tag_buffer(struct tag *tag, const char *data,
unsigned long size, fsck_error error_func)
{
unsigned char sha1[20];
int ret = 0;
const char *buffer;
char *to_free = NULL, *eol;
struct strbuf sb = STRBUF_INIT;

if (data)
buffer = data;
else {
enum object_type type;

buffer = to_free =
read_sha1_file(tag->object.sha1, &type, &size);
if (!buffer)
return error_func(&tag->object, FSCK_ERROR,
"cannot read tag object");

if (type != OBJ_TAG) {
ret = error_func(&tag->object, FSCK_ERROR,
"expected tag got %s",
typename(type));
goto done;
}
}

if (require_end_of_header(buffer, size, &tag->object, error_func))
goto done;

if (!skip_prefix(buffer, "object ", &buffer)) {
ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'object' line");
goto done;
}
if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
ret = error_func(&tag->object, FSCK_ERROR, "invalid 'object' line format - bad sha1");
goto done;
}
buffer += 41;

if (!skip_prefix(buffer, "type ", &buffer)) {
ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'type' line");
goto done;
}
eol = strchr(buffer, '\n');
if (!eol) {
ret = error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
goto done;
}
if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
ret = error_func(&tag->object, FSCK_ERROR, "invalid 'type' value");
if (ret)
goto done;
buffer = eol + 1;

if (!skip_prefix(buffer, "tag ", &buffer)) {
ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'tag' line");
goto done;
}
eol = strchr(buffer, '\n');
if (!eol) {
ret = error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
goto done;
}
strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
if (check_refname_format(sb.buf, 0))
error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %s", buffer);
buffer = eol + 1;

if (!skip_prefix(buffer, "tagger ", &buffer))
/* early tags do not contain 'tagger' lines; warn only */
error_func(&tag->object, FSCK_WARN, "invalid format - expected 'tagger' line");
else
ret = fsck_ident(&buffer, &tag->object, error_func);

done:
strbuf_release(&sb);
free(to_free);
return ret;
}

static int fsck_tag(struct tag *tag, const char *data,
unsigned long size, fsck_error error_func)
{
struct object *tagged = tag->tagged;

if (!tagged)
return error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
return 0;

return fsck_tag_buffer(tag, data, size, error_func);
}

int fsck_object(struct object *obj, void *data, unsigned long size,
Expand Down

0 comments on commit cec097b

Please sign in to comment.