mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 01:58:32 +00:00
delta: refactor git_delta functions for consistency
Refactor the git_delta functions to have consistent naming and parameters with the rest of the library.
This commit is contained in:
parent
6a2d2f8aa1
commit
1cd6599142
135
src/delta.c
135
src/delta.c
@ -114,7 +114,7 @@ struct index_entry {
|
||||
struct git_delta_index {
|
||||
unsigned long memsize;
|
||||
const void *src_buf;
|
||||
unsigned long src_size;
|
||||
size_t src_size;
|
||||
unsigned int hash_mask;
|
||||
struct index_entry *hash[GIT_FLEX_ARRAY];
|
||||
};
|
||||
@ -142,8 +142,8 @@ static int lookup_index_alloc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct git_delta_index *
|
||||
git_delta_create_index(const void *buf, unsigned long bufsize)
|
||||
int git_delta_index_init(
|
||||
git_delta_index **out, const void *buf, size_t bufsize)
|
||||
{
|
||||
unsigned int i, hsize, hmask, entries, prev_val, *hash_count;
|
||||
const unsigned char *data, *buffer = buf;
|
||||
@ -152,8 +152,10 @@ git_delta_create_index(const void *buf, unsigned long bufsize)
|
||||
void *mem;
|
||||
unsigned long memsize;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if (!buf || !bufsize)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
/* Determine index hash size. Note that indexing skips the
|
||||
first byte to allow for optimizing the rabin polynomial
|
||||
@ -172,7 +174,7 @@ git_delta_create_index(const void *buf, unsigned long bufsize)
|
||||
hmask = hsize - 1;
|
||||
|
||||
if (lookup_index_alloc(&mem, &memsize, entries, hsize) < 0)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
index = mem;
|
||||
mem = index->hash;
|
||||
@ -190,7 +192,7 @@ git_delta_create_index(const void *buf, unsigned long bufsize)
|
||||
hash_count = git__calloc(hsize, sizeof(*hash_count));
|
||||
if (!hash_count) {
|
||||
git__free(index);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* then populate the index */
|
||||
@ -243,20 +245,20 @@ git_delta_create_index(const void *buf, unsigned long bufsize)
|
||||
}
|
||||
git__free(hash_count);
|
||||
|
||||
return index;
|
||||
*out = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_delta_free_index(struct git_delta_index *index)
|
||||
void git_delta_index_free(git_delta_index *index)
|
||||
{
|
||||
git__free(index);
|
||||
}
|
||||
|
||||
unsigned long git_delta_sizeof_index(struct git_delta_index *index)
|
||||
size_t git_delta_index_size(git_delta_index *index)
|
||||
{
|
||||
if (index)
|
||||
return index->memsize;
|
||||
else
|
||||
return 0;
|
||||
assert(index);
|
||||
|
||||
return index->memsize;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -265,55 +267,57 @@ unsigned long git_delta_sizeof_index(struct git_delta_index *index)
|
||||
*/
|
||||
#define MAX_OP_SIZE (5 + 5 + 1 + RABIN_WINDOW + 7)
|
||||
|
||||
void *
|
||||
git_delta_create(
|
||||
int git_delta_create_from_index(
|
||||
void **out,
|
||||
size_t *out_len,
|
||||
const struct git_delta_index *index,
|
||||
const void *trg_buf,
|
||||
unsigned long trg_size,
|
||||
unsigned long *delta_size,
|
||||
unsigned long max_size)
|
||||
size_t trg_size,
|
||||
size_t max_size)
|
||||
{
|
||||
unsigned int i, outpos, outsize, moff, msize, val;
|
||||
unsigned int i, bufpos, bufsize, moff, msize, val;
|
||||
int inscnt;
|
||||
const unsigned char *ref_data, *ref_top, *data, *top;
|
||||
unsigned char *out;
|
||||
unsigned char *buf;
|
||||
|
||||
*out = NULL;
|
||||
*out_len = 0;
|
||||
|
||||
if (!trg_buf || !trg_size)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
outpos = 0;
|
||||
outsize = 8192;
|
||||
if (max_size && outsize >= max_size)
|
||||
outsize = (unsigned int)(max_size + MAX_OP_SIZE + 1);
|
||||
out = git__malloc(outsize);
|
||||
if (!out)
|
||||
return NULL;
|
||||
bufpos = 0;
|
||||
bufsize = 8192;
|
||||
if (max_size && bufsize >= max_size)
|
||||
bufsize = (unsigned int)(max_size + MAX_OP_SIZE + 1);
|
||||
buf = git__malloc(bufsize);
|
||||
GITERR_CHECK_ALLOC(buf);
|
||||
|
||||
/* store reference buffer size */
|
||||
i = index->src_size;
|
||||
while (i >= 0x80) {
|
||||
out[outpos++] = i | 0x80;
|
||||
buf[bufpos++] = i | 0x80;
|
||||
i >>= 7;
|
||||
}
|
||||
out[outpos++] = i;
|
||||
buf[bufpos++] = i;
|
||||
|
||||
/* store target buffer size */
|
||||
i = trg_size;
|
||||
while (i >= 0x80) {
|
||||
out[outpos++] = i | 0x80;
|
||||
buf[bufpos++] = i | 0x80;
|
||||
i >>= 7;
|
||||
}
|
||||
out[outpos++] = i;
|
||||
buf[bufpos++] = i;
|
||||
|
||||
ref_data = index->src_buf;
|
||||
ref_top = ref_data + index->src_size;
|
||||
data = trg_buf;
|
||||
top = (const unsigned char *) trg_buf + trg_size;
|
||||
|
||||
outpos++;
|
||||
bufpos++;
|
||||
val = 0;
|
||||
for (i = 0; i < RABIN_WINDOW && data < top; i++, data++) {
|
||||
out[outpos++] = *data;
|
||||
buf[bufpos++] = *data;
|
||||
val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
|
||||
}
|
||||
inscnt = i;
|
||||
@ -350,11 +354,11 @@ git_delta_create(
|
||||
|
||||
if (msize < 4) {
|
||||
if (!inscnt)
|
||||
outpos++;
|
||||
out[outpos++] = *data++;
|
||||
bufpos++;
|
||||
buf[bufpos++] = *data++;
|
||||
inscnt++;
|
||||
if (inscnt == 0x7f) {
|
||||
out[outpos - inscnt - 1] = inscnt;
|
||||
buf[bufpos - inscnt - 1] = inscnt;
|
||||
inscnt = 0;
|
||||
}
|
||||
msize = 0;
|
||||
@ -368,14 +372,14 @@ git_delta_create(
|
||||
msize++;
|
||||
moff--;
|
||||
data--;
|
||||
outpos--;
|
||||
bufpos--;
|
||||
if (--inscnt)
|
||||
continue;
|
||||
outpos--; /* remove count slot */
|
||||
bufpos--; /* remove count slot */
|
||||
inscnt--; /* make it -1 */
|
||||
break;
|
||||
}
|
||||
out[outpos - inscnt - 1] = inscnt;
|
||||
buf[bufpos - inscnt - 1] = inscnt;
|
||||
inscnt = 0;
|
||||
}
|
||||
|
||||
@ -383,22 +387,22 @@ git_delta_create(
|
||||
left = (msize < 0x10000) ? 0 : (msize - 0x10000);
|
||||
msize -= left;
|
||||
|
||||
op = out + outpos++;
|
||||
op = buf + bufpos++;
|
||||
i = 0x80;
|
||||
|
||||
if (moff & 0x000000ff)
|
||||
out[outpos++] = moff >> 0, i |= 0x01;
|
||||
buf[bufpos++] = moff >> 0, i |= 0x01;
|
||||
if (moff & 0x0000ff00)
|
||||
out[outpos++] = moff >> 8, i |= 0x02;
|
||||
buf[bufpos++] = moff >> 8, i |= 0x02;
|
||||
if (moff & 0x00ff0000)
|
||||
out[outpos++] = moff >> 16, i |= 0x04;
|
||||
buf[bufpos++] = moff >> 16, i |= 0x04;
|
||||
if (moff & 0xff000000)
|
||||
out[outpos++] = moff >> 24, i |= 0x08;
|
||||
buf[bufpos++] = moff >> 24, i |= 0x08;
|
||||
|
||||
if (msize & 0x00ff)
|
||||
out[outpos++] = msize >> 0, i |= 0x10;
|
||||
buf[bufpos++] = msize >> 0, i |= 0x10;
|
||||
if (msize & 0xff00)
|
||||
out[outpos++] = msize >> 8, i |= 0x20;
|
||||
buf[bufpos++] = msize >> 8, i |= 0x20;
|
||||
|
||||
*op = i;
|
||||
|
||||
@ -415,31 +419,33 @@ git_delta_create(
|
||||
}
|
||||
}
|
||||
|
||||
if (outpos >= outsize - MAX_OP_SIZE) {
|
||||
void *tmp = out;
|
||||
outsize = outsize * 3 / 2;
|
||||
if (max_size && outsize >= max_size)
|
||||
outsize = max_size + MAX_OP_SIZE + 1;
|
||||
if (max_size && outpos > max_size)
|
||||
if (bufpos >= bufsize - MAX_OP_SIZE) {
|
||||
void *tmp = buf;
|
||||
bufsize = bufsize * 3 / 2;
|
||||
if (max_size && bufsize >= max_size)
|
||||
bufsize = max_size + MAX_OP_SIZE + 1;
|
||||
if (max_size && bufpos > max_size)
|
||||
break;
|
||||
out = git__realloc(out, outsize);
|
||||
if (!out) {
|
||||
buf = git__realloc(buf, bufsize);
|
||||
if (!buf) {
|
||||
git__free(tmp);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inscnt)
|
||||
out[outpos - inscnt - 1] = inscnt;
|
||||
buf[bufpos - inscnt - 1] = inscnt;
|
||||
|
||||
if (max_size && outpos > max_size) {
|
||||
git__free(out);
|
||||
return NULL;
|
||||
if (max_size && bufpos > max_size) {
|
||||
giterr_set(GITERR_NOMEMORY, "delta would be larger than maximum size");
|
||||
git__free(buf);
|
||||
return GIT_EBUFS;
|
||||
}
|
||||
|
||||
*delta_size = outpos;
|
||||
return out;
|
||||
*out_len = bufpos;
|
||||
*out = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -459,8 +465,11 @@ static int hdr_sz(
|
||||
unsigned int c, shift = 0;
|
||||
|
||||
do {
|
||||
if (d == end)
|
||||
if (d == end) {
|
||||
giterr_set(GITERR_INVALID, "truncated delta");
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = *d++;
|
||||
r |= (c & 0x7f) << shift;
|
||||
shift += 7;
|
||||
|
98
src/delta.h
98
src/delta.h
@ -8,11 +8,10 @@
|
||||
#include "common.h"
|
||||
#include "pack.h"
|
||||
|
||||
/* opaque object for delta index */
|
||||
struct git_delta_index;
|
||||
typedef struct git_delta_index git_delta_index;
|
||||
|
||||
/*
|
||||
* create_delta_index: compute index data from given buffer
|
||||
* git_delta_index_init: compute index data from given buffer
|
||||
*
|
||||
* This returns a pointer to a struct delta_index that should be passed to
|
||||
* subsequent create_delta() calls, or to free_delta_index(). A NULL pointer
|
||||
@ -20,22 +19,18 @@ struct git_delta_index;
|
||||
* before free_delta_index() is called. The returned pointer must be freed
|
||||
* using free_delta_index().
|
||||
*/
|
||||
extern struct git_delta_index *git_delta_create_index(
|
||||
const void *buf, unsigned long bufsize);
|
||||
extern int git_delta_index_init(
|
||||
git_delta_index **out, const void *buf, size_t bufsize);
|
||||
|
||||
/*
|
||||
* free_delta_index: free the index created by create_delta_index()
|
||||
*
|
||||
* Given pointer must be what create_delta_index() returned, or NULL.
|
||||
* Free the index created by git_delta_index_init()
|
||||
*/
|
||||
extern void git_delta_free_index(struct git_delta_index *index);
|
||||
extern void git_delta_index_free(git_delta_index *index);
|
||||
|
||||
/*
|
||||
* sizeof_delta_index: returns memory usage of delta index
|
||||
*
|
||||
* Given pointer must be what create_delta_index() returned, or NULL.
|
||||
* Returns memory usage of delta index.
|
||||
*/
|
||||
extern unsigned long git_delta_sizeof_index(struct git_delta_index *index);
|
||||
extern size_t git_delta_index_size(git_delta_index *index);
|
||||
|
||||
/*
|
||||
* create_delta: create a delta from given index for the given buffer
|
||||
@ -47,71 +42,50 @@ extern unsigned long git_delta_sizeof_index(struct git_delta_index *index);
|
||||
* returned and *delta_size is updated with its size. The returned buffer
|
||||
* must be freed by the caller.
|
||||
*/
|
||||
extern void *git_delta_create(
|
||||
extern int git_delta_create_from_index(
|
||||
void **out,
|
||||
size_t *out_size,
|
||||
const struct git_delta_index *index,
|
||||
const void *buf,
|
||||
unsigned long bufsize,
|
||||
unsigned long *delta_size,
|
||||
unsigned long max_delta_size);
|
||||
size_t bufsize,
|
||||
size_t max_delta_size);
|
||||
|
||||
/*
|
||||
* diff_delta: create a delta from source buffer to target buffer
|
||||
*
|
||||
* If max_delta_size is non-zero and the resulting delta is to be larger
|
||||
* than max_delta_size then NULL is returned. On success, a non-NULL
|
||||
* than max_delta_size then GIT_EBUFS is returned. On success, a non-NULL
|
||||
* pointer to the buffer with the delta data is returned and *delta_size is
|
||||
* updated with its size. The returned buffer must be freed by the caller.
|
||||
*/
|
||||
GIT_INLINE(void *) git_delta(
|
||||
const void *src_buf, unsigned long src_bufsize,
|
||||
const void *trg_buf, unsigned long trg_bufsize,
|
||||
unsigned long *delta_size,
|
||||
unsigned long max_delta_size)
|
||||
GIT_INLINE(int) git_delta(
|
||||
void **out, size_t *out_len,
|
||||
const void *src_buf, size_t src_bufsize,
|
||||
const void *trg_buf, size_t trg_bufsize,
|
||||
size_t max_delta_size)
|
||||
{
|
||||
struct git_delta_index *index = git_delta_create_index(src_buf, src_bufsize);
|
||||
if (index) {
|
||||
void *delta = git_delta_create(
|
||||
index, trg_buf, trg_bufsize, delta_size, max_delta_size);
|
||||
git_delta_free_index(index);
|
||||
return delta;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
git_delta_index *index;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* patch_delta: recreate target buffer given source buffer and delta data
|
||||
*
|
||||
* On success, a non-NULL pointer to the target buffer is returned and
|
||||
* *trg_bufsize is updated with its size. On failure a NULL pointer is
|
||||
* returned. The returned buffer must be freed by the caller.
|
||||
*/
|
||||
extern void *git_delta_patch(
|
||||
const void *src_buf, unsigned long src_size,
|
||||
const void *delta_buf, unsigned long delta_size,
|
||||
unsigned long *dst_size);
|
||||
*out = NULL;
|
||||
*out_len = 0;
|
||||
|
||||
if ((error = git_delta_index_init(&index, src_buf, src_bufsize)) < 0)
|
||||
return error;
|
||||
|
||||
if (index) {
|
||||
error = git_delta_create_from_index(out, out_len,
|
||||
index, trg_buf, trg_bufsize, max_delta_size);
|
||||
|
||||
git_delta_index_free(index);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* the smallest possible delta size is 4 bytes */
|
||||
#define GIT_DELTA_SIZE_MIN 4
|
||||
|
||||
/*
|
||||
* This must be called twice on the delta data buffer, first to get the
|
||||
* expected source buffer size, and again to get the target buffer size.
|
||||
*/
|
||||
GIT_INLINE(unsigned long) git_delta_get_hdr_size(
|
||||
const unsigned char **datap, const unsigned char *top)
|
||||
{
|
||||
const unsigned char *data = *datap;
|
||||
unsigned long cmd, size = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
cmd = *data++;
|
||||
size |= (cmd & 0x7f) << i;
|
||||
i += 7;
|
||||
} while (cmd & 0x80 && data < top);
|
||||
*datap = data;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a git binary delta to recover the original content.
|
||||
* The caller is responsible for freeing the returned buffer.
|
||||
|
@ -270,20 +270,24 @@ static int create_binary(
|
||||
}
|
||||
|
||||
if (a_datalen && b_datalen) {
|
||||
void *delta_data = git_delta(
|
||||
a_data, (unsigned long)a_datalen,
|
||||
b_data, (unsigned long)b_datalen,
|
||||
&delta_data_len, (unsigned long)deflate.size);
|
||||
void *delta_data;
|
||||
|
||||
if (delta_data) {
|
||||
error = git_delta(&delta_data, &delta_data_len,
|
||||
a_data, a_datalen,
|
||||
b_data, b_datalen,
|
||||
deflate.size);
|
||||
|
||||
if (error == 0) {
|
||||
error = git_zstream_deflatebuf(
|
||||
&delta, delta_data, (size_t)delta_data_len);
|
||||
|
||||
git__free(delta_data);
|
||||
|
||||
if (error < 0)
|
||||
goto done;
|
||||
} else if (error == GIT_EBUFS) {
|
||||
error = 0;
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (delta.size && delta.size < deflate.size) {
|
||||
|
@ -274,6 +274,7 @@ static int get_delta(void **out, git_odb *odb, git_pobject *po)
|
||||
git_odb_object *src = NULL, *trg = NULL;
|
||||
unsigned long delta_size;
|
||||
void *delta_buf;
|
||||
int error;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
@ -281,12 +282,15 @@ static int get_delta(void **out, git_odb *odb, git_pobject *po)
|
||||
git_odb_read(&trg, odb, &po->id) < 0)
|
||||
goto on_error;
|
||||
|
||||
delta_buf = git_delta(
|
||||
git_odb_object_data(src), (unsigned long)git_odb_object_size(src),
|
||||
git_odb_object_data(trg), (unsigned long)git_odb_object_size(trg),
|
||||
&delta_size, 0);
|
||||
error = git_delta(&delta_buf, &delta_size,
|
||||
git_odb_object_data(src), git_odb_object_size(src),
|
||||
git_odb_object_data(trg), git_odb_object_size(trg),
|
||||
0);
|
||||
|
||||
if (!delta_buf || delta_size != po->delta_size) {
|
||||
if (error < 0 && error != GIT_EBUFS)
|
||||
goto on_error;
|
||||
|
||||
if (error == GIT_EBUFS || delta_size != po->delta_size) {
|
||||
giterr_set(GITERR_INVALID, "Delta size changed");
|
||||
goto on_error;
|
||||
}
|
||||
@ -815,16 +819,14 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
|
||||
*mem_usage += sz;
|
||||
}
|
||||
if (!src->index) {
|
||||
src->index = git_delta_create_index(src->data, src_size);
|
||||
if (!src->index)
|
||||
if (git_delta_index_init(&src->index, src->data, src_size) < 0)
|
||||
return 0; /* suboptimal pack - out of memory */
|
||||
|
||||
*mem_usage += git_delta_sizeof_index(src->index);
|
||||
*mem_usage += git_delta_index_size(src->index);
|
||||
}
|
||||
|
||||
delta_buf = git_delta_create(src->index, trg->data, trg_size,
|
||||
&delta_size, max_size);
|
||||
if (!delta_buf)
|
||||
if (git_delta_create_from_index(&delta_buf, &delta_size, src->index, trg->data, trg_size,
|
||||
max_size) < 0)
|
||||
return 0;
|
||||
|
||||
if (trg_object->delta) {
|
||||
@ -885,9 +887,14 @@ static unsigned int check_delta_limit(git_pobject *me, unsigned int n)
|
||||
|
||||
static unsigned long free_unpacked(struct unpacked *n)
|
||||
{
|
||||
unsigned long freed_mem = git_delta_sizeof_index(n->index);
|
||||
git_delta_free_index(n->index);
|
||||
unsigned long freed_mem = 0;
|
||||
|
||||
if (n->index) {
|
||||
freed_mem += git_delta_index_size(n->index);
|
||||
git_delta_index_free(n->index);
|
||||
}
|
||||
n->index = NULL;
|
||||
|
||||
if (n->data) {
|
||||
freed_mem += (unsigned long)n->object->size;
|
||||
git__free(n->data);
|
||||
|
Loading…
Reference in New Issue
Block a user