Commit d8f6fee3 by Patrick Steinhardt

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.
parent ba64f50c
......@@ -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;
}
/*
......
......@@ -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)
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment