Merge branch 'jk/cleanup-object-parsing-and-fsck'
Crufty code and logic accumulated over time around the object parsing and low-level object access used in "git fsck" have been cleaned up. * jk/cleanup-object-parsing-and-fsck: (23 commits) fsck: accept an oid instead of a "struct tree" for fsck_tree() fsck: accept an oid instead of a "struct commit" for fsck_commit() fsck: accept an oid instead of a "struct tag" for fsck_tag() fsck: rename vague "oid" local variables fsck: don't require an object struct in verify_headers() fsck: don't require an object struct for fsck_ident() fsck: drop blob struct from fsck_finish() fsck: accept an oid instead of a "struct blob" for fsck_blob() fsck: don't require an object struct for report() fsck: only require an oid for skiplist functions fsck: only provide oid/type in fsck_error callback fsck: don't require object structs for display functions fsck: use oids rather than objects for object_name API fsck_describe_object(): build on our get_object_name() primitive fsck: unify object-name code fsck: require an actual buffer for non-blobs fsck: stop checking tag->tagged fsck: stop checking commit->parent counts fsck: stop checking commit->tree value commit, tag: don't set parsed bit for parse failures ...
This commit is contained in:
commit
0e07c1cd83
126
builtin/fsck.c
126
builtin/fsck.c
@ -50,40 +50,20 @@ static int name_objects;
|
||||
#define ERROR_REFS 010
|
||||
#define ERROR_COMMIT_GRAPH 020
|
||||
|
||||
static const char *describe_object(struct object *obj)
|
||||
static const char *describe_object(const struct object_id *oid)
|
||||
{
|
||||
static struct strbuf bufs[] = {
|
||||
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
|
||||
};
|
||||
static int b = 0;
|
||||
struct strbuf *buf;
|
||||
char *name = NULL;
|
||||
|
||||
if (name_objects)
|
||||
name = lookup_decoration(fsck_walk_options.object_names, obj);
|
||||
|
||||
buf = bufs + b;
|
||||
b = (b + 1) % ARRAY_SIZE(bufs);
|
||||
strbuf_reset(buf);
|
||||
strbuf_addstr(buf, oid_to_hex(&obj->oid));
|
||||
if (name)
|
||||
strbuf_addf(buf, " (%s)", name);
|
||||
|
||||
return buf->buf;
|
||||
return fsck_describe_object(&fsck_walk_options, oid);
|
||||
}
|
||||
|
||||
static const char *printable_type(struct object *obj)
|
||||
static const char *printable_type(const struct object_id *oid,
|
||||
enum object_type type)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
if (obj->type == OBJ_NONE) {
|
||||
enum object_type type = oid_object_info(the_repository,
|
||||
&obj->oid, NULL);
|
||||
if (type > 0)
|
||||
object_as_type(the_repository, obj, type, 0);
|
||||
}
|
||||
if (type == OBJ_NONE)
|
||||
type = oid_object_info(the_repository, oid, NULL);
|
||||
|
||||
ret = type_name(obj->type);
|
||||
ret = type_name(type);
|
||||
if (!ret)
|
||||
ret = _("unknown");
|
||||
|
||||
@ -118,26 +98,32 @@ static int objerror(struct object *obj, const char *err)
|
||||
errors_found |= ERROR_OBJECT;
|
||||
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
|
||||
fprintf_ln(stderr, _("error in %s %s: %s"),
|
||||
printable_type(obj), describe_object(obj), err);
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid), err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int fsck_error_func(struct fsck_options *o,
|
||||
struct object *obj, int type, const char *message)
|
||||
const struct object_id *oid,
|
||||
enum object_type object_type,
|
||||
int msg_type, const char *message)
|
||||
{
|
||||
switch (type) {
|
||||
switch (msg_type) {
|
||||
case FSCK_WARN:
|
||||
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
|
||||
fprintf_ln(stderr, _("warning in %s %s: %s"),
|
||||
printable_type(obj), describe_object(obj), message);
|
||||
printable_type(oid, object_type),
|
||||
describe_object(oid), message);
|
||||
return 0;
|
||||
case FSCK_ERROR:
|
||||
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
|
||||
fprintf_ln(stderr, _("error in %s %s: %s"),
|
||||
printable_type(obj), describe_object(obj), message);
|
||||
printable_type(oid, object_type),
|
||||
describe_object(oid), message);
|
||||
return 1;
|
||||
default:
|
||||
BUG("%d (FSCK_IGNORE?) should never trigger this callback", type);
|
||||
BUG("%d (FSCK_IGNORE?) should never trigger this callback",
|
||||
msg_type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +141,8 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
|
||||
if (!obj) {
|
||||
/* ... these references to parent->fld are safe here */
|
||||
printf_ln(_("broken link from %7s %s"),
|
||||
printable_type(parent), describe_object(parent));
|
||||
printable_type(&parent->oid, parent->type),
|
||||
describe_object(&parent->oid));
|
||||
printf_ln(_("broken link from %7s %s"),
|
||||
(type == OBJ_ANY ? _("unknown") : type_name(type)),
|
||||
_("unknown"));
|
||||
@ -183,10 +170,10 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
|
||||
if (parent && !has_object_file(&obj->oid)) {
|
||||
printf_ln(_("broken link from %7s %s\n"
|
||||
" to %7s %s"),
|
||||
printable_type(parent),
|
||||
describe_object(parent),
|
||||
printable_type(obj),
|
||||
describe_object(obj));
|
||||
printable_type(&parent->oid, parent->type),
|
||||
describe_object(&parent->oid),
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
}
|
||||
return 1;
|
||||
@ -292,8 +279,9 @@ static void check_reachable_object(struct object *obj)
|
||||
return;
|
||||
if (has_object_pack(&obj->oid))
|
||||
return; /* it is in pack - forget about it */
|
||||
printf_ln(_("missing %s %s"), printable_type(obj),
|
||||
describe_object(obj));
|
||||
printf_ln(_("missing %s %s"),
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
return;
|
||||
}
|
||||
@ -318,8 +306,9 @@ static void check_unreachable_object(struct object *obj)
|
||||
* since this is something that is prunable.
|
||||
*/
|
||||
if (show_unreachable) {
|
||||
printf_ln(_("unreachable %s %s"), printable_type(obj),
|
||||
describe_object(obj));
|
||||
printf_ln(_("unreachable %s %s"),
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -337,12 +326,13 @@ static void check_unreachable_object(struct object *obj)
|
||||
*/
|
||||
if (!(obj->flags & USED)) {
|
||||
if (show_dangling)
|
||||
printf_ln(_("dangling %s %s"), printable_type(obj),
|
||||
describe_object(obj));
|
||||
printf_ln(_("dangling %s %s"),
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid));
|
||||
if (write_lost_and_found) {
|
||||
char *filename = git_pathdup("lost-found/%s/%s",
|
||||
obj->type == OBJ_COMMIT ? "commit" : "other",
|
||||
describe_object(obj));
|
||||
describe_object(&obj->oid));
|
||||
FILE *f;
|
||||
|
||||
if (safe_create_leading_directories_const(filename)) {
|
||||
@ -355,7 +345,7 @@ static void check_unreachable_object(struct object *obj)
|
||||
if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
|
||||
die_errno(_("could not write '%s'"), filename);
|
||||
} else
|
||||
fprintf(f, "%s\n", describe_object(obj));
|
||||
fprintf(f, "%s\n", describe_object(&obj->oid));
|
||||
if (fclose(f))
|
||||
die_errno(_("could not finish '%s'"),
|
||||
filename);
|
||||
@ -374,7 +364,7 @@ static void check_unreachable_object(struct object *obj)
|
||||
static void check_object(struct object *obj)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf_ln(stderr, _("Checking %s"), describe_object(obj));
|
||||
fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
|
||||
|
||||
if (obj->flags & REACHABLE)
|
||||
check_reachable_object(obj);
|
||||
@ -432,7 +422,8 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
|
||||
|
||||
if (verbose)
|
||||
fprintf_ln(stderr, _("Checking %s %s"),
|
||||
printable_type(obj), describe_object(obj));
|
||||
printable_type(&obj->oid, obj->type),
|
||||
describe_object(&obj->oid));
|
||||
|
||||
if (fsck_walk(obj, NULL, &fsck_obj_options))
|
||||
objerror(obj, _("broken links"));
|
||||
@ -445,7 +436,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
|
||||
|
||||
if (!commit->parents && show_root)
|
||||
printf_ln(_("root %s"),
|
||||
describe_object(&commit->object));
|
||||
describe_object(&commit->object.oid));
|
||||
}
|
||||
|
||||
if (obj->type == OBJ_TAG) {
|
||||
@ -453,10 +444,10 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
|
||||
|
||||
if (show_tags && tag->tagged) {
|
||||
printf_ln(_("tagged %s %s (%s) in %s"),
|
||||
printable_type(tag->tagged),
|
||||
describe_object(tag->tagged),
|
||||
printable_type(&tag->tagged->oid, tag->tagged->type),
|
||||
describe_object(&tag->tagged->oid),
|
||||
tag->tag,
|
||||
describe_object(&tag->object));
|
||||
describe_object(&tag->object.oid));
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,10 +490,10 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
|
||||
if (!is_null_oid(oid)) {
|
||||
obj = lookup_object(the_repository, oid);
|
||||
if (obj && (obj->flags & HAS_OBJ)) {
|
||||
if (timestamp && name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj,
|
||||
xstrfmt("%s@{%"PRItime"}", refname, timestamp));
|
||||
if (timestamp)
|
||||
fsck_put_object_name(&fsck_walk_options, oid,
|
||||
"%s@{%"PRItime"}",
|
||||
refname, timestamp);
|
||||
obj->flags |= USED;
|
||||
mark_object_reachable(obj);
|
||||
} else if (!is_promisor_object(oid)) {
|
||||
@ -566,9 +557,8 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
|
||||
}
|
||||
default_refs++;
|
||||
obj->flags |= USED;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(refname));
|
||||
fsck_put_object_name(&fsck_walk_options,
|
||||
oid, "%s", refname);
|
||||
mark_object_reachable(obj);
|
||||
|
||||
return 0;
|
||||
@ -742,9 +732,7 @@ static int fsck_cache_tree(struct cache_tree *it)
|
||||
return 1;
|
||||
}
|
||||
obj->flags |= USED;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(":"));
|
||||
fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
|
||||
mark_object_reachable(obj);
|
||||
if (obj->type != OBJ_TREE)
|
||||
err |= objerror(obj, _("non-tree in cache-tree"));
|
||||
@ -830,8 +818,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (name_objects)
|
||||
fsck_walk_options.object_names =
|
||||
xcalloc(1, sizeof(struct decoration));
|
||||
fsck_enable_object_names(&fsck_walk_options);
|
||||
|
||||
git_config(fsck_config, NULL);
|
||||
|
||||
@ -890,9 +877,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
obj->flags |= USED;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(arg));
|
||||
fsck_put_object_name(&fsck_walk_options, &oid,
|
||||
"%s", arg);
|
||||
mark_object_reachable(obj);
|
||||
continue;
|
||||
}
|
||||
@ -928,10 +914,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
obj = &blob->object;
|
||||
obj->flags |= USED;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj,
|
||||
xstrfmt(":%s", active_cache[i]->name));
|
||||
fsck_put_object_name(&fsck_walk_options, &obj->oid,
|
||||
":%s", active_cache[i]->name);
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
if (active_cache_tree)
|
||||
|
@ -858,9 +858,6 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
|
||||
die(_("unable to parse commit %s"),
|
||||
oid_to_hex(&(*list)->object.oid));
|
||||
tree = get_commit_tree_oid(*list);
|
||||
if (!tree)
|
||||
die(_("unable to get tree for %s"),
|
||||
oid_to_hex(&(*list)->object.oid));
|
||||
hashwrite(f, tree->hash, hash_len);
|
||||
|
||||
parent = (*list)->parents;
|
||||
|
33
commit.c
33
commit.c
@ -402,10 +402,22 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
|
||||
struct commit_graft *graft;
|
||||
const int tree_entry_len = the_hash_algo->hexsz + 5;
|
||||
const int parent_entry_len = the_hash_algo->hexsz + 7;
|
||||
struct tree *tree;
|
||||
|
||||
if (item->object.parsed)
|
||||
return 0;
|
||||
item->object.parsed = 1;
|
||||
|
||||
if (item->parents) {
|
||||
/*
|
||||
* Presumably this is leftover from an earlier failed parse;
|
||||
* clear it out in preparation for us re-parsing (we'll hit the
|
||||
* same error, but that's good, since it lets our caller know
|
||||
* the result cannot be trusted.
|
||||
*/
|
||||
free_commit_list(item->parents);
|
||||
item->parents = NULL;
|
||||
}
|
||||
|
||||
tail += size;
|
||||
if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
|
||||
bufptr[tree_entry_len] != '\n')
|
||||
@ -413,7 +425,12 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
|
||||
if (get_oid_hex(bufptr + 5, &parent) < 0)
|
||||
return error("bad tree pointer in commit %s",
|
||||
oid_to_hex(&item->object.oid));
|
||||
set_commit_tree(item, lookup_tree(r, &parent));
|
||||
tree = lookup_tree(r, &parent);
|
||||
if (!tree)
|
||||
return error("bad tree pointer %s in commit %s",
|
||||
oid_to_hex(&parent),
|
||||
oid_to_hex(&item->object.oid));
|
||||
set_commit_tree(item, tree);
|
||||
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
|
||||
pptr = &item->parents;
|
||||
|
||||
@ -433,8 +450,11 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
|
||||
if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
|
||||
continue;
|
||||
new_parent = lookup_commit(r, &parent);
|
||||
if (new_parent)
|
||||
pptr = &commit_list_insert(new_parent, pptr)->next;
|
||||
if (!new_parent)
|
||||
return error("bad parent %s in commit %s",
|
||||
oid_to_hex(&parent),
|
||||
oid_to_hex(&item->object.oid));
|
||||
pptr = &commit_list_insert(new_parent, pptr)->next;
|
||||
}
|
||||
if (graft) {
|
||||
int i;
|
||||
@ -443,7 +463,9 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
|
||||
new_parent = lookup_commit(r,
|
||||
&graft->parent[i]);
|
||||
if (!new_parent)
|
||||
continue;
|
||||
return error("bad graft parent %s in commit %s",
|
||||
oid_to_hex(&graft->parent[i]),
|
||||
oid_to_hex(&item->object.oid));
|
||||
pptr = &commit_list_insert(new_parent, pptr)->next;
|
||||
}
|
||||
}
|
||||
@ -452,6 +474,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
|
||||
if (check_graph)
|
||||
load_commit_graph_info(r, item);
|
||||
|
||||
item->object.parsed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
386
fsck.c
386
fsck.c
@ -43,21 +43,17 @@ static struct oidset gitmodules_done = OIDSET_INIT;
|
||||
FUNC(MISSING_AUTHOR, ERROR) \
|
||||
FUNC(MISSING_COMMITTER, ERROR) \
|
||||
FUNC(MISSING_EMAIL, ERROR) \
|
||||
FUNC(MISSING_GRAFT, ERROR) \
|
||||
FUNC(MISSING_NAME_BEFORE_EMAIL, ERROR) \
|
||||
FUNC(MISSING_OBJECT, ERROR) \
|
||||
FUNC(MISSING_PARENT, ERROR) \
|
||||
FUNC(MISSING_SPACE_BEFORE_DATE, ERROR) \
|
||||
FUNC(MISSING_SPACE_BEFORE_EMAIL, ERROR) \
|
||||
FUNC(MISSING_TAG, ERROR) \
|
||||
FUNC(MISSING_TAG_ENTRY, ERROR) \
|
||||
FUNC(MISSING_TAG_OBJECT, ERROR) \
|
||||
FUNC(MISSING_TREE, ERROR) \
|
||||
FUNC(MISSING_TREE_OBJECT, ERROR) \
|
||||
FUNC(MISSING_TYPE, ERROR) \
|
||||
FUNC(MISSING_TYPE_ENTRY, ERROR) \
|
||||
FUNC(MULTIPLE_AUTHORS, ERROR) \
|
||||
FUNC(TAG_OBJECT_NOT_TAG, ERROR) \
|
||||
FUNC(TREE_NOT_SORTED, ERROR) \
|
||||
FUNC(UNKNOWN_TYPE, ERROR) \
|
||||
FUNC(ZERO_PADDED_DATE, ERROR) \
|
||||
@ -281,14 +277,16 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
|
||||
strbuf_addstr(sb, ": ");
|
||||
}
|
||||
|
||||
static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
|
||||
static int object_on_skiplist(struct fsck_options *opts,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
return opts && obj && oidset_contains(&opts->skiplist, &obj->oid);
|
||||
return opts && oid && oidset_contains(&opts->skiplist, oid);
|
||||
}
|
||||
|
||||
__attribute__((format (printf, 4, 5)))
|
||||
static int report(struct fsck_options *options, struct object *object,
|
||||
enum fsck_msg_id id, const char *fmt, ...)
|
||||
__attribute__((format (printf, 5, 6)))
|
||||
static int report(struct fsck_options *options,
|
||||
const struct object_id *oid, enum object_type object_type,
|
||||
enum fsck_msg_id id, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
@ -297,7 +295,7 @@ static int report(struct fsck_options *options, struct object *object,
|
||||
if (msg_type == FSCK_IGNORE)
|
||||
return 0;
|
||||
|
||||
if (object_on_skiplist(options, object))
|
||||
if (object_on_skiplist(options, oid))
|
||||
return 0;
|
||||
|
||||
if (msg_type == FSCK_FATAL)
|
||||
@ -309,49 +307,71 @@ static int report(struct fsck_options *options, struct object *object,
|
||||
|
||||
va_start(ap, fmt);
|
||||
strbuf_vaddf(&sb, fmt, ap);
|
||||
result = options->error_func(options, object, msg_type, sb.buf);
|
||||
result = options->error_func(options, oid, object_type,
|
||||
msg_type, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *get_object_name(struct fsck_options *options, struct object *obj)
|
||||
void fsck_enable_object_names(struct fsck_options *options)
|
||||
{
|
||||
if (!options->object_names)
|
||||
return NULL;
|
||||
return lookup_decoration(options->object_names, obj);
|
||||
options->object_names = kh_init_oid_map();
|
||||
}
|
||||
|
||||
static void put_object_name(struct fsck_options *options, struct object *obj,
|
||||
const char *fmt, ...)
|
||||
const char *fsck_get_object_name(struct fsck_options *options,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
khiter_t pos;
|
||||
if (!options->object_names)
|
||||
return NULL;
|
||||
pos = kh_get_oid_map(options->object_names, *oid);
|
||||
if (pos >= kh_end(options->object_names))
|
||||
return NULL;
|
||||
return kh_value(options->object_names, pos);
|
||||
}
|
||||
|
||||
void fsck_put_object_name(struct fsck_options *options,
|
||||
const struct object_id *oid,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *existing;
|
||||
khiter_t pos;
|
||||
int hashret;
|
||||
|
||||
if (!options->object_names)
|
||||
return;
|
||||
existing = lookup_decoration(options->object_names, obj);
|
||||
if (existing)
|
||||
|
||||
pos = kh_put_oid_map(options->object_names, *oid, &hashret);
|
||||
if (!hashret)
|
||||
return;
|
||||
va_start(ap, fmt);
|
||||
strbuf_vaddf(&buf, fmt, ap);
|
||||
add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
|
||||
kh_value(options->object_names, pos) = strbuf_detach(&buf, NULL);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static const char *describe_object(struct fsck_options *o, struct object *obj)
|
||||
const char *fsck_describe_object(struct fsck_options *options,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
char *name;
|
||||
static struct strbuf bufs[] = {
|
||||
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
|
||||
};
|
||||
static int b = 0;
|
||||
struct strbuf *buf;
|
||||
const char *name = fsck_get_object_name(options, oid);
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, oid_to_hex(&obj->oid));
|
||||
if (o->object_names && (name = lookup_decoration(o->object_names, obj)))
|
||||
strbuf_addf(&buf, " (%s)", name);
|
||||
buf = bufs + b;
|
||||
b = (b + 1) % ARRAY_SIZE(bufs);
|
||||
strbuf_reset(buf);
|
||||
strbuf_addstr(buf, oid_to_hex(oid));
|
||||
if (name)
|
||||
strbuf_addf(buf, " (%s)", name);
|
||||
|
||||
return buf.buf;
|
||||
return buf->buf;
|
||||
}
|
||||
|
||||
static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
|
||||
@ -364,7 +384,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
|
||||
if (parse_tree(tree))
|
||||
return -1;
|
||||
|
||||
name = get_object_name(options, &tree->object);
|
||||
name = fsck_get_object_name(options, &tree->object.oid);
|
||||
if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
|
||||
return -1;
|
||||
while (tree_entry_gently(&desc, &entry)) {
|
||||
@ -377,20 +397,21 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
|
||||
if (S_ISDIR(entry.mode)) {
|
||||
obj = (struct object *)lookup_tree(the_repository, &entry.oid);
|
||||
if (name && obj)
|
||||
put_object_name(options, obj, "%s%s/", name,
|
||||
entry.path);
|
||||
fsck_put_object_name(options, &entry.oid, "%s%s/",
|
||||
name, entry.path);
|
||||
result = options->walk(obj, OBJ_TREE, data, options);
|
||||
}
|
||||
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
|
||||
obj = (struct object *)lookup_blob(the_repository, &entry.oid);
|
||||
if (name && obj)
|
||||
put_object_name(options, obj, "%s%s", name,
|
||||
entry.path);
|
||||
fsck_put_object_name(options, &entry.oid, "%s%s",
|
||||
name, entry.path);
|
||||
result = options->walk(obj, OBJ_BLOB, data, options);
|
||||
}
|
||||
else {
|
||||
result = error("in tree %s: entry %s has bad mode %.6o",
|
||||
describe_object(options, &tree->object), entry.path, entry.mode);
|
||||
fsck_describe_object(options, &tree->object.oid),
|
||||
entry.path, entry.mode);
|
||||
}
|
||||
if (result < 0)
|
||||
return result;
|
||||
@ -411,10 +432,10 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
|
||||
if (parse_commit(commit))
|
||||
return -1;
|
||||
|
||||
name = get_object_name(options, &commit->object);
|
||||
name = fsck_get_object_name(options, &commit->object.oid);
|
||||
if (name)
|
||||
put_object_name(options, &get_commit_tree(commit)->object,
|
||||
"%s:", name);
|
||||
fsck_put_object_name(options, get_commit_tree_oid(commit),
|
||||
"%s:", name);
|
||||
|
||||
result = options->walk((struct object *)get_commit_tree(commit),
|
||||
OBJ_TREE, data, options);
|
||||
@ -442,16 +463,17 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
|
||||
|
||||
while (parents) {
|
||||
if (name) {
|
||||
struct object *obj = &parents->item->object;
|
||||
struct object_id *oid = &parents->item->object.oid;
|
||||
|
||||
if (counter++)
|
||||
put_object_name(options, obj, "%s^%d",
|
||||
name, counter);
|
||||
fsck_put_object_name(options, oid, "%s^%d",
|
||||
name, counter);
|
||||
else if (generation > 0)
|
||||
put_object_name(options, obj, "%.*s~%d",
|
||||
name_prefix_len, name, generation + 1);
|
||||
fsck_put_object_name(options, oid, "%.*s~%d",
|
||||
name_prefix_len, name,
|
||||
generation + 1);
|
||||
else
|
||||
put_object_name(options, obj, "%s^", name);
|
||||
fsck_put_object_name(options, oid, "%s^", name);
|
||||
}
|
||||
result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
|
||||
if (result < 0)
|
||||
@ -465,12 +487,12 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
|
||||
|
||||
static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
|
||||
{
|
||||
char *name = get_object_name(options, &tag->object);
|
||||
const char *name = fsck_get_object_name(options, &tag->object.oid);
|
||||
|
||||
if (parse_tag(tag))
|
||||
return -1;
|
||||
if (name)
|
||||
put_object_name(options, tag->tagged, "%s", name);
|
||||
fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
|
||||
return options->walk(tag->tagged, OBJ_ANY, data, options);
|
||||
}
|
||||
|
||||
@ -492,7 +514,8 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
|
||||
case OBJ_TAG:
|
||||
return fsck_walk_tag((struct tag *)obj, data, options);
|
||||
default:
|
||||
error("Unknown object type for %s", describe_object(options, obj));
|
||||
error("Unknown object type for %s",
|
||||
fsck_describe_object(options, &obj->oid));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -543,7 +566,9 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
|
||||
return c1 < c2 ? 0 : TREE_UNORDERED;
|
||||
}
|
||||
|
||||
static int fsck_tree(struct tree *item, struct fsck_options *options)
|
||||
static int fsck_tree(const struct object_id *oid,
|
||||
const char *buffer, unsigned long size,
|
||||
struct fsck_options *options)
|
||||
{
|
||||
int retval = 0;
|
||||
int has_null_sha1 = 0;
|
||||
@ -560,8 +585,8 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
|
||||
unsigned o_mode;
|
||||
const char *o_name;
|
||||
|
||||
if (init_tree_desc_gently(&desc, item->buffer, item->size)) {
|
||||
retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
|
||||
if (init_tree_desc_gently(&desc, buffer, size)) {
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -587,13 +612,14 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
|
||||
if (!S_ISLNK(mode))
|
||||
oidset_insert(&gitmodules_found, oid);
|
||||
else
|
||||
retval += report(options, &item->object,
|
||||
retval += report(options,
|
||||
oid, OBJ_TREE,
|
||||
FSCK_MSG_GITMODULES_SYMLINK,
|
||||
".gitmodules is a symbolic link");
|
||||
}
|
||||
|
||||
if (update_tree_entry_gently(&desc)) {
|
||||
retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -638,30 +664,31 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
|
||||
}
|
||||
|
||||
if (has_null_sha1)
|
||||
retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
|
||||
if (has_full_path)
|
||||
retval += report(options, &item->object, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
|
||||
if (has_empty_name)
|
||||
retval += report(options, &item->object, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
|
||||
if (has_dot)
|
||||
retval += report(options, &item->object, FSCK_MSG_HAS_DOT, "contains '.'");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOT, "contains '.'");
|
||||
if (has_dotdot)
|
||||
retval += report(options, &item->object, FSCK_MSG_HAS_DOTDOT, "contains '..'");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTDOT, "contains '..'");
|
||||
if (has_dotgit)
|
||||
retval += report(options, &item->object, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
|
||||
if (has_zero_pad)
|
||||
retval += report(options, &item->object, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
|
||||
if (has_bad_modes)
|
||||
retval += report(options, &item->object, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
|
||||
if (has_dup_entries)
|
||||
retval += report(options, &item->object, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
|
||||
if (not_properly_sorted)
|
||||
retval += report(options, &item->object, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
|
||||
retval += report(options, oid, OBJ_TREE, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int verify_headers(const void *data, unsigned long size,
|
||||
struct object *obj, struct fsck_options *options)
|
||||
const struct object_id *oid, enum object_type type,
|
||||
struct fsck_options *options)
|
||||
{
|
||||
const char *buffer = (const char *)data;
|
||||
unsigned long i;
|
||||
@ -669,7 +696,7 @@ static int verify_headers(const void *data, unsigned long size,
|
||||
for (i = 0; i < size; i++) {
|
||||
switch (buffer[i]) {
|
||||
case '\0':
|
||||
return report(options, obj,
|
||||
return report(options, oid, type,
|
||||
FSCK_MSG_NUL_IN_HEADER,
|
||||
"unterminated header: NUL at offset %ld", i);
|
||||
case '\n':
|
||||
@ -687,11 +714,13 @@ static int verify_headers(const void *data, unsigned long size,
|
||||
if (size && buffer[size - 1] == '\n')
|
||||
return 0;
|
||||
|
||||
return report(options, obj,
|
||||
return report(options, oid, type,
|
||||
FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
|
||||
}
|
||||
|
||||
static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options)
|
||||
static int fsck_ident(const char **ident,
|
||||
const struct object_id *oid, enum object_type type,
|
||||
struct fsck_options *options)
|
||||
{
|
||||
const char *p = *ident;
|
||||
char *end;
|
||||
@ -701,28 +730,28 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
|
||||
(*ident)++;
|
||||
|
||||
if (*p == '<')
|
||||
return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
|
||||
return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
|
||||
p += strcspn(p, "<>\n");
|
||||
if (*p == '>')
|
||||
return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
|
||||
return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
|
||||
if (*p != '<')
|
||||
return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
|
||||
return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
|
||||
if (p[-1] != ' ')
|
||||
return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
|
||||
return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
|
||||
p++;
|
||||
p += strcspn(p, "<>\n");
|
||||
if (*p != '>')
|
||||
return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
|
||||
return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
|
||||
p++;
|
||||
if (*p != ' ')
|
||||
return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
|
||||
return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
|
||||
p++;
|
||||
if (*p == '0' && p[1] != ' ')
|
||||
return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
|
||||
return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
|
||||
if (date_overflows(parse_timestamp(p, &end, 10)))
|
||||
return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
|
||||
return report(options, oid, type, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
|
||||
if ((end == p || *end != ' '))
|
||||
return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
|
||||
return report(options, oid, type, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
|
||||
p = end + 1;
|
||||
if ((*p != '+' && *p != '-') ||
|
||||
!isdigit(p[1]) ||
|
||||
@ -730,83 +759,60 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
|
||||
!isdigit(p[3]) ||
|
||||
!isdigit(p[4]) ||
|
||||
(p[5] != '\n'))
|
||||
return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
|
||||
return report(options, oid, type, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
|
||||
p += 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_commit_buffer(struct commit *commit, const char *buffer,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
static int fsck_commit(const struct object_id *oid,
|
||||
const char *buffer, unsigned long size,
|
||||
struct fsck_options *options)
|
||||
{
|
||||
struct object_id tree_oid, oid;
|
||||
struct commit_graft *graft;
|
||||
unsigned parent_count, parent_line_count = 0, author_count;
|
||||
struct object_id tree_oid, parent_oid;
|
||||
unsigned author_count;
|
||||
int err;
|
||||
const char *buffer_begin = buffer;
|
||||
const char *p;
|
||||
|
||||
if (verify_headers(buffer, size, &commit->object, options))
|
||||
if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
|
||||
return -1;
|
||||
|
||||
if (!skip_prefix(buffer, "tree ", &buffer))
|
||||
return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
|
||||
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
|
||||
if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
|
||||
err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
|
||||
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
buffer = p + 1;
|
||||
while (skip_prefix(buffer, "parent ", &buffer)) {
|
||||
if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
|
||||
err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
|
||||
if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
|
||||
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
buffer = p + 1;
|
||||
parent_line_count++;
|
||||
}
|
||||
graft = lookup_commit_graft(the_repository, &commit->object.oid);
|
||||
parent_count = commit_list_count(commit->parents);
|
||||
if (graft) {
|
||||
if (graft->nr_parent == -1 && !parent_count)
|
||||
; /* shallow commit */
|
||||
else if (graft->nr_parent != parent_count) {
|
||||
err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (parent_count != parent_line_count) {
|
||||
err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
author_count = 0;
|
||||
while (skip_prefix(buffer, "author ", &buffer)) {
|
||||
author_count++;
|
||||
err = fsck_ident(&buffer, &commit->object, options);
|
||||
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (author_count < 1)
|
||||
err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
|
||||
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
|
||||
else if (author_count > 1)
|
||||
err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
|
||||
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
|
||||
if (err)
|
||||
return err;
|
||||
if (!skip_prefix(buffer, "committer ", &buffer))
|
||||
return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
|
||||
err = fsck_ident(&buffer, &commit->object, options);
|
||||
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
|
||||
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
|
||||
if (err)
|
||||
return err;
|
||||
if (!get_commit_tree(commit)) {
|
||||
err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (memchr(buffer_begin, '\0', size)) {
|
||||
err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
|
||||
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_NUL_IN_COMMIT,
|
||||
"NUL byte in the commit object body");
|
||||
if (err)
|
||||
return err;
|
||||
@ -814,91 +820,60 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_commit(struct commit *commit, const char *data,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
static int fsck_tag(const struct object_id *oid, const char *buffer,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
{
|
||||
const char *buffer = data ? data : get_commit_buffer(commit, &size);
|
||||
int ret = fsck_commit_buffer(commit, buffer, size, options);
|
||||
if (!data)
|
||||
unuse_commit_buffer(commit, buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsck_tag_buffer(struct tag *tag, const char *data,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
{
|
||||
struct object_id oid;
|
||||
struct object_id tagged_oid;
|
||||
int ret = 0;
|
||||
const char *buffer;
|
||||
char *to_free = NULL, *eol;
|
||||
char *eol;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *p;
|
||||
|
||||
if (data)
|
||||
buffer = data;
|
||||
else {
|
||||
enum object_type type;
|
||||
|
||||
buffer = to_free =
|
||||
read_object_file(&tag->object.oid, &type, &size);
|
||||
if (!buffer)
|
||||
return report(options, &tag->object,
|
||||
FSCK_MSG_MISSING_TAG_OBJECT,
|
||||
"cannot read tag object");
|
||||
|
||||
if (type != OBJ_TAG) {
|
||||
ret = report(options, &tag->object,
|
||||
FSCK_MSG_TAG_OBJECT_NOT_TAG,
|
||||
"expected tag got %s",
|
||||
type_name(type));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = verify_headers(buffer, size, &tag->object, options);
|
||||
ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
if (!skip_prefix(buffer, "object ", &buffer)) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
|
||||
goto done;
|
||||
}
|
||||
if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
|
||||
ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
|
||||
if (parse_oid_hex(buffer, &tagged_oid, &p) || *p != '\n') {
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
buffer = p + 1;
|
||||
|
||||
if (!skip_prefix(buffer, "type ", &buffer)) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
|
||||
goto done;
|
||||
}
|
||||
eol = strchr(buffer, '\n');
|
||||
if (!eol) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
|
||||
goto done;
|
||||
}
|
||||
if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
|
||||
ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
|
||||
if (ret)
|
||||
goto done;
|
||||
buffer = eol + 1;
|
||||
|
||||
if (!skip_prefix(buffer, "tag ", &buffer)) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
|
||||
goto done;
|
||||
}
|
||||
eol = strchr(buffer, '\n');
|
||||
if (!eol) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "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)) {
|
||||
ret = report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME,
|
||||
"invalid 'tag' name: %.*s",
|
||||
(int)(eol - buffer), buffer);
|
||||
ret = report(options, oid, OBJ_TAG,
|
||||
FSCK_MSG_BAD_TAG_NAME,
|
||||
"invalid 'tag' name: %.*s",
|
||||
(int)(eol - buffer), buffer);
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
@ -906,32 +881,20 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
|
||||
|
||||
if (!skip_prefix(buffer, "tagger ", &buffer)) {
|
||||
/* early tags do not contain 'tagger' lines; warn only */
|
||||
ret = report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
|
||||
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
ret = fsck_ident(&buffer, &tag->object, options);
|
||||
ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
|
||||
|
||||
done:
|
||||
strbuf_release(&sb);
|
||||
free(to_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsck_tag(struct tag *tag, const char *data,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
{
|
||||
struct object *tagged = tag->tagged;
|
||||
|
||||
if (!tagged)
|
||||
return report(options, &tag->object, FSCK_MSG_BAD_TAG_OBJECT, "could not load tagged object");
|
||||
|
||||
return fsck_tag_buffer(tag, data, size, options);
|
||||
}
|
||||
|
||||
struct fsck_gitmodules_data {
|
||||
struct object *obj;
|
||||
const struct object_id *oid;
|
||||
struct fsck_options *options;
|
||||
int ret;
|
||||
};
|
||||
@ -949,19 +912,22 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
|
||||
|
||||
name = xmemdupz(subsection, subsection_len);
|
||||
if (check_submodule_name(name) < 0)
|
||||
data->ret |= report(data->options, data->obj,
|
||||
data->ret |= report(data->options,
|
||||
data->oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_NAME,
|
||||
"disallowed submodule name: %s",
|
||||
name);
|
||||
if (!strcmp(key, "url") && value &&
|
||||
looks_like_command_line_option(value))
|
||||
data->ret |= report(data->options, data->obj,
|
||||
data->ret |= report(data->options,
|
||||
data->oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_URL,
|
||||
"disallowed submodule url: %s",
|
||||
value);
|
||||
if (!strcmp(key, "path") && value &&
|
||||
looks_like_command_line_option(value))
|
||||
data->ret |= report(data->options, data->obj,
|
||||
data->ret |= report(data->options,
|
||||
data->oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_PATH,
|
||||
"disallowed submodule path: %s",
|
||||
value);
|
||||
@ -970,17 +936,17 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_blob(struct blob *blob, const char *buf,
|
||||
static int fsck_blob(const struct object_id *oid, const char *buf,
|
||||
unsigned long size, struct fsck_options *options)
|
||||
{
|
||||
struct fsck_gitmodules_data data;
|
||||
struct config_options config_opts = { 0 };
|
||||
|
||||
if (!oidset_contains(&gitmodules_found, &blob->object.oid))
|
||||
if (!oidset_contains(&gitmodules_found, oid))
|
||||
return 0;
|
||||
oidset_insert(&gitmodules_done, &blob->object.oid);
|
||||
oidset_insert(&gitmodules_done, oid);
|
||||
|
||||
if (object_on_skiplist(options, &blob->object))
|
||||
if (object_on_skiplist(options, oid))
|
||||
return 0;
|
||||
|
||||
if (!buf) {
|
||||
@ -989,18 +955,18 @@ static int fsck_blob(struct blob *blob, const char *buf,
|
||||
* blob too gigantic to load into memory. Let's just consider
|
||||
* that an error.
|
||||
*/
|
||||
return report(options, &blob->object,
|
||||
return report(options, oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_LARGE,
|
||||
".gitmodules too large to parse");
|
||||
}
|
||||
|
||||
data.obj = &blob->object;
|
||||
data.oid = oid;
|
||||
data.options = options;
|
||||
data.ret = 0;
|
||||
config_opts.error_action = CONFIG_ERROR_SILENT;
|
||||
if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
|
||||
".gitmodules", buf, size, &data, &config_opts))
|
||||
data.ret |= report(options, &blob->object,
|
||||
data.ret |= report(options, oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_PARSE,
|
||||
"could not parse gitmodules blob");
|
||||
|
||||
@ -1011,31 +977,33 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
|
||||
struct fsck_options *options)
|
||||
{
|
||||
if (!obj)
|
||||
return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
|
||||
return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
|
||||
|
||||
if (obj->type == OBJ_BLOB)
|
||||
return fsck_blob((struct blob *)obj, data, size, options);
|
||||
return fsck_blob(&obj->oid, data, size, options);
|
||||
if (obj->type == OBJ_TREE)
|
||||
return fsck_tree((struct tree *) obj, options);
|
||||
return fsck_tree(&obj->oid, data, size, options);
|
||||
if (obj->type == OBJ_COMMIT)
|
||||
return fsck_commit((struct commit *) obj, (const char *) data,
|
||||
size, options);
|
||||
return fsck_commit(&obj->oid, data, size, options);
|
||||
if (obj->type == OBJ_TAG)
|
||||
return fsck_tag((struct tag *) obj, (const char *) data,
|
||||
size, options);
|
||||
return fsck_tag(&obj->oid, data, size, options);
|
||||
|
||||
return report(options, obj, FSCK_MSG_UNKNOWN_TYPE, "unknown type '%d' (internal fsck error)",
|
||||
obj->type);
|
||||
return report(options, &obj->oid, obj->type,
|
||||
FSCK_MSG_UNKNOWN_TYPE,
|
||||
"unknown type '%d' (internal fsck error)",
|
||||
obj->type);
|
||||
}
|
||||
|
||||
int fsck_error_function(struct fsck_options *o,
|
||||
struct object *obj, int msg_type, const char *message)
|
||||
const struct object_id *oid,
|
||||
enum object_type object_type,
|
||||
int msg_type, const char *message)
|
||||
{
|
||||
if (msg_type == FSCK_WARN) {
|
||||
warning("object %s: %s", describe_object(o, obj), message);
|
||||
warning("object %s: %s", fsck_describe_object(o, oid), message);
|
||||
return 0;
|
||||
}
|
||||
error("object %s: %s", describe_object(o, obj), message);
|
||||
error("object %s: %s", fsck_describe_object(o, oid), message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1047,7 +1015,6 @@ int fsck_finish(struct fsck_options *options)
|
||||
|
||||
oidset_iter_init(&gitmodules_found, &iter);
|
||||
while ((oid = oidset_iter_next(&iter))) {
|
||||
struct blob *blob;
|
||||
enum object_type type;
|
||||
unsigned long size;
|
||||
char *buf;
|
||||
@ -1055,29 +1022,22 @@ int fsck_finish(struct fsck_options *options)
|
||||
if (oidset_contains(&gitmodules_done, oid))
|
||||
continue;
|
||||
|
||||
blob = lookup_blob(the_repository, oid);
|
||||
if (!blob) {
|
||||
struct object *obj = lookup_unknown_object(oid);
|
||||
ret |= report(options, obj,
|
||||
FSCK_MSG_GITMODULES_BLOB,
|
||||
"non-blob found at .gitmodules");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf = read_object_file(oid, &type, &size);
|
||||
if (!buf) {
|
||||
if (is_promisor_object(&blob->object.oid))
|
||||
if (is_promisor_object(oid))
|
||||
continue;
|
||||
ret |= report(options, &blob->object,
|
||||
ret |= report(options,
|
||||
oid, OBJ_BLOB,
|
||||
FSCK_MSG_GITMODULES_MISSING,
|
||||
"unable to read .gitmodules blob");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == OBJ_BLOB)
|
||||
ret |= fsck_blob(blob, buf, size, options);
|
||||
ret |= fsck_blob(oid, buf, size, options);
|
||||
else
|
||||
ret |= report(options, &blob->object,
|
||||
ret |= report(options,
|
||||
oid, type,
|
||||
FSCK_MSG_GITMODULES_BLOB,
|
||||
"non-blob found at .gitmodules");
|
||||
free(buf);
|
||||
|
39
fsck.h
39
fsck.h
@ -27,10 +27,12 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data, struct f
|
||||
|
||||
/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
|
||||
typedef int (*fsck_error)(struct fsck_options *o,
|
||||
struct object *obj, int type, const char *message);
|
||||
const struct object_id *oid, enum object_type object_type,
|
||||
int msg_type, const char *message);
|
||||
|
||||
int fsck_error_function(struct fsck_options *o,
|
||||
struct object *obj, int type, const char *message);
|
||||
const struct object_id *oid, enum object_type object_type,
|
||||
int msg_type, const char *message);
|
||||
|
||||
struct fsck_options {
|
||||
fsck_walk_func walk;
|
||||
@ -38,7 +40,7 @@ struct fsck_options {
|
||||
unsigned strict:1;
|
||||
int *msg_type;
|
||||
struct oidset skiplist;
|
||||
struct decoration *object_names;
|
||||
kh_oid_map_t *object_names;
|
||||
};
|
||||
|
||||
#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL, OIDSET_INIT }
|
||||
@ -52,7 +54,11 @@ struct fsck_options {
|
||||
* 0 everything OK
|
||||
*/
|
||||
int fsck_walk(struct object *obj, void *data, struct fsck_options *options);
|
||||
/* If NULL is passed for data, we assume the object is local and read it. */
|
||||
|
||||
/*
|
||||
* Blob objects my pass a NULL data pointer, which indicates they are too large
|
||||
* to fit in memory. All other types must pass a real buffer.
|
||||
*/
|
||||
int fsck_object(struct object *obj, void *data, unsigned long size,
|
||||
struct fsck_options *options);
|
||||
|
||||
@ -63,4 +69,29 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
|
||||
*/
|
||||
int fsck_finish(struct fsck_options *options);
|
||||
|
||||
/*
|
||||
* Subsystem for storing human-readable names for each object.
|
||||
*
|
||||
* If fsck_enable_object_names() has not been called, all other functions are
|
||||
* noops.
|
||||
*
|
||||
* Use fsck_put_object_name() to seed initial names (e.g. from refnames); the
|
||||
* fsck code will extend that while walking trees, etc.
|
||||
*
|
||||
* Use fsck_get_object_name() to get a single name (or NULL if none). Or the
|
||||
* more convenient describe_object(), which always produces an output string
|
||||
* with the oid combined with the name (if any). Note that the return value
|
||||
* points to a rotating array of static buffers, and may be invalidated by a
|
||||
* subsequent call.
|
||||
*/
|
||||
void fsck_enable_object_names(struct fsck_options *options);
|
||||
const char *fsck_get_object_name(struct fsck_options *options,
|
||||
const struct object_id *oid);
|
||||
__attribute__((format (printf,3,4)))
|
||||
void fsck_put_object_name(struct fsck_options *options,
|
||||
const struct object_id *oid,
|
||||
const char *fmt, ...);
|
||||
const char *fsck_describe_object(struct fsck_options *options,
|
||||
const struct object_id *oid);
|
||||
|
||||
#endif
|
||||
|
@ -616,7 +616,7 @@ test_expect_success 'fsck --name-objects' '
|
||||
remove_object $(git rev-parse julius:caesar.t) &&
|
||||
test_must_fail git fsck --name-objects >out &&
|
||||
tree=$(git rev-parse --verify julius:) &&
|
||||
test_i18ngrep -E "$tree \((refs/heads/master|HEAD)@\{[0-9]*\}:" out
|
||||
test_i18ngrep "$tree (refs/tags/julius:" out
|
||||
)
|
||||
'
|
||||
|
||||
|
@ -660,7 +660,7 @@ test_expect_success 'corrupt commit-graph write (missing tree)' '
|
||||
git commit-tree -p "$broken" -m "good" "$tree" >good &&
|
||||
test_must_fail git commit-graph write --stdin-commits \
|
||||
<good 2>test_err &&
|
||||
test_i18ngrep "unable to get tree for" test_err
|
||||
test_i18ngrep "unable to parse commit" test_err
|
||||
)
|
||||
'
|
||||
|
||||
|
@ -52,7 +52,7 @@ test_expect_success 'traverse unexpected non-commit parent (lone)' '
|
||||
'
|
||||
|
||||
test_expect_success 'traverse unexpected non-commit parent (seen)' '
|
||||
test_must_fail git rev-list --objects $commit $broken_commit \
|
||||
test_must_fail git rev-list --objects $blob $broken_commit \
|
||||
>output 2>&1 &&
|
||||
test_i18ngrep "not a commit" output
|
||||
'
|
||||
|
21
tag.c
21
tag.c
@ -141,7 +141,16 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
|
||||
|
||||
if (item->object.parsed)
|
||||
return 0;
|
||||
item->object.parsed = 1;
|
||||
|
||||
if (item->tag) {
|
||||
/*
|
||||
* Presumably left over from a previous failed parse;
|
||||
* clear it out in preparation for re-parsing (we'll probably
|
||||
* hit the same error, which lets us tell our current caller
|
||||
* about the problem).
|
||||
*/
|
||||
FREE_AND_NULL(item->tag);
|
||||
}
|
||||
|
||||
if (size < the_hash_algo->hexsz + 24)
|
||||
return -1;
|
||||
@ -167,10 +176,15 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
|
||||
} else if (!strcmp(type, tag_type)) {
|
||||
item->tagged = (struct object *)lookup_tag(r, &oid);
|
||||
} else {
|
||||
error("Unknown type %s", type);
|
||||
item->tagged = NULL;
|
||||
return error("unknown tag type '%s' in %s",
|
||||
type, oid_to_hex(&item->object.oid));
|
||||
}
|
||||
|
||||
if (!item->tagged)
|
||||
return error("bad tag pointer to %s in %s",
|
||||
oid_to_hex(&oid),
|
||||
oid_to_hex(&item->object.oid));
|
||||
|
||||
if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
|
||||
; /* good */
|
||||
else
|
||||
@ -187,6 +201,7 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
|
||||
else
|
||||
item->date = 0;
|
||||
|
||||
item->object.parsed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user