object-file API: split up and simplify check_object_signature()

Split up the check_object_signature() function into that non-streaming
version (it accepts an already filled "buf"), and a new
stream_object_signature() which will retrieve the object from storage,
and hash it on-the-fly.

All of the callers of check_object_signature() were effectively
calling two different functions, if we go by cyclomatic
complexity. I.e. they'd either take the early "if (map)" branch and
return early, or not. This has been the case since the "if (map)"
condition was added in 090ea12671 (parse_object: avoid putting whole
blob in core, 2012-03-07).

We can then further simplify the resulting check_object_signature()
function since only one caller wanted to pass a non-NULL "buf" and a
non-NULL "real_oidp". That "read_loose_object()" codepath used by "git
fsck" can instead use hash_object_file() followed by oideq().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ævar Arnfjörð Bjarmason 2022-02-05 00:48:30 +01:00 коммит произвёл Junio C Hamano
Родитель ee213de22d
Коммит 0f156dbb04
7 изменённых файлов: 38 добавлений и 28 удалений

Просмотреть файл

@ -300,7 +300,7 @@ static void export_blob(const struct object_id *oid)
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
type_name(type), NULL) < 0)
type_name(type)) < 0)
die("oid mismatch in blob %s", oid_to_hex(oid));
object = parse_object_buffer(the_repository, oid, type,
size, buf, &eaten);

Просмотреть файл

@ -1413,7 +1413,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
continue;
if (check_object_signature(the_repository, &d->oid, data, size,
type_name(type), NULL) < 0)
type_name(type)) < 0)
die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
/*

Просмотреть файл

@ -61,9 +61,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
type_name(*tagged_type), type_name(type));
repl = lookup_replace_object(the_repository, tagged_oid);
ret = check_object_signature(the_repository, repl,
buffer, size, type_name(*tagged_type),
NULL);
ret = check_object_signature(the_repository, repl, buffer, size,
type_name(*tagged_type));
free(buffer);
return ret;

12
cache.h
Просмотреть файл

@ -1322,15 +1322,19 @@ int parse_loose_header(const char *hdr, struct object_info *oi);
/**
* With in-core object data in "buf", rehash it to make sure the
* object name actually matches "oid" to detect object corruption.
* With "buf" == NULL, try reading the object named with "oid" using
* the streaming interface and rehash it to do the same.
*
* A negative value indicates an error, usually that the OID is not
* what we expected, but it might also indicate another error.
*/
int check_object_signature(struct repository *r, const struct object_id *oid,
void *buf, unsigned long size, const char *type,
struct object_id *real_oidp);
void *buf, unsigned long size, const char *type);
/**
* A streaming version of check_object_signature().
* Try reading the object named with "oid" using
* the streaming interface and rehash it to do the same.
*/
int stream_object_signature(struct repository *r, const struct object_id *oid);
int finalize_object_file(const char *tmpfile, const char *filename);

Просмотреть файл

@ -1067,22 +1067,25 @@ int format_object_header(char *str, size_t size, enum object_type type,
}
int check_object_signature(struct repository *r, const struct object_id *oid,
void *buf, unsigned long size, const char *type,
struct object_id *real_oidp)
void *buf, unsigned long size, const char *type)
{
struct object_id tmp;
struct object_id *real_oid = real_oidp ? real_oidp : &tmp;
struct object_id real_oid;
hash_object_file(r->hash_algo, buf, size, type, &real_oid);
return !oideq(oid, &real_oid) ? -1 : 0;
}
int stream_object_signature(struct repository *r, const struct object_id *oid)
{
struct object_id real_oid;
unsigned long size;
enum object_type obj_type;
struct git_istream *st;
git_hash_ctx c;
char hdr[MAX_HEADER_LEN];
int hdrlen;
if (buf) {
hash_object_file(r->hash_algo, buf, size, type, real_oid);
return !oideq(oid, real_oid) ? -1 : 0;
}
st = open_istream(r, oid, &obj_type, &size, NULL);
if (!st)
return -1;
@ -1105,9 +1108,9 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
break;
r->hash_algo->update_fn(&c, buf, readlen);
}
r->hash_algo->final_oid_fn(real_oid, &c);
r->hash_algo->final_oid_fn(&real_oid, &c);
close_istream(st);
return !oideq(oid, real_oid) ? -1 : 0;
return !oideq(oid, &real_oid) ? -1 : 0;
}
int git_open_cloexec(const char *name, int flags)
@ -2611,9 +2614,10 @@ int read_loose_object(const char *path,
git_inflate_end(&stream);
goto out;
}
if (check_object_signature(the_repository, expected_oid,
*contents, *size,
oi->type_name->buf, real_oid) < 0)
hash_object_file(the_repository->hash_algo,
*contents, *size, oi->type_name->buf,
real_oid);
if (!oideq(expected_oid, real_oid))
goto out;
}

Просмотреть файл

@ -279,7 +279,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
if ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||
(!obj && repo_has_object_file(r, oid) &&
oid_object_info(r, oid, NULL) == OBJ_BLOB)) {
if (check_object_signature(r, repl, NULL, 0, NULL, NULL) < 0) {
if (stream_object_signature(r, repl) < 0) {
error(_("hash mismatch %s"), oid_to_hex(oid));
return NULL;
}
@ -290,7 +290,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
buffer = repo_read_object_file(r, oid, &type, &size);
if (buffer) {
if (check_object_signature(r, repl, buffer, size,
type_name(type), NULL) < 0) {
type_name(type)) < 0) {
free(buffer);
error(_("hash mismatch %s"), oid_to_hex(repl));
return NULL;

Просмотреть файл

@ -127,7 +127,7 @@ static int verify_packfile(struct repository *r,
if (type == OBJ_BLOB && big_file_threshold <= size) {
/*
* Let check_object_signature() check it with
* Let stream_object_signature() check it with
* the streaming interface; no point slurping
* the data in-core only to discard.
*/
@ -142,8 +142,11 @@ static int verify_packfile(struct repository *r,
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
oid_to_hex(&oid), p->pack_name,
(uintmax_t)entries[i].offset);
else if (check_object_signature(r, &oid, data, size,
type_name(type), NULL) < 0)
else if (data && check_object_signature(r, &oid, data, size,
type_name(type)) < 0)
err = error("packed %s from %s is corrupt",
oid_to_hex(&oid), p->pack_name);
else if (!data && stream_object_signature(r, &oid) < 0)
err = error("packed %s from %s is corrupt",
oid_to_hex(&oid), p->pack_name);
else if (fn) {