odb: update `struct odb_write_stream` read() callback
The `read()` callback used by `struct odb_write_stream` currently returns a pointer to an internal buffer along with the number of bytes read. This makes buffer ownership unclear and provides no way to report errors. Update the interface to instead require the caller to provide a buffer, and have the callback return the number of bytes written to it or a negative value on error. While at it, also move the `struct odb_write_stream` definition to "odb/streaming.h". Call sites are updated accordingly. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Justin Tobler committed
May 14, 2026 at 13:37 UTC
970f63519e494b590c807972af6c40477e14bc61
5 files changed
+44
-20
builtin/unpack-objects.c
+8
-12
@@ -9,6 +9,7 @@
9
#include "hex.h"
10
#include "object-file.h"
11
#include "odb.h"
12
+#include "odb/streaming.h"
13
#include "odb/transaction.h"
14
#include "object.h"
15
#include "delta.h"
@@ -360,24 +361,21 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
361
362
struct input_zstream_data {
363
git_zstream *zstream;
363
- unsigned char buf[8192];
364
int status;
365
};
366
367
-static const void *feed_input_zstream(struct odb_write_stream *in_stream,
368
- unsigned long *readlen)
367
+static ssize_t feed_input_zstream(struct odb_write_stream *in_stream,
368
+ unsigned char *buf, size_t buf_len)
369
{
370
struct input_zstream_data *data = in_stream->data;
371
git_zstream *zstream = data->zstream;
372
void *in = fill(1);
373
374
- if (in_stream->is_finished) {
375
- *readlen = 0;
376
- return NULL;
377
- }
374
+ if (in_stream->is_finished)
375
+ return 0;
376
379
- zstream->next_out = data->buf;
380
- zstream->avail_out = sizeof(data->buf);
377
+ zstream->next_out = buf;
378
+ zstream->avail_out = buf_len;
379
zstream->next_in = in;
380
zstream->avail_in = len;
381
@@ -385,9 +383,7 @@ static const void *feed_input_zstream(struct odb_write_stream *in_stream,
383
384
in_stream->is_finished = data->status != Z_OK;
385
use(len - zstream->avail_in);
388
- *readlen = sizeof(data->buf) - zstream->avail_out;
389
-
390
- return data->buf;
386
+ return buf_len - zstream->avail_out;
387
}
388
389
static void stream_blob(unsigned long size, unsigned nr)
object-file.c
+12
-3
@@ -1066,6 +1066,7 @@ int odb_source_loose_write_stream(struct odb_source *source,
1066
struct git_hash_ctx c, compat_c;
1067
struct strbuf tmp_file = STRBUF_INIT;
1068
struct strbuf filename = STRBUF_INIT;
1069
+ unsigned char buf[8192];
1070
int dirlen;
1071
char hdr[MAX_HEADER_LEN];
1072
int hdrlen;
@@ -1098,9 +1099,17 @@ int odb_source_loose_write_stream(struct odb_source *source,
1099
unsigned char *in0 = stream.next_in;
1100
1101
if (!stream.avail_in && !in_stream->is_finished) {
1101
- const void *in = in_stream->read(in_stream, &stream.avail_in);
1102
- stream.next_in = (void *)in;
1103
- in0 = (unsigned char *)in;
1102
+ ssize_t read_len = odb_write_stream_read(in_stream, buf,
1103
+ sizeof(buf));
1104
+ if (read_len < 0) {
1105
+ close(fd);
1106
+ err = -1;
1107
+ goto cleanup;
1108
+ }
1109
+
1110
+ stream.avail_in = read_len;
1111
+ stream.next_in = buf;
1112
+ in0 = buf;
1113
/* All data has been read. */
1114
if (in_stream->is_finished)
1115
flush = 1;
odb.h
+1
-5
@@ -529,11 +529,7 @@ static inline int odb_write_object(struct object_database *odb,
529
return odb_write_object_ext(odb, buf, len, type, oid, NULL, 0);
530
}
531
532
-struct odb_write_stream {
533
- const void *(*read)(struct odb_write_stream *, unsigned long *len);
534
- void *data;
535
- int is_finished;
536
-};
532
+struct odb_write_stream;
533
534
int odb_write_object_stream(struct object_database *odb,
535
struct odb_write_stream *stream, size_t len,
odb/streaming.c
+5
@@ -232,6 +232,11 @@ struct odb_read_stream *odb_read_stream_open(struct object_database *odb,
232
return st;
233
}
234
235
+ssize_t odb_write_stream_read(struct odb_write_stream *st, void *buf, size_t sz)
236
+{
237
+ return st->read(st, buf, sz);
238
+}
239
+
240
int odb_stream_blob_to_fd(struct object_database *odb,
241
int fd,
242
const struct object_id *oid,
odb/streaming.h
+18
@@ -47,6 +47,24 @@ int odb_read_stream_close(struct odb_read_stream *stream);
47
*/
48
ssize_t odb_read_stream_read(struct odb_read_stream *stream, void *buf, size_t len);
49
50
+/*
51
+ * A stream that provides an object to be written to the object database without
52
+ * loading all of it into memory.
53
+ */
54
+struct odb_write_stream {
55
+ ssize_t (*read)(struct odb_write_stream *, unsigned char *, size_t);
56
+ void *data;
57
+ int is_finished;
58
+};
59
+
60
+/*
61
+ * Read data from the stream into the buffer. Returns 0 when finished and the
62
+ * number of bytes read on success. Returns a negative error code in case
63
+ * reading from the stream fails.
64
+ */
65
+ssize_t odb_write_stream_read(struct odb_write_stream *stream, void *buf,
66
+ size_t len);
67
+
68
/*
69
* Look up the object by its ID and write the full contents to the file
70
* descriptor. The object must be a blob, or the function will fail. When