Commit 80dc3946 by Edward Thomson

odb_loose: packlike loose objects use `git_zstream`

Refactor packlike loose object reads to use `git_zstream` for
simplification.
parent 7cb5bae7
...@@ -104,32 +104,39 @@ static int object_mkdir(const git_buf *name, const loose_backend *be) ...@@ -104,32 +104,39 @@ static int object_mkdir(const git_buf *name, const loose_backend *be)
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR, NULL); GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR, NULL);
} }
static size_t get_binary_object_header( static int parse_header_packlike(
obj_hdr *hdr, const unsigned char *data, size_t len) obj_hdr *out, size_t *out_len, const unsigned char *data, size_t len)
{ {
unsigned long c; unsigned long c;
size_t shift, size, used = 0; size_t shift, size, used = 0;
if (len == 0) if (len == 0)
return 0; goto on_error;
c = data[used++]; c = data[used++];
hdr->type = (c >> 4) & 7; out->type = (c >> 4) & 7;
size = c & 15; size = c & 15;
shift = 4; shift = 4;
while (c & 0x80) { while (c & 0x80) {
if (len <= used) if (len <= used)
return 0; goto on_error;
if (sizeof(size_t) * 8 <= shift) if (sizeof(size_t) * 8 <= shift)
return 0; goto on_error;
c = data[used++]; c = data[used++];
size += (c & 0x7f) << shift; size += (c & 0x7f) << shift;
shift += 7; shift += 7;
} }
hdr->size = size;
return used; out->size = size;
*out_len = used;
return 0;
on_error:
giterr_set(GITERR_OBJECT, "failed to parse loose object: invalid header");
return -1;
} }
static int parse_header( static int parse_header(
...@@ -254,38 +261,15 @@ static int is_zlib_compressed_data(unsigned char *data) ...@@ -254,38 +261,15 @@ static int is_zlib_compressed_data(unsigned char *data)
return (data[0] & 0x8F) == 0x08 && !(w % 31); return (data[0] & 0x8F) == 0x08 && !(w % 31);
} }
static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) /***********************************************************
{ *
z_stream zs; * ODB OBJECT READING & WRITING
int status = Z_OK; *
* Backend for the public API; read headers and full objects
memset(&zs, 0x0, sizeof(zs)); * from the ODB. Write raw data to the ODB.
*
zs.next_out = out; ***********************************************************/
zs.avail_out = (uInt)outlen;
zs.next_in = in;
zs.avail_in = (uInt)inlen;
if (inflateInit(&zs) < Z_OK) {
giterr_set(GITERR_ZLIB, "failed to inflate buffer");
return -1;
}
while (status == Z_OK)
status = inflate(&zs, Z_FINISH);
inflateEnd(&zs);
if (status != Z_STREAM_END /* || zs.avail_in != 0 */ ||
zs.total_out != outlen)
{
giterr_set(GITERR_ZLIB, "failed to inflate buffer; stream aborted prematurely");
return -1;
}
return 0;
}
/* /*
* At one point, there was a loose object format that was intended to * At one point, there was a loose object format that was intended to
...@@ -293,45 +277,55 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) ...@@ -293,45 +277,55 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
* of loose object data into packs. This format is no longer used, but * of loose object data into packs. This format is no longer used, but
* we must still read it. * we must still read it.
*/ */
static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) static int read_loose_packlike(git_rawobj *out, git_buf *obj)
{ {
unsigned char *in, *buf; git_buf body = GIT_BUF_INIT;
const unsigned char *obj_data;
obj_hdr hdr; obj_hdr hdr;
size_t len, used, alloclen; size_t obj_len, head_len, alloc_size;
int error;
obj_data = (unsigned char *)obj->ptr;
obj_len = obj->size;
/* /*
* read the object header, which is an (uncompressed) * read the object header, which is an (uncompressed)
* binary encoding of the object type and size. * binary encoding of the object type and size.
*/ */
if ((used = get_binary_object_header(&hdr, (unsigned char *)obj->ptr, obj->size)) == 0 || if ((error = parse_header_packlike(&hdr, &head_len, obj_data, obj_len)) < 0)
!git_object_typeisloose(hdr.type)) { goto done;
if (!git_object_typeisloose(hdr.type) || head_len > obj_len) {
giterr_set(GITERR_ODB, "failed to inflate loose object"); giterr_set(GITERR_ODB, "failed to inflate loose object");
return -1; error = -1;
goto done;
} }
obj_data += head_len;
obj_len -= head_len;
/* /*
* allocate a buffer and inflate the data into it * allocate a buffer and inflate the data into it
*/ */
GITERR_CHECK_ALLOC_ADD(&alloclen, hdr.size, 1); if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) ||
buf = git__malloc(alloclen); git_buf_init(&body, alloc_size) < 0) {
GITERR_CHECK_ALLOC(buf); error = -1;
goto done;
in = ((unsigned char *)obj->ptr) + used;
len = obj->size - used;
if (inflate_buffer(in, len, buf, hdr.size) < 0) {
git__free(buf);
return -1;
} }
buf[hdr.size] = '\0';
out->data = buf; if ((error = git_zstream_inflatebuf(&body, obj_data, obj_len)) < 0)
goto done;
out->len = hdr.size; out->len = hdr.size;
out->type = hdr.type; out->type = hdr.type;
out->data = git_buf_detach(&body);
return 0; done:
git_buf_free(&body);
return error;
} }
static int inflate_disk_obj(git_rawobj *out, git_buf *obj) static int read_loose_standard(git_rawobj *out, git_buf *obj)
{ {
git_zstream zstream = GIT_ZSTREAM_INIT; git_zstream zstream = GIT_ZSTREAM_INIT;
unsigned char head[HEADER_LEN], *body = NULL; unsigned char head[HEADER_LEN], *body = NULL;
...@@ -339,10 +333,6 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj) ...@@ -339,10 +333,6 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
obj_hdr hdr; obj_hdr hdr;
int error; int error;
/* check for a pack-like loose object */
if (!is_zlib_compressed_data((unsigned char *)obj->ptr))
return inflate_packlike_loose_disk_obj(out, obj);
if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0 || if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0 ||
(error = git_zstream_set_input(&zstream, git_buf_cstr(obj), git_buf_len(obj))) < 0) (error = git_zstream_set_input(&zstream, git_buf_cstr(obj), git_buf_len(obj))) < 0)
goto done; goto done;
...@@ -404,20 +394,6 @@ done: ...@@ -404,20 +394,6 @@ done:
return error; return error;
} }
/***********************************************************
*
* ODB OBJECT READING & WRITING
*
* Backend for the public API; read headers and full objects
* from the ODB. Write raw data to the ODB.
*
***********************************************************/
static int read_loose(git_rawobj *out, git_buf *loc) static int read_loose(git_rawobj *out, git_buf *loc)
{ {
int error; int error;
...@@ -432,11 +408,16 @@ static int read_loose(git_rawobj *out, git_buf *loc) ...@@ -432,11 +408,16 @@ static int read_loose(git_rawobj *out, git_buf *loc)
out->len = 0; out->len = 0;
out->type = GIT_OBJ_BAD; out->type = GIT_OBJ_BAD;
if (!(error = git_futils_readbuffer(&obj, loc->ptr))) if ((error = git_futils_readbuffer(&obj, loc->ptr)) < 0)
error = inflate_disk_obj(out, &obj); goto done;
git_buf_free(&obj); if (!is_zlib_compressed_data((unsigned char *)obj.ptr))
error = read_loose_packlike(out, &obj);
else
error = read_loose_standard(out, &obj);
done:
git_buf_free(&obj);
return error; return error;
} }
...@@ -958,25 +939,27 @@ static int loose_backend__readstream_packlike( ...@@ -958,25 +939,27 @@ static int loose_backend__readstream_packlike(
obj_hdr *hdr, obj_hdr *hdr,
loose_readstream *stream) loose_readstream *stream)
{ {
size_t head_len; const unsigned char *data;
size_t data_len, head_len;
int error; int error;
data = stream->map.data;
data_len = stream->map.len;
/* /*
* read the object header, which is an (uncompressed) * read the object header, which is an (uncompressed)
* binary encoding of the object type and size. * binary encoding of the object type and size.
*/ */
if ((head_len = get_binary_object_header(hdr, if ((error = parse_header_packlike(hdr, &head_len, data, data_len)) < 0)
stream->map.data, stream->map.len)) == 0 || return error;
!git_object_typeisloose(hdr->type)) {
if (!git_object_typeisloose(hdr->type)) {
giterr_set(GITERR_ODB, "failed to inflate loose object"); giterr_set(GITERR_ODB, "failed to inflate loose object");
return -1; return -1;
} }
if ((error = git_zstream_set_input(&stream->zstream, return git_zstream_set_input(&stream->zstream,
stream->map.data + head_len, stream->map.len - head_len)) < 0) data + head_len, data_len - head_len);
return error;
return 0;
} }
static int loose_backend__readstream_standard( static int loose_backend__readstream_standard(
......
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