Split up unpack_sha1_file() some more
authorLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 2 Jun 2005 14:57:25 +0000 (07:57 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 2 Jun 2005 14:57:25 +0000 (07:57 -0700)
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.

cache.h
sha1_file.c

diff --git a/cache.h b/cache.h
index 69b63ba1d40d7891b9814fa97535fc6489564ad8..aa74bcc0179fc20c4ddc490d6da4bf0730a2fb9e 100644 (file)
--- 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);
index bc3d70fdd63bba3e508a23bc983590e5bbd3f8f5..af39e8860ec55d420c724a079be02379288e3f61 100644 (file)
@@ -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)