mirror of
https://github.com/git/git.git
synced 2024-11-18 20:03:54 +01:00
unpack-objects: fix --strict handling
Earlier attempt (which was reverted) called added_object() (by the way, the function should be renamed to resolve_dependents() --- it is called when we have a complete object data, and is responsible to resolve pending deltified objects that use this object as their delta base object) without updating obj_list[nr].sha1 with the correct value. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
c0e809e5c0
commit
f2898cfadc
@ -21,6 +21,11 @@ static unsigned int offset, len;
|
|||||||
static off_t consumed_bytes;
|
static off_t consumed_bytes;
|
||||||
static SHA_CTX ctx;
|
static SHA_CTX ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When running under --strict mode, objects whose reachability are
|
||||||
|
* suspect are kept in core without getting written in the object
|
||||||
|
* store.
|
||||||
|
*/
|
||||||
struct obj_buffer {
|
struct obj_buffer {
|
||||||
char *buffer;
|
char *buffer;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
@ -155,6 +160,10 @@ struct obj_info {
|
|||||||
static struct obj_info *obj_list;
|
static struct obj_info *obj_list;
|
||||||
unsigned nr_objects;
|
unsigned nr_objects;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called only from check_object() after it verified this object
|
||||||
|
* is Ok.
|
||||||
|
*/
|
||||||
static void write_cached_object(struct object *obj)
|
static void write_cached_object(struct object *obj)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
@ -164,6 +173,11 @@ static void write_cached_object(struct object *obj)
|
|||||||
obj->flags |= FLAG_WRITTEN;
|
obj->flags |= FLAG_WRITTEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the very end of the processing, write_rest() scans the objects
|
||||||
|
* that have reachability requirements and calls this function.
|
||||||
|
* Verify its reachability and validity recursively and write it out.
|
||||||
|
*/
|
||||||
static int check_object(struct object *obj, int type, void *data)
|
static int check_object(struct object *obj, int type, void *data)
|
||||||
{
|
{
|
||||||
if (!obj)
|
if (!obj)
|
||||||
@ -202,19 +216,25 @@ static void write_rest(void)
|
|||||||
static void added_object(unsigned nr, enum object_type type,
|
static void added_object(unsigned nr, enum object_type type,
|
||||||
void *data, unsigned long size);
|
void *data, unsigned long size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out nr-th object from the list, now we know the contents
|
||||||
|
* of it. Under --strict, this buffers structured objects in-core,
|
||||||
|
* to be checked at the end.
|
||||||
|
*/
|
||||||
static void write_object(unsigned nr, enum object_type type,
|
static void write_object(unsigned nr, enum object_type type,
|
||||||
void *buf, unsigned long size)
|
void *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
added_object(nr, type, buf, size);
|
|
||||||
if (!strict) {
|
if (!strict) {
|
||||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||||
die("failed to write object");
|
die("failed to write object");
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
free(buf);
|
free(buf);
|
||||||
obj_list[nr].obj = 0;
|
obj_list[nr].obj = NULL;
|
||||||
} else if (type == OBJ_BLOB) {
|
} else if (type == OBJ_BLOB) {
|
||||||
struct blob *blob;
|
struct blob *blob;
|
||||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||||
die("failed to write object");
|
die("failed to write object");
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
blob = lookup_blob(obj_list[nr].sha1);
|
blob = lookup_blob(obj_list[nr].sha1);
|
||||||
@ -222,15 +242,15 @@ static void write_object(unsigned nr, enum object_type type,
|
|||||||
blob->object.flags |= FLAG_WRITTEN;
|
blob->object.flags |= FLAG_WRITTEN;
|
||||||
else
|
else
|
||||||
die("invalid blob object");
|
die("invalid blob object");
|
||||||
obj_list[nr].obj = 0;
|
obj_list[nr].obj = NULL;
|
||||||
} else {
|
} else {
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
int eaten;
|
int eaten;
|
||||||
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
|
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
|
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
die("invalid %s", typename(type));
|
die("invalid %s", typename(type));
|
||||||
/* buf is stored via add_object_buffer and in obj, if its a tree or commit */
|
|
||||||
add_object_buffer(obj, buf, size);
|
add_object_buffer(obj, buf, size);
|
||||||
obj->flags |= FLAG_OPEN;
|
obj->flags |= FLAG_OPEN;
|
||||||
obj_list[nr].obj = obj;
|
obj_list[nr].obj = obj;
|
||||||
@ -253,6 +273,10 @@ static void resolve_delta(unsigned nr, enum object_type type,
|
|||||||
write_object(nr, type, result, result_size);
|
write_object(nr, type, result, result_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We now know the contents of an object (which is nr-th in the pack);
|
||||||
|
* resolve all the deltified objects that are based on it.
|
||||||
|
*/
|
||||||
static void added_object(unsigned nr, enum object_type type,
|
static void added_object(unsigned nr, enum object_type type,
|
||||||
void *data, unsigned long size)
|
void *data, unsigned long size)
|
||||||
{
|
{
|
||||||
@ -284,13 +308,28 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
|
|||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int resolve_against_held(unsigned nr, const unsigned char *base,
|
||||||
|
void *delta_data, unsigned long delta_size)
|
||||||
|
{
|
||||||
|
struct object *obj;
|
||||||
|
struct obj_buffer *obj_buffer;
|
||||||
|
obj = lookup_object(base);
|
||||||
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
obj_buffer = lookup_object_buffer(obj);
|
||||||
|
if (!obj_buffer)
|
||||||
|
return 0;
|
||||||
|
resolve_delta(nr, obj->type, obj_buffer->buffer,
|
||||||
|
obj_buffer->size, delta_data, delta_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||||
unsigned nr)
|
unsigned nr)
|
||||||
{
|
{
|
||||||
void *delta_data, *base;
|
void *delta_data, *base;
|
||||||
unsigned long base_size;
|
unsigned long base_size;
|
||||||
unsigned char base_sha1[20];
|
unsigned char base_sha1[20];
|
||||||
struct object *obj;
|
|
||||||
|
|
||||||
if (type == OBJ_REF_DELTA) {
|
if (type == OBJ_REF_DELTA) {
|
||||||
hashcpy(base_sha1, fill(20));
|
hashcpy(base_sha1, fill(20));
|
||||||
@ -300,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||||||
free(delta_data);
|
free(delta_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!has_sha1_file(base_sha1)) {
|
if (has_sha1_file(base_sha1))
|
||||||
|
; /* Ok we have this one */
|
||||||
|
else if (resolve_against_held(nr, base_sha1,
|
||||||
|
delta_data, delta_size))
|
||||||
|
return; /* we are done */
|
||||||
|
else {
|
||||||
|
/* cannot resolve yet --- queue it */
|
||||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||||
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
||||||
return;
|
return;
|
||||||
@ -346,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!base_found) {
|
if (!base_found) {
|
||||||
/* The delta base object is itself a delta that
|
/*
|
||||||
has not been resolved yet. */
|
* The delta base object is itself a delta that
|
||||||
|
* has not been resolved yet.
|
||||||
|
*/
|
||||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||||
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = lookup_object(base_sha1);
|
if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
|
||||||
if (obj) {
|
return;
|
||||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
|
||||||
if (obj_buf) {
|
|
||||||
resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base = read_sha1_file(base_sha1, &type, &base_size);
|
base = read_sha1_file(base_sha1, &type, &base_size);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
|
@ -274,7 +274,7 @@ test_expect_success \
|
|||||||
packname_4=$(git pack-objects test-4 <obj-list) &&
|
packname_4=$(git pack-objects test-4 <obj-list) &&
|
||||||
test 3 = $(ls test-4-*.pack | wc -l)'
|
test 3 = $(ls test-4-*.pack | wc -l)'
|
||||||
|
|
||||||
test_expect_failure 'unpacking with --strict' '
|
test_expect_success 'unpacking with --strict' '
|
||||||
|
|
||||||
git config --unset pack.packsizelimit &&
|
git config --unset pack.packsizelimit &&
|
||||||
for j in a b c d e f g
|
for j in a b c d e f g
|
||||||
|
Loading…
Reference in New Issue
Block a user