From 10a6762719f612bb5edc554e62239a744bbc4283 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Feb 2026 17:00:07 +0100 Subject: [PATCH] object-file: adapt `stream_object_signature()` to take a stream The function `stream_object_signature()` is responsible for verifying whether the given object ID matches the actual hash of the object's contents. In contrast to `check_object_signature()` it does so in a streaming fashion so that we don't have to load the full object into memory. In a subsequent commit we'll want to adapt one of its callsites to pass a preconstructed stream. Prepare for this by accepting a stream as input that the caller needs to assemble. While at it, improve the error reporting in `parse_object_with_flags()` to tell apart the two failure modes. Helped-by: Jeff King Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-file.c | 10 +++------- object-file.h | 4 +++- object.c | 19 ++++++++++++++++--- pack-check.c | 12 +++++++++--- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/object-file.c b/object-file.c index e7e4c3348f..a59b7abaaf 100644 --- a/object-file.c +++ b/object-file.c @@ -129,18 +129,15 @@ int check_object_signature(struct repository *r, const struct object_id *oid, return !oideq(oid, &real_oid) ? -1 : 0; } -int stream_object_signature(struct repository *r, const struct object_id *oid) +int stream_object_signature(struct repository *r, + struct odb_read_stream *st, + const struct object_id *oid) { struct object_id real_oid; - struct odb_read_stream *st; struct git_hash_ctx c; char hdr[MAX_HEADER_LEN]; int hdrlen; - st = odb_read_stream_open(r->objects, oid, NULL); - if (!st) - return -1; - /* Generate the header */ hdrlen = format_object_header(hdr, sizeof(hdr), st->type, st->size); @@ -160,7 +157,6 @@ int stream_object_signature(struct repository *r, const struct object_id *oid) git_hash_update(&c, buf, readlen); } git_hash_final_oid(&real_oid, &c); - odb_read_stream_close(st); return !oideq(oid, &real_oid) ? -1 : 0; } diff --git a/object-file.h b/object-file.h index 1229d5f675..6936fd0fef 100644 --- a/object-file.h +++ b/object-file.h @@ -164,7 +164,9 @@ int check_object_signature(struct repository *r, const struct object_id *oid, * 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 stream_object_signature(struct repository *r, + struct odb_read_stream *stream, + const struct object_id *oid); enum finalize_object_file_flags { FOF_SKIP_COLLISION_CHECK = 1, diff --git a/object.c b/object.c index 4669b8d65e..9d2c676b16 100644 --- a/object.c +++ b/object.c @@ -6,6 +6,7 @@ #include "object.h" #include "replace-object.h" #include "object-file.h" +#include "odb/streaming.h" #include "blob.h" #include "statinfo.h" #include "tree.h" @@ -330,9 +331,21 @@ struct object *parse_object_with_flags(struct repository *r, if ((!obj || obj->type == OBJ_NONE || obj->type == OBJ_BLOB) && odb_read_object_info(r->objects, oid, NULL) == OBJ_BLOB) { - if (!skip_hash && stream_object_signature(r, repl) < 0) { - error(_("hash mismatch %s"), oid_to_hex(oid)); - return NULL; + if (!skip_hash) { + struct odb_read_stream *stream = odb_read_stream_open(r->objects, oid, NULL); + + if (!stream) { + error(_("unable to open object stream for %s"), oid_to_hex(oid)); + return NULL; + } + + if (stream_object_signature(r, stream, repl) < 0) { + error(_("hash mismatch %s"), oid_to_hex(oid)); + odb_read_stream_close(stream); + return NULL; + } + + odb_read_stream_close(stream); } parse_blob_buffer(lookup_blob(r, oid)); return lookup_object(r, oid); diff --git a/pack-check.c b/pack-check.c index 67cb2cf72f..46782a29d5 100644 --- a/pack-check.c +++ b/pack-check.c @@ -9,6 +9,7 @@ #include "packfile.h" #include "object-file.h" #include "odb.h" +#include "odb/streaming.h" struct idx_entry { off_t offset; @@ -104,6 +105,7 @@ static int verify_packfile(struct repository *r, QSORT(entries, nr_objects, compare_entries); for (i = 0; i < nr_objects; i++) { + struct odb_read_stream *stream = NULL; void *data; struct object_id oid; enum object_type type; @@ -152,7 +154,9 @@ static int verify_packfile(struct repository *r, 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) + else if (!data && + (!(stream = odb_read_stream_open(r->objects, &oid, NULL)) || + stream_object_signature(r, stream, &oid) < 0)) err = error("packed %s from %s is corrupt", oid_to_hex(&oid), p->pack_name); else if (fn) { @@ -163,12 +167,14 @@ static int verify_packfile(struct repository *r, } if (((base_count + i) & 1023) == 0) display_progress(progress, base_count + i); - free(data); + if (stream) + odb_read_stream_close(stream); + free(data); } + display_progress(progress, base_count + i); free(entries); - return err; }