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 <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Feb 23, 2026 at 17:00 UTC 10a6762719f612bb5edc554e62239a744bbc4283
4 files changed +31 -14
object-file.c
+3 -7
@@ -129,18 +129,15 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
129 return !oideq(oid, &real_oid) ? -1 : 0;
130 }
131
132 -int stream_object_signature(struct repository *r, const struct object_id *oid)
132 +int stream_object_signature(struct repository *r,
133 + struct odb_read_stream *st,
134 + const struct object_id *oid)
135 {
136 struct object_id real_oid;
135 - struct odb_read_stream *st;
137 struct git_hash_ctx c;
138 char hdr[MAX_HEADER_LEN];
139 int hdrlen;
140
140 - st = odb_read_stream_open(r->objects, oid, NULL);
141 - if (!st)
142 - return -1;
143 -
141 /* Generate the header */
142 hdrlen = format_object_header(hdr, sizeof(hdr), st->type, st->size);
143
@@ -160,7 +157,6 @@ int stream_object_signature(struct repository *r, const struct object_id *oid)
157 git_hash_update(&c, buf, readlen);
158 }
159 git_hash_final_oid(&real_oid, &c);
163 - odb_read_stream_close(st);
160 return !oideq(oid, &real_oid) ? -1 : 0;
161 }
162
object-file.h
+3 -1
@@ -164,7 +164,9 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
164 * Try reading the object named with "oid" using
165 * the streaming interface and rehash it to do the same.
166 */
167 -int stream_object_signature(struct repository *r, const struct object_id *oid);
167 +int stream_object_signature(struct repository *r,
168 + struct odb_read_stream *stream,
169 + const struct object_id *oid);
170
171 enum finalize_object_file_flags {
172 FOF_SKIP_COLLISION_CHECK = 1,
object.c
+16 -3
@@ -6,6 +6,7 @@
6 #include "object.h"
7 #include "replace-object.h"
8 #include "object-file.h"
9 +#include "odb/streaming.h"
10 #include "blob.h"
11 #include "statinfo.h"
12 #include "tree.h"
@@ -330,9 +331,21 @@ struct object *parse_object_with_flags(struct repository *r,
331
332 if ((!obj || obj->type == OBJ_NONE || obj->type == OBJ_BLOB) &&
333 odb_read_object_info(r->objects, oid, NULL) == OBJ_BLOB) {
333 - if (!skip_hash && stream_object_signature(r, repl) < 0) {
334 - error(_("hash mismatch %s"), oid_to_hex(oid));
335 - return NULL;
334 + if (!skip_hash) {
335 + struct odb_read_stream *stream = odb_read_stream_open(r->objects, oid, NULL);
336 +
337 + if (!stream) {
338 + error(_("unable to open object stream for %s"), oid_to_hex(oid));
339 + return NULL;
340 + }
341 +
342 + if (stream_object_signature(r, stream, repl) < 0) {
343 + error(_("hash mismatch %s"), oid_to_hex(oid));
344 + odb_read_stream_close(stream);
345 + return NULL;
346 + }
347 +
348 + odb_read_stream_close(stream);
349 }
350 parse_blob_buffer(lookup_blob(r, oid));
351 return lookup_object(r, oid);
pack-check.c
+9 -3
@@ -9,6 +9,7 @@
9 #include "packfile.h"
10 #include "object-file.h"
11 #include "odb.h"
12 +#include "odb/streaming.h"
13
14 struct idx_entry {
15 off_t offset;
@@ -104,6 +105,7 @@ static int verify_packfile(struct repository *r,
105 QSORT(entries, nr_objects, compare_entries);
106
107 for (i = 0; i < nr_objects; i++) {
108 + struct odb_read_stream *stream = NULL;
109 void *data;
110 struct object_id oid;
111 enum object_type type;
@@ -152,7 +154,9 @@ static int verify_packfile(struct repository *r,
154 type) < 0)
155 err = error("packed %s from %s is corrupt",
156 oid_to_hex(&oid), p->pack_name);
155 - else if (!data && stream_object_signature(r, &oid) < 0)
157 + else if (!data &&
158 + (!(stream = odb_read_stream_open(r->objects, &oid, NULL)) ||
159 + stream_object_signature(r, stream, &oid) < 0))
160 err = error("packed %s from %s is corrupt",
161 oid_to_hex(&oid), p->pack_name);
162 else if (fn) {
@@ -163,12 +167,14 @@ static int verify_packfile(struct repository *r,
167 }
168 if (((base_count + i) & 1023) == 0)
169 display_progress(progress, base_count + i);
166 - free(data);
170
171 + if (stream)
172 + odb_read_stream_close(stream);
173 + free(data);
174 }
175 +
176 display_progress(progress, base_count + i);
177 free(entries);
171 -
178 return err;
179 }
180