Signed-off-by: Christian Couder <[email protected]>
---
odb-helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 78 insertions(+), 6 deletions(-)
diff --git a/odb-helper.c b/odb-helper.c
index 0017faa36e..a27208463c 100644
--- a/odb-helper.c
+++ b/odb-helper.c
@@ -142,6 +142,82 @@ static int check_object_process_error(int err,
return err;
}
+static ssize_t read_packetized_git_object_to_fd(struct odb_helper *o,
+ const unsigned char *sha1,
+ int fd_in, int fd_out)
+{
+ ssize_t total_read = 0;
+ unsigned long total_got = 0;
+ int packet_len;
+ git_zstream stream;
+ int zret = Z_STREAM_END;
+ git_SHA_CTX hash;
+ unsigned char real_sha1[20];
+
+ memset(&stream, 0, sizeof(stream));
+ git_inflate_init(&stream);
+ git_SHA1_Init(&hash);
+
+ for (;;) {
+ /* packet_read() writes a '\0' extra byte at the end */
+ char buf[LARGE_PACKET_DATA_MAX + 1];
+
+ packet_len = packet_read(fd_in, NULL, NULL,
+ buf, LARGE_PACKET_DATA_MAX + 1,
+ PACKET_READ_GENTLE_ON_EOF);
+
+ if (packet_len <= 0)
+ break;
+
+ write_or_die(fd_out, buf, packet_len);
+
+ stream.next_in = (unsigned char *)buf;
+ stream.avail_in = packet_len;
+ do {
+ unsigned char inflated[4096];
+ unsigned long got;
+
+ stream.next_out = inflated;
+ stream.avail_out = sizeof(inflated);
+ zret = git_inflate(&stream, Z_SYNC_FLUSH);
+ got = sizeof(inflated) - stream.avail_out;
+
+ git_SHA1_Update(&hash, inflated, got);
+ /* skip header when counting size */
+ if (!total_got) {
+ const unsigned char *p = memchr(inflated, '\0',
got);
+ if (p)
+ got -= p - inflated + 1;
+ else
+ got = 0;
+ }
+ total_got += got;
+ } while (stream.avail_in && zret == Z_OK);
+
+ total_read += packet_len;
+ }
+
+ git_inflate_end(&stream);
+
+ if (packet_len < 0)
+ return packet_len;
+
+ git_SHA1_Final(real_sha1, &hash);
+
+ if (zret != Z_STREAM_END) {
+ warning("bad zlib data from odb helper '%s' for %s",
+ o->name, sha1_to_hex(sha1));
+ return -1;
+ }
+ if (hashcmp(real_sha1, sha1)) {
+ warning("sha1 mismatch from odb helper '%s' for %s (got %s)",
+ o->name, sha1_to_hex(sha1), sha1_to_hex(real_sha1));
+ return -1;
+ }
+
+ return total_read;
+}
+
static int read_object_process(struct odb_helper *o, const unsigned char
*sha1, int fd)
{
int err;
@@ -174,12 +250,8 @@ static int read_object_process(struct odb_helper *o, const
unsigned char *sha1,
if (err)
goto done;
- if (o->fetch_kind != ODB_FETCH_KIND_FAULT_IN) {
- struct strbuf buf;
- read_packetized_to_strbuf(process->out, &buf);
- if (err)
- goto done;
- }
+ if (o->fetch_kind != ODB_FETCH_KIND_FAULT_IN)
+ err = read_packetized_git_object_to_fd(o, sha1, process->out,
fd) < 0;
subprocess_read_status(process->out, &status);
err = strcmp(status.buf, "success");
--
2.13.1.565.gbfcd7a9048