pack: refactor unpacking of raw objects to use `git_zstream` While we do have a zstream abstraction that encapsulates all the calls to zlib as well as its error handling, we do not use it in our pack file code. Refactor it to make the code a lot easier to understand.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
diff --git a/src/pack.c b/src/pack.c
index 4c4eb9b..92a3abe 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -7,12 +7,13 @@
#include "pack.h"
-#include "odb.h"
#include "delta.h"
-#include "sha1_lookup.h"
-#include "mwindow.h"
#include "futils.h"
+#include "mwindow.h"
+#include "odb.h"
#include "oid.h"
+#include "sha1_lookup.h"
+#include "zstream.h"
#include <zlib.h>
@@ -845,64 +846,60 @@ void git_packfile_stream_dispose(git_packfile_stream *obj)
static int packfile_unpack_compressed(
git_rawobj *obj,
struct git_pack_file *p,
- git_mwindow **w_curs,
- off64_t *curpos,
+ git_mwindow **mwindow,
+ off64_t *position,
size_t size,
git_object_t type)
{
- size_t buf_size;
- int st;
- z_stream stream;
- unsigned char *buffer, *in;
-
- GIT_ERROR_CHECK_ALLOC_ADD(&buf_size, size, 1);
- buffer = git__calloc(1, buf_size);
- GIT_ERROR_CHECK_ALLOC(buffer);
+ git_zstream zstream = GIT_ZSTREAM_INIT;
+ size_t buffer_len, total = 0;
+ char *data = NULL;
+ int error;
- memset(&stream, 0, sizeof(stream));
- stream.next_out = buffer;
- stream.avail_out = (uInt)buf_size;
- stream.zalloc = use_git_alloc;
- stream.zfree = use_git_free;
+ GIT_ERROR_CHECK_ALLOC_ADD(&buffer_len, size, 1);
+ data = git__calloc(1, buffer_len);
+ GIT_ERROR_CHECK_ALLOC(data);
- st = inflateInit(&stream);
- if (st != Z_OK) {
- git__free(buffer);
+ if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0) {
git_error_set(GIT_ERROR_ZLIB, "failed to init zlib stream on unpack");
-
- return -1;
+ goto out;
}
do {
- in = pack_window_open(p, w_curs, *curpos, &stream.avail_in);
- stream.next_in = in;
- st = inflate(&stream, Z_FINISH);
- git_mwindow_close(w_curs);
+ size_t bytes = buffer_len - total;
+ unsigned int window_len;
+ unsigned char *in;
- if (!stream.avail_out)
- break; /* the payload is larger than it should be */
+ in = pack_window_open(p, mwindow, *position, &window_len);
- if (st == Z_BUF_ERROR && in == NULL) {
- inflateEnd(&stream);
- git__free(buffer);
- return GIT_EBUFS;
+ if ((error = git_zstream_set_input(&zstream, in, window_len)) < 0 ||
+ (error = git_zstream_get_output_chunk(data + total, &bytes, &zstream)) < 0) {
+ git_mwindow_close(mwindow);
+ goto out;
}
- *curpos += stream.next_in - in;
- } while (st == Z_OK || st == Z_BUF_ERROR);
+ git_mwindow_close(mwindow);
- inflateEnd(&stream);
+ *position += window_len - zstream.in_len;
+ total += bytes;
+ } while (total < size);
- if ((st != Z_STREAM_END) || stream.total_out != size) {
- git__free(buffer);
+ if (total != size || !git_zstream_eos(&zstream)) {
git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream");
- return -1;
+ error = -1;
+ goto out;
}
obj->type = type;
obj->len = size;
- obj->data = buffer;
- return 0;
+ obj->data = data;
+
+out:
+ git_zstream_free(&zstream);
+ if (error)
+ git__free(data);
+
+ return error;
}
/*
diff --git a/src/zstream.c b/src/zstream.c
index fc8bfb8..975ead2 100644
--- a/src/zstream.c
+++ b/src/zstream.c
@@ -77,6 +77,11 @@ bool git_zstream_done(git_zstream *zstream)
return (!zstream->in_len && zstream->zerr == Z_STREAM_END);
}
+bool git_zstream_eos(git_zstream *zstream)
+{
+ return zstream->zerr == Z_STREAM_END;
+}
+
size_t git_zstream_suggest_output_len(git_zstream *zstream)
{
if (zstream->in_len > ZSTREAM_BUFFER_SIZE)
diff --git a/src/zstream.h b/src/zstream.h
index 47ecc13..db0cc47 100644
--- a/src/zstream.h
+++ b/src/zstream.h
@@ -44,6 +44,7 @@ int git_zstream_get_output_chunk(
int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream);
bool git_zstream_done(git_zstream *zstream);
+bool git_zstream_eos(git_zstream *zstream);
void git_zstream_reset(git_zstream *zstream);