From 90191d37ab08f7c6810fa22804dedb23bade02a1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 12 Jul 2013 02:31:57 -0400 Subject: [PATCH] packed_object_info: hoist delta type resolution to helper To calculate the type of a packed object, we must walk down its delta chain until we hit a true base object with a real type. Most of the code in packed_object_info is for handling this case. Let's hoist it out into a separate helper function, which will make it easier to make the type-lookup optional in the future (and keep our indentation level sane). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- sha1_file.c | 123 +++++++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 55 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 285337819e..8fb10e451c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1710,9 +1710,75 @@ static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset) return type; } - #define POI_STACK_PREALLOC 64 +static enum object_type packed_to_object_type(struct packed_git *p, + off_t obj_offset, + enum object_type type, + struct pack_window **w_curs, + off_t curpos) +{ + off_t small_poi_stack[POI_STACK_PREALLOC]; + off_t *poi_stack = small_poi_stack; + int poi_stack_nr = 0, poi_stack_alloc = POI_STACK_PREALLOC; + + while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) { + off_t base_offset; + unsigned long size; + /* Push the object we're going to leave behind */ + if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) { + poi_stack_alloc = alloc_nr(poi_stack_nr); + poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc); + memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr); + } else { + ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc); + } + poi_stack[poi_stack_nr++] = obj_offset; + /* If parsing the base offset fails, just unwind */ + base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset); + if (!base_offset) + goto unwind; + curpos = obj_offset = base_offset; + type = unpack_object_header(p, w_curs, &curpos, &size); + if (type <= OBJ_NONE) { + /* If getting the base itself fails, we first + * retry the base, otherwise unwind */ + type = retry_bad_packed_offset(p, base_offset); + if (type > OBJ_NONE) + goto out; + goto unwind; + } + } + + switch (type) { + case OBJ_BAD: + case OBJ_COMMIT: + case OBJ_TREE: + case OBJ_BLOB: + case OBJ_TAG: + break; + default: + error("unknown object type %i at offset %"PRIuMAX" in %s", + type, (uintmax_t)obj_offset, p->pack_name); + type = OBJ_BAD; + } + +out: + if (poi_stack != small_poi_stack) + free(poi_stack); + return type; + +unwind: + while (poi_stack_nr) { + obj_offset = poi_stack[--poi_stack_nr]; + type = retry_bad_packed_offset(p, obj_offset); + if (type > OBJ_NONE) + goto out; + } + type = OBJ_BAD; + goto out; +} + static int packed_object_info(struct packed_git *p, off_t obj_offset, unsigned long *sizep, int *rtype, unsigned long *disk_sizep) @@ -1721,9 +1787,6 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset, unsigned long size; off_t curpos = obj_offset; enum object_type type; - off_t small_poi_stack[POI_STACK_PREALLOC]; - off_t *poi_stack = small_poi_stack; - int poi_stack_nr = 0, poi_stack_alloc = POI_STACK_PREALLOC; type = unpack_object_header(p, &w_curs, &curpos, &size); @@ -1754,61 +1817,11 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset, *disk_sizep = revidx[1].offset - obj_offset; } - while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) { - off_t base_offset; - /* Push the object we're going to leave behind */ - if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) { - poi_stack_alloc = alloc_nr(poi_stack_nr); - poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc); - memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr); - } else { - ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc); - } - poi_stack[poi_stack_nr++] = obj_offset; - /* If parsing the base offset fails, just unwind */ - base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset); - if (!base_offset) - goto unwind; - curpos = obj_offset = base_offset; - type = unpack_object_header(p, &w_curs, &curpos, &size); - if (type <= OBJ_NONE) { - /* If getting the base itself fails, we first - * retry the base, otherwise unwind */ - type = retry_bad_packed_offset(p, base_offset); - if (type > OBJ_NONE) - goto out; - goto unwind; - } - } - - switch (type) { - case OBJ_BAD: - case OBJ_COMMIT: - case OBJ_TREE: - case OBJ_BLOB: - case OBJ_TAG: - break; - default: - error("unknown object type %i at offset %"PRIuMAX" in %s", - type, (uintmax_t)obj_offset, p->pack_name); - type = OBJ_BAD; - } + type = packed_to_object_type(p, obj_offset, type, &w_curs, curpos); out: - if (poi_stack != small_poi_stack) - free(poi_stack); unuse_pack(&w_curs); return type; - -unwind: - while (poi_stack_nr) { - obj_offset = poi_stack[--poi_stack_nr]; - type = retry_bad_packed_offset(p, obj_offset); - if (type > OBJ_NONE) - goto out; - } - type = OBJ_BAD; - goto out; } static void *unpack_compressed_entry(struct packed_git *p,