From: Linus Torvalds Date: Thu, 2 Jun 2005 14:57:25 +0000 (-0700) Subject: Split up unpack_sha1_file() some more X-Git-Tag: v0.99~387 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=5180cacc202bb20b15981469487eb8d6b0509997;p=git.git Split up unpack_sha1_file() some more Make a separate helper for parsing the header of an object file (really carefully) and for unpacking the rest. This means that anybody who uses the "unpack_sha1_header()" interface can easily look at the header and decide to unpack the rest too, without doing any extra work. --- diff --git a/cache.h b/cache.h index 69b63ba1..aa74bcc0 100644 --- a/cache.h +++ b/cache.h @@ -152,6 +152,7 @@ extern char *sha1_file_name(const unsigned char *sha1); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size); extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size); +extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep); extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size); extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size); extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1); diff --git a/sha1_file.c b/sha1_file.c index bc3d70fd..af39e886 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -320,31 +320,85 @@ int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void return inflate(stream, 0); } +void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size) +{ + int bytes = strlen(buffer) + 1; + char *buf = xmalloc(1+size); + + memcpy(buf, buffer + bytes, stream->total_out - bytes); + bytes = stream->total_out - bytes; + if (bytes < size) { + stream->next_out = buf + bytes; + stream->avail_out = size - bytes; + while (inflate(stream, Z_FINISH) == Z_OK) + /* nothing */; + } + buf[size] = 0; + inflateEnd(stream); + return buf; +} + +/* + * We used to just use "sscanf()", but that's actually way + * too permissive for what we want to check. So do an anal + * object header parse by hand. + */ +int parse_sha1_header(char *hdr, char *type, unsigned long *sizep) +{ + int i; + unsigned long size; + + /* + * The type can be at most ten bytes (including the + * terminating '\0' that we add), and is followed by + * a space. + */ + i = 10; + for (;;) { + char c = *hdr++; + if (c == ' ') + break; + if (!--i) + return -1; + *type++ = c; + } + *type = 0; + + /* + * The length must follow immediately, and be in canonical + * decimal format (ie "010" is not valid). + */ + size = *hdr++ - '0'; + if (size > 9) + return -1; + if (size) { + for (;;) { + unsigned long c = *hdr - '0'; + if (c > 9) + break; + hdr++; + size = size * 10 + c; + } + } + *sizep = size; + + /* + * The length must be followed by a zero byte + */ + return *hdr ? -1 : 0; +} + void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size) { - int ret, bytes; + int ret; z_stream stream; - char buffer[8192]; - unsigned char *buf; + char hdr[8192]; - ret = unpack_sha1_header(&stream, map, mapsize, buffer, sizeof(buffer)); - if (ret < Z_OK || sscanf(buffer, "%10s %lu", type, size) != 2) + ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)); + if (ret < Z_OK || parse_sha1_header(hdr, type, size) < 0) return NULL; - bytes = strlen(buffer) + 1; - buf = xmalloc(1+*size); - - memcpy(buf, buffer + bytes, stream.total_out - bytes); - bytes = stream.total_out - bytes; - if (bytes < *size && ret == Z_OK) { - stream.next_out = buf + bytes; - stream.avail_out = *size - bytes; - while (inflate(&stream, Z_FINISH) == Z_OK) - /* nothing */; - } - buf[*size] = 0; - inflateEnd(&stream); - return buf; + return unpack_sha1_rest(&stream, hdr, *size); } void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)