Unverified Commit 258188dd by Edward Thomson Committed by GitHub

Merge pull request #5340 from pks-t/pks/pack-zstream

Refactor packfile code to use zstream abstraction
parents ba64f50c 2dc7b5ef
...@@ -7,14 +7,12 @@ ...@@ -7,14 +7,12 @@
#include "pack.h" #include "pack.h"
#include "odb.h"
#include "delta.h" #include "delta.h"
#include "sha1_lookup.h"
#include "mwindow.h"
#include "futils.h" #include "futils.h"
#include "mwindow.h"
#include "odb.h"
#include "oid.h" #include "oid.h"
#include "sha1_lookup.h"
#include <zlib.h>
/* Option to bypass checking existence of '.keep' files */ /* Option to bypass checking existence of '.keep' files */
bool git_disable_pack_keep_file_checks = false; bool git_disable_pack_keep_file_checks = false;
...@@ -765,31 +763,13 @@ cleanup: ...@@ -765,31 +763,13 @@ cleanup:
return error; return error;
} }
static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size)
{
GIT_UNUSED(opaq);
return git__calloc(count, size);
}
static void use_git_free(void *opaq, void *ptr)
{
GIT_UNUSED(opaq);
git__free(ptr);
}
int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, off64_t curpos) int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, off64_t curpos)
{ {
int st;
memset(obj, 0, sizeof(git_packfile_stream)); memset(obj, 0, sizeof(git_packfile_stream));
obj->curpos = curpos; obj->curpos = curpos;
obj->p = p; obj->p = p;
obj->zstream.zalloc = use_git_alloc;
obj->zstream.zfree = use_git_free; if (git_zstream_init(&obj->zstream, GIT_ZSTREAM_INFLATE) < 0) {
obj->zstream.next_in = Z_NULL;
obj->zstream.next_out = Z_NULL;
st = inflateInit(&obj->zstream);
if (st != Z_OK) {
git_error_set(GIT_ERROR_ZLIB, "failed to init packfile stream"); git_error_set(GIT_ERROR_ZLIB, "failed to init packfile stream");
return -1; return -1;
} }
...@@ -799,110 +779,100 @@ int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, ...@@ -799,110 +779,100 @@ int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p,
ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len) ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len)
{ {
unsigned int window_len;
unsigned char *in; unsigned char *in;
size_t written; int error;
int st;
if (obj->done) if (obj->done)
return 0; return 0;
in = pack_window_open(obj->p, &obj->mw, obj->curpos, &obj->zstream.avail_in); if ((in = pack_window_open(obj->p, &obj->mw, obj->curpos, &window_len)) == NULL)
if (in == NULL)
return GIT_EBUFS; return GIT_EBUFS;
obj->zstream.next_out = buffer; if ((error = git_zstream_set_input(&obj->zstream, in, window_len)) < 0 ||
obj->zstream.avail_out = (unsigned int)len; (error = git_zstream_get_output_chunk(buffer, &len, &obj->zstream)) < 0) {
obj->zstream.next_in = in;
st = inflate(&obj->zstream, Z_SYNC_FLUSH);
git_mwindow_close(&obj->mw); git_mwindow_close(&obj->mw);
obj->curpos += obj->zstream.next_in - in;
written = len - obj->zstream.avail_out;
if (st != Z_OK && st != Z_STREAM_END) {
git_error_set(GIT_ERROR_ZLIB, "error reading from the zlib stream"); git_error_set(GIT_ERROR_ZLIB, "error reading from the zlib stream");
return -1; return -1;
} }
if (st == Z_STREAM_END) git_mwindow_close(&obj->mw);
obj->done = 1;
obj->curpos += window_len - obj->zstream.in_len;
if (git_zstream_eos(&obj->zstream))
obj->done = 1;
/* If we didn't write anything out but we're not done, we need more data */ /* If we didn't write anything out but we're not done, we need more data */
if (!written && st != Z_STREAM_END) if (!len && !git_zstream_eos(&obj->zstream))
return GIT_EBUFS; return GIT_EBUFS;
return written; return len;
} }
void git_packfile_stream_dispose(git_packfile_stream *obj) void git_packfile_stream_dispose(git_packfile_stream *obj)
{ {
inflateEnd(&obj->zstream); git_zstream_free(&obj->zstream);
} }
static int packfile_unpack_compressed( static int packfile_unpack_compressed(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_curs, git_mwindow **mwindow,
off64_t *curpos, off64_t *position,
size_t size, size_t size,
git_object_t type) git_object_t type)
{ {
size_t buf_size; git_zstream zstream = GIT_ZSTREAM_INIT;
int st; size_t buffer_len, total = 0;
z_stream stream; char *data = NULL;
unsigned char *buffer, *in; int error;
GIT_ERROR_CHECK_ALLOC_ADD(&buf_size, size, 1);
buffer = git__calloc(1, buf_size);
GIT_ERROR_CHECK_ALLOC(buffer);
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;
st = inflateInit(&stream);
if (st != Z_OK) {
git__free(buffer);
git_error_set(GIT_ERROR_ZLIB, "failed to init zlib stream on unpack");
return -1; GIT_ERROR_CHECK_ALLOC_ADD(&buffer_len, size, 1);
data = git__calloc(1, buffer_len);
GIT_ERROR_CHECK_ALLOC(data);
if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0) {
git_error_set(GIT_ERROR_ZLIB, "failed to init zlib stream on unpack");
goto out;
} }
do { do {
in = pack_window_open(p, w_curs, *curpos, &stream.avail_in); size_t bytes = buffer_len - total;
stream.next_in = in; unsigned int window_len;
st = inflate(&stream, Z_FINISH); unsigned char *in;
git_mwindow_close(w_curs);
if (!stream.avail_out) in = pack_window_open(p, mwindow, *position, &window_len);
break; /* the payload is larger than it should be */
if (st == Z_BUF_ERROR && in == NULL) { if ((error = git_zstream_set_input(&zstream, in, window_len)) < 0 ||
inflateEnd(&stream); (error = git_zstream_get_output_chunk(data + total, &bytes, &zstream)) < 0) {
git__free(buffer); git_mwindow_close(mwindow);
return GIT_EBUFS; goto out;
} }
*curpos += stream.next_in - in; git_mwindow_close(mwindow);
} while (st == Z_OK || st == Z_BUF_ERROR);
inflateEnd(&stream); *position += window_len - zstream.in_len;
total += bytes;
} while (total < size);
if ((st != Z_STREAM_END) || stream.total_out != size) { if (total != size || !git_zstream_eos(&zstream)) {
git__free(buffer);
git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream"); git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream");
return -1; error = -1;
goto out;
} }
obj->type = type; obj->type = type;
obj->len = size; obj->len = size;
obj->data = buffer; obj->data = data;
return 0;
out:
git_zstream_free(&zstream);
if (error)
git__free(data);
return error;
} }
/* /*
......
...@@ -10,16 +10,15 @@ ...@@ -10,16 +10,15 @@
#include "common.h" #include "common.h"
#include <zlib.h>
#include "git2/oid.h" #include "git2/oid.h"
#include "array.h"
#include "map.h" #include "map.h"
#include "mwindow.h" #include "mwindow.h"
#include "odb.h" #include "odb.h"
#include "offmap.h" #include "offmap.h"
#include "oidmap.h" #include "oidmap.h"
#include "array.h" #include "zstream.h"
#define GIT_PACK_FILE_MODE 0444 #define GIT_PACK_FILE_MODE 0444
...@@ -116,7 +115,7 @@ struct git_pack_entry { ...@@ -116,7 +115,7 @@ struct git_pack_entry {
typedef struct git_packfile_stream { typedef struct git_packfile_stream {
off64_t curpos; off64_t curpos;
int done; int done;
z_stream zstream; git_zstream zstream;
struct git_pack_file *p; struct git_pack_file *p;
git_mwindow *mw; git_mwindow *mw;
} git_packfile_stream; } git_packfile_stream;
......
...@@ -77,6 +77,11 @@ bool git_zstream_done(git_zstream *zstream) ...@@ -77,6 +77,11 @@ bool git_zstream_done(git_zstream *zstream)
return (!zstream->in_len && zstream->zerr == Z_STREAM_END); 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) size_t git_zstream_suggest_output_len(git_zstream *zstream)
{ {
if (zstream->in_len > ZSTREAM_BUFFER_SIZE) if (zstream->in_len > ZSTREAM_BUFFER_SIZE)
......
...@@ -44,6 +44,7 @@ int git_zstream_get_output_chunk( ...@@ -44,6 +44,7 @@ int git_zstream_get_output_chunk(
int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream); int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream);
bool git_zstream_done(git_zstream *zstream); bool git_zstream_done(git_zstream *zstream);
bool git_zstream_eos(git_zstream *zstream);
void git_zstream_reset(git_zstream *zstream); void git_zstream_reset(git_zstream *zstream);
......
...@@ -145,7 +145,7 @@ void test_pack_packbuilder__get_hash(void) ...@@ -145,7 +145,7 @@ void test_pack_packbuilder__get_hash(void)
seed_packbuilder(); seed_packbuilder();
git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL); cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL));
git_oid_fmt(hex, git_packbuilder_hash(_packbuilder)); git_oid_fmt(hex, git_packbuilder_hash(_packbuilder));
cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0"); cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0");
...@@ -158,7 +158,7 @@ static void test_write_pack_permission(mode_t given, mode_t expected) ...@@ -158,7 +158,7 @@ static void test_write_pack_permission(mode_t given, mode_t expected)
seed_packbuilder(); seed_packbuilder();
git_packbuilder_write(_packbuilder, ".", given, NULL, NULL); cl_git_pass(git_packbuilder_write(_packbuilder, ".", given, NULL, NULL));
/* Windows does not return group/user bits from stat, /* Windows does not return group/user bits from stat,
* files are never executable. * files are never executable.
...@@ -197,7 +197,7 @@ void test_pack_packbuilder__permissions_readwrite(void) ...@@ -197,7 +197,7 @@ void test_pack_packbuilder__permissions_readwrite(void)
void test_pack_packbuilder__does_not_fsync_by_default(void) void test_pack_packbuilder__does_not_fsync_by_default(void)
{ {
seed_packbuilder(); seed_packbuilder();
git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(0, p_fsync__cnt); cl_assert_equal_sz(0, p_fsync__cnt);
} }
...@@ -215,7 +215,7 @@ void test_pack_packbuilder__fsync_global_setting(void) ...@@ -215,7 +215,7 @@ void test_pack_packbuilder__fsync_global_setting(void)
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
p_fsync__cnt = 0; p_fsync__cnt = 0;
seed_packbuilder(); seed_packbuilder();
git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
} }
...@@ -224,7 +224,7 @@ void test_pack_packbuilder__fsync_repo_setting(void) ...@@ -224,7 +224,7 @@ void test_pack_packbuilder__fsync_repo_setting(void)
cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true); cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true);
p_fsync__cnt = 0; p_fsync__cnt = 0;
seed_packbuilder(); seed_packbuilder();
git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
} }
......
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