Signed-off-by: Christian Couder <chriscool@xxxxxxxxxxxxx> --- 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