diff options
author | Junio C Hamano <junkio@cox.net> | 2006-09-01 15:17:01 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-09-01 15:17:01 -0700 |
commit | ad1ed5ee896ba5d7f89bc04c7441b1532efb9853 (patch) | |
tree | 4d9cd7744f292ebbcca467e39e23ec7e08bc32ac | |
parent | 501524e938aee0b9691fe7fb1abf5eb17a23132f (diff) | |
download | git-ad1ed5ee896ba5d7f89bc04c7441b1532efb9853.tar.gz |
consolidate two copies of new style object header parsing code.
Also while we are at it, remove redundant typename[] array from
unpack_sha1_header. The only reason it is different from the
type_names[] array in object.c module is that this code cares
about the subset of object types that are valid in a loose
object, so prepare a separate array of boolean that tells us
which types are valid, and share the name translation with the
others.
Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r-- | sha1_file.c | 85 |
1 files changed, 45 insertions, 40 deletions
diff --git a/sha1_file.c b/sha1_file.c index ce90e200cb..76f66e6a85 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -711,17 +711,39 @@ int legacy_loose_object(unsigned char *map) return 0; } -static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep) { + unsigned shift; unsigned char c; - unsigned int bits; unsigned long size; - static const char *typename[8] = { - NULL, /* OBJ_EXT */ - "commit", "tree", "blob", "tag", - NULL, NULL, NULL + unsigned long used = 0; + + c = buf[used++]; + *type = (c >> 4) & 7; + size = c & 15; + shift = 4; + while (c & 0x80) { + if (len <= used) + return 0; + if (sizeof(long) * 8 <= shift) + return 0; + c = buf[used++]; + size += (c & 0x7f) << shift; + shift += 7; + } + *sizep = size; + return used; +} + +static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +{ + unsigned long size, used; + static const char valid_loose_object_type[8] = { + 0, /* OBJ_EXT */ + 1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */ + 0, /* "delta" and others are invalid in a loose object */ }; - const char *type; + enum object_type type; /* Get the data stream */ memset(stream, 0, sizeof(*stream)); @@ -735,22 +757,11 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon return inflate(stream, 0); } - c = *map++; - mapsize--; - type = typename[(c >> 4) & 7]; - if (!type) + used = unpack_object_header_gently(map, mapsize, &type, &size); + if (!used || !valid_loose_object_type[type]) return -1; - - bits = 4; - size = c & 0xf; - while ((c & 0x80)) { - if (bits >= 8*sizeof(long)) - return -1; - c = *map++; - size += (c & 0x7f) << bits; - bits += 7; - mapsize--; - } + map += used; + mapsize -= used; /* Set up the stream for the rest.. */ stream->next_in = map; @@ -758,7 +769,8 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon inflateInit(stream); /* And generate the fake traditional header */ - stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size); + stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", + type_names[type], size); return 0; } @@ -916,25 +928,18 @@ static int packed_delta_info(unsigned char *base_sha1, static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset, enum object_type *type, unsigned long *sizep) { - unsigned shift; - unsigned char c; - unsigned long size; + unsigned long used; - if (offset >= p->pack_size) + if (p->pack_size <= offset) die("object offset outside of pack file"); - c = *((unsigned char *)p->pack_base + offset++); - *type = (c >> 4) & 7; - size = c & 15; - shift = 4; - while (c & 0x80) { - if (offset >= p->pack_size) - die("object offset outside of pack file"); - c = *((unsigned char *)p->pack_base + offset++); - size += (c & 0x7f) << shift; - shift += 7; - } - *sizep = size; - return offset; + + used = unpack_object_header_gently((unsigned char *)p->pack_base + + offset, + p->pack_size - offset, type, sizep); + if (!used) + die("object offset outside of pack file"); + + return offset + used; } int check_reuse_pack_delta(struct packed_git *p, unsigned long offset, |