index-pack: loop while inflating objects in unpack_data

When the unpack_data function is given a consume() callback, it unpacks only 64K of the input at a time, feeding it to git_inflate along with a 64K output buffer. However, because we are inflating, there is a good chance that the output buffer will fill before consuming all of the input. In this case, we need to loop on git_inflate until we have fed the whole input buffer, feeding each chunk of output to the consume buffer. The current code does not do this, and as a result, will fail the loop condition and trigger a fatal "serious inflate inconsistency" error in this case. While we're rearranging the loop, let's get rid of the extra last_out pointer. It is meant to point to the beginning of the buffer that we feed to git_inflate, but in practice this is always the beginning of our same 64K buffer, because: 1. At the beginning of the loop, we are feeding the buffer. 2. At the end of the loop, if we are using a consume() function, we reset git_inflate's pointer to the beginning of the buffer. If we are not using a consume() function, then we do not care about the value of last_out at all. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jul 4, 2012 at 03:12 UTC f8b090386bb5af172ea95f16ad6274e02222d2c1
1 file changed +13 -10
builtin/index-pack.c
+13 -10
@@ -524,7 +524,6 @@ static void *unpack_data(struct object_entry *obj,
524 stream.avail_out = consume ? 64*1024 : obj->size;
525
526 do {
527 - unsigned char *last_out = stream.next_out;
527 ssize_t n = (len < 64*1024) ? len : 64*1024;
528 n = pread(pack_fd, inbuf, n, from);
529 if (n < 0)
@@ -538,15 +537,19 @@ static void *unpack_data(struct object_entry *obj,
537 len -= n;
538 stream.next_in = inbuf;
539 stream.avail_in = n;
541 - status = git_inflate(&stream, 0);
542 - if (consume) {
543 - if (consume(last_out, stream.next_out - last_out, cb_data)) {
544 - free(inbuf);
545 - free(data);
546 - return NULL;
547 - }
548 - stream.next_out = data;
549 - stream.avail_out = 64*1024;
540 + if (!consume)
541 + status = git_inflate(&stream, 0);
542 + else {
543 + do {
544 + status = git_inflate(&stream, 0);
545 + if (consume(data, stream.next_out - data, cb_data)) {
546 + free(inbuf);
547 + free(data);
548 + return NULL;
549 + }
550 + stream.next_out = data;
551 + stream.avail_out = 64*1024;
552 + } while (status == Z_OK && stream.avail_in);
553 }
554 } while (len && status == Z_OK && !stream.avail_in);
555