summaryrefslogtreecommitdiff
path: root/sha1_file.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-03-05 00:21:37 -0800
committerJunio C Hamano <junkio@cox.net>2007-03-05 00:55:19 -0800
commit7efbff7531af4281487d54c1dc1401308d988e33 (patch)
tree025cfaf2225fbc027534d0d4ccd31a45cd4be38f /sha1_file.c
parentefec43c028c52bc252afdaa586b46f83186d3eaa (diff)
downloadgit-7efbff7531af4281487d54c1dc1401308d988e33.tar.gz
unpack_sha1_file(): detect corrupt loose object files.
We did not detect broken loose object files, either when underlying inflate() signalled the breakage, nor inflate() finished and we had garbage trailing at the end. We do better now. We also make unpack_sha1_file() a static function to sha1_file.c, since it is not used by anybody outside. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'sha1_file.c')
-rw-r--r--sha1_file.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/sha1_file.c b/sha1_file.c
index 6d0a72ed09..ac6b5e00b6 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -956,11 +956,12 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
return 0;
}
-static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size)
+static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
{
int bytes = strlen(buffer) + 1;
unsigned char *buf = xmalloc(1+size);
unsigned long n;
+ int status = Z_OK;
n = stream->total_out - bytes;
if (n > size)
@@ -970,12 +971,22 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size
if (bytes < size) {
stream->next_out = buf + bytes;
stream->avail_out = size - bytes;
- while (inflate(stream, Z_FINISH) == Z_OK)
- /* nothing */;
+ while (status == Z_OK)
+ status = inflate(stream, Z_FINISH);
}
buf[size] = 0;
- inflateEnd(stream);
- return buf;
+ if ((status == Z_OK || status == Z_STREAM_END) && !stream->avail_in) {
+ inflateEnd(stream);
+ return buf;
+ }
+
+ if (status < 0)
+ error("corrupt loose object '%s'", sha1_to_hex(sha1));
+ else if (stream->avail_in)
+ error("garbage at end of loose object '%s'",
+ sha1_to_hex(sha1));
+ free(buf);
+ return NULL;
}
/*
@@ -1029,7 +1040,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep)
return *hdr ? -1 : type_from_string(type);
}
-void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size)
+static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
{
int ret;
z_stream stream;
@@ -1039,7 +1050,7 @@ void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type
if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
return NULL;
- return unpack_sha1_rest(&stream, hdr, *size);
+ return unpack_sha1_rest(&stream, hdr, *size, sha1);
}
static unsigned long get_delta_base(struct packed_git *p,
@@ -1555,7 +1566,7 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
return buf;
map = map_sha1_file(sha1, &mapsize);
if (map) {
- buf = unpack_sha1_file(map, mapsize, type, size);
+ buf = unpack_sha1_file(map, mapsize, type, size, sha1);
munmap(map, mapsize);
return buf;
}