summaryrefslogtreecommitdiff
path: root/src/odb_loose.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2017-12-17 16:26:48 +0000
committerEdward Thomson <ethomson@edwardthomson.com>2018-02-01 16:50:29 -0800
commit80dc3946d82fc55ff235c30005d6d93c4f664520 (patch)
tree40d11b503ad8a1b864f1f1635406a7befb8bcab1 /src/odb_loose.c
parent7cb5bae796d5e098ef06847902cb8e1c1bd4e0cf (diff)
downloadlibgit2-80dc3946d82fc55ff235c30005d6d93c4f664520.tar.gz
odb_loose: packlike loose objects use `git_zstream`
Refactor packlike loose object reads to use `git_zstream` for simplification.
Diffstat (limited to 'src/odb_loose.c')
-rw-r--r--src/odb_loose.c159
1 files changed, 71 insertions, 88 deletions
diff --git a/src/odb_loose.c b/src/odb_loose.c
index e56c9c18e..156586fc2 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -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);
}
-static size_t get_binary_object_header(
- obj_hdr *hdr, const unsigned char *data, size_t len)
+static int parse_header_packlike(
+ obj_hdr *out, size_t *out_len, const unsigned char *data, size_t len)
{
unsigned long c;
size_t shift, size, used = 0;
if (len == 0)
- return 0;
+ goto on_error;
c = data[used++];
- hdr->type = (c >> 4) & 7;
+ out->type = (c >> 4) & 7;
size = c & 15;
shift = 4;
while (c & 0x80) {
if (len <= used)
- return 0;
+ goto on_error;
+
if (sizeof(size_t) * 8 <= shift)
- return 0;
+ goto on_error;
+
c = data[used++];
size += (c & 0x7f) << shift;
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(
@@ -254,38 +261,15 @@ static int is_zlib_compressed_data(unsigned char *data)
return (data[0] & 0x8F) == 0x08 && !(w % 31);
}
-static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
-{
- z_stream zs;
- int status = Z_OK;
-
- memset(&zs, 0x0, sizeof(zs));
-
- 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;
- }
+/***********************************************************
+ *
+ * ODB OBJECT READING & WRITING
+ *
+ * Backend for the public API; read headers and full objects
+ * from the ODB. Write raw data to the ODB.
+ *
+ ***********************************************************/
- return 0;
-}
/*
* 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)
* of loose object data into packs. This format is no longer used, but
* 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;
- 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)
* binary encoding of the object type and size.
*/
- if ((used = get_binary_object_header(&hdr, (unsigned char *)obj->ptr, obj->size)) == 0 ||
- !git_object_typeisloose(hdr.type)) {
+ if ((error = parse_header_packlike(&hdr, &head_len, obj_data, obj_len)) < 0)
+ goto done;
+
+ if (!git_object_typeisloose(hdr.type) || head_len > obj_len) {
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
*/
- GITERR_CHECK_ALLOC_ADD(&alloclen, hdr.size, 1);
- buf = git__malloc(alloclen);
- GITERR_CHECK_ALLOC(buf);
-
- in = ((unsigned char *)obj->ptr) + used;
- len = obj->size - used;
- if (inflate_buffer(in, len, buf, hdr.size) < 0) {
- git__free(buf);
- return -1;
+ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) ||
+ git_buf_init(&body, alloc_size) < 0) {
+ error = -1;
+ goto done;
}
- 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->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;
unsigned char head[HEADER_LEN], *body = NULL;
@@ -339,10 +333,6 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
obj_hdr hdr;
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 ||
(error = git_zstream_set_input(&zstream, git_buf_cstr(obj), git_buf_len(obj))) < 0)
goto done;
@@ -404,20 +394,6 @@ done:
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)
{
int error;
@@ -432,11 +408,16 @@ static int read_loose(git_rawobj *out, git_buf *loc)
out->len = 0;
out->type = GIT_OBJ_BAD;
- if (!(error = git_futils_readbuffer(&obj, loc->ptr)))
- error = inflate_disk_obj(out, &obj);
+ if ((error = git_futils_readbuffer(&obj, loc->ptr)) < 0)
+ 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;
}
@@ -958,25 +939,27 @@ static int loose_backend__readstream_packlike(
obj_hdr *hdr,
loose_readstream *stream)
{
- size_t head_len;
+ const unsigned char *data;
+ size_t data_len, head_len;
int error;
+ data = stream->map.data;
+ data_len = stream->map.len;
+
/*
* read the object header, which is an (uncompressed)
* binary encoding of the object type and size.
*/
- if ((head_len = get_binary_object_header(hdr,
- stream->map.data, stream->map.len)) == 0 ||
- !git_object_typeisloose(hdr->type)) {
+ if ((error = parse_header_packlike(hdr, &head_len, data, data_len)) < 0)
+ return error;
+
+ if (!git_object_typeisloose(hdr->type)) {
giterr_set(GITERR_ODB, "failed to inflate loose object");
return -1;
}
- if ((error = git_zstream_set_input(&stream->zstream,
- stream->map.data + head_len, stream->map.len - head_len)) < 0)
- return error;
-
- return 0;
+ return git_zstream_set_input(&stream->zstream,
+ data + head_len, data_len - head_len);
}
static int loose_backend__readstream_standard(