@@ -1564,6 +1564,40 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma
15641564 return git_inflate (stream , 0 );
15651565}
15661566
1567+ static int unpack_sha1_header_to_strbuf (git_zstream * stream , unsigned char * map ,
1568+ unsigned long mapsize , void * buffer ,
1569+ unsigned long bufsiz , struct strbuf * header )
1570+ {
1571+ int status ;
1572+
1573+ status = unpack_sha1_header (stream , map , mapsize , buffer , bufsiz );
1574+
1575+ /*
1576+ * Check if entire header is unpacked in the first iteration.
1577+ */
1578+ if (memchr (buffer , '\0' , stream -> next_out - (unsigned char * )buffer ))
1579+ return 0 ;
1580+
1581+ /*
1582+ * buffer[0..bufsiz] was not large enough. Copy the partial
1583+ * result out to header, and then append the result of further
1584+ * reading the stream.
1585+ */
1586+ strbuf_add (header , buffer , stream -> next_out - (unsigned char * )buffer );
1587+ stream -> next_out = buffer ;
1588+ stream -> avail_out = bufsiz ;
1589+
1590+ do {
1591+ status = git_inflate (stream , 0 );
1592+ strbuf_add (header , buffer , stream -> next_out - (unsigned char * )buffer );
1593+ if (memchr (buffer , '\0' , stream -> next_out - (unsigned char * )buffer ))
1594+ return 0 ;
1595+ stream -> next_out = buffer ;
1596+ stream -> avail_out = bufsiz ;
1597+ } while (status != Z_STREAM_END );
1598+ return -1 ;
1599+ }
1600+
15671601static void * unpack_sha1_rest (git_zstream * stream , void * buffer , unsigned long size , const unsigned char * sha1 )
15681602{
15691603 int bytes = strlen (buffer ) + 1 ;
@@ -1614,27 +1648,38 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
16141648 * too permissive for what we want to check. So do an anal
16151649 * object header parse by hand.
16161650 */
1617- int parse_sha1_header (const char * hdr , unsigned long * sizep )
1651+ static int parse_sha1_header_extended (const char * hdr , struct object_info * oi ,
1652+ unsigned int flags )
16181653{
1619- char type [10 ];
1620- int i ;
1654+ const char * type_buf = hdr ;
16211655 unsigned long size ;
1656+ int type , type_len = 0 ;
16221657
16231658 /*
1624- * The type can be at most ten bytes (including the
1625- * terminating '\0' that we add), and is followed by
1659+ * The type can be of any size but is followed by
16261660 * a space.
16271661 */
1628- i = 0 ;
16291662 for (;;) {
16301663 char c = * hdr ++ ;
16311664 if (c == ' ' )
16321665 break ;
1633- type [i ++ ] = c ;
1634- if (i >= sizeof (type ))
1635- return -1 ;
1666+ type_len ++ ;
16361667 }
1637- type [i ] = 0 ;
1668+
1669+ type = type_from_string_gently (type_buf , type_len , 1 );
1670+ if (oi -> typename )
1671+ strbuf_add (oi -> typename , type_buf , type_len );
1672+ /*
1673+ * Set type to 0 if its an unknown object and
1674+ * we're obtaining the type using '--allow-unkown-type'
1675+ * option.
1676+ */
1677+ if ((flags & LOOKUP_UNKNOWN_OBJECT ) && (type < 0 ))
1678+ type = 0 ;
1679+ else if (type < 0 )
1680+ die ("invalid object type" );
1681+ if (oi -> typep )
1682+ * oi -> typep = type ;
16381683
16391684 /*
16401685 * The length must follow immediately, and be in canonical
@@ -1652,12 +1697,24 @@ int parse_sha1_header(const char *hdr, unsigned long *sizep)
16521697 size = size * 10 + c ;
16531698 }
16541699 }
1655- * sizep = size ;
1700+
1701+ if (oi -> sizep )
1702+ * oi -> sizep = size ;
16561703
16571704 /*
16581705 * The length must be followed by a zero byte
16591706 */
1660- return * hdr ? -1 : type_from_string (type );
1707+ return * hdr ? -1 : type ;
1708+ }
1709+
1710+ int parse_sha1_header (const char * hdr , unsigned long * sizep )
1711+ {
1712+ struct object_info oi ;
1713+
1714+ oi .sizep = sizep ;
1715+ oi .typename = NULL ;
1716+ oi .typep = NULL ;
1717+ return parse_sha1_header_extended (hdr , & oi , LOOKUP_REPLACE_OBJECT );
16611718}
16621719
16631720static void * unpack_sha1_file (void * map , unsigned long mapsize , enum object_type * type , unsigned long * size , const unsigned char * sha1 )
@@ -2524,13 +2581,15 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
25242581}
25252582
25262583static int sha1_loose_object_info (const unsigned char * sha1 ,
2527- struct object_info * oi )
2584+ struct object_info * oi ,
2585+ int flags )
25282586{
2529- int status ;
2530- unsigned long mapsize , size ;
2587+ int status = 0 ;
2588+ unsigned long mapsize ;
25312589 void * map ;
25322590 git_zstream stream ;
25332591 char hdr [32 ];
2592+ struct strbuf hdrbuf = STRBUF_INIT ;
25342593
25352594 if (oi -> delta_base_sha1 )
25362595 hashclr (oi -> delta_base_sha1 );
@@ -2543,7 +2602,7 @@ static int sha1_loose_object_info(const unsigned char *sha1,
25432602 * return value implicitly indicates whether the
25442603 * object even exists.
25452604 */
2546- if (!oi -> typep && !oi -> sizep ) {
2605+ if (!oi -> typep && !oi -> typename && ! oi -> sizep ) {
25472606 struct stat st ;
25482607 if (stat_sha1_file (sha1 , & st ) < 0 )
25492608 return -1 ;
@@ -2557,17 +2616,26 @@ static int sha1_loose_object_info(const unsigned char *sha1,
25572616 return -1 ;
25582617 if (oi -> disk_sizep )
25592618 * oi -> disk_sizep = mapsize ;
2560- if (unpack_sha1_header (& stream , map , mapsize , hdr , sizeof (hdr )) < 0 )
2619+ if ((flags & LOOKUP_UNKNOWN_OBJECT )) {
2620+ if (unpack_sha1_header_to_strbuf (& stream , map , mapsize , hdr , sizeof (hdr ), & hdrbuf ) < 0 )
2621+ status = error ("unable to unpack %s header with --allow-unknown-type" ,
2622+ sha1_to_hex (sha1 ));
2623+ } else if (unpack_sha1_header (& stream , map , mapsize , hdr , sizeof (hdr )) < 0 )
25612624 status = error ("unable to unpack %s header" ,
25622625 sha1_to_hex (sha1 ));
2563- else if ((status = parse_sha1_header (hdr , & size )) < 0 )
2626+ if (status < 0 )
2627+ ; /* Do nothing */
2628+ else if (hdrbuf .len ) {
2629+ if ((status = parse_sha1_header_extended (hdrbuf .buf , oi , flags )) < 0 )
2630+ status = error ("unable to parse %s header with --allow-unknown-type" ,
2631+ sha1_to_hex (sha1 ));
2632+ } else if ((status = parse_sha1_header_extended (hdr , oi , flags )) < 0 )
25642633 status = error ("unable to parse %s header" , sha1_to_hex (sha1 ));
2565- else if (oi -> sizep )
2566- * oi -> sizep = size ;
25672634 git_inflate_end (& stream );
25682635 munmap (map , mapsize );
2569- if (oi -> typep )
2636+ if (status && oi -> typep )
25702637 * oi -> typep = status ;
2638+ strbuf_release (& hdrbuf );
25712639 return 0 ;
25722640}
25732641
@@ -2576,6 +2644,7 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
25762644 struct cached_object * co ;
25772645 struct pack_entry e ;
25782646 int rtype ;
2647+ enum object_type real_type ;
25792648 const unsigned char * real = lookup_replace_object_extended (sha1 , flags );
25802649
25812650 co = find_cached_object (real );
@@ -2588,13 +2657,15 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
25882657 * (oi -> disk_sizep ) = 0 ;
25892658 if (oi -> delta_base_sha1 )
25902659 hashclr (oi -> delta_base_sha1 );
2660+ if (oi -> typename )
2661+ strbuf_addstr (oi -> typename , typename (co -> type ));
25912662 oi -> whence = OI_CACHED ;
25922663 return 0 ;
25932664 }
25942665
25952666 if (!find_pack_entry (real , & e )) {
25962667 /* Most likely it's a loose object. */
2597- if (!sha1_loose_object_info (real , oi )) {
2668+ if (!sha1_loose_object_info (real , oi , flags )) {
25982669 oi -> whence = OI_LOOSE ;
25992670 return 0 ;
26002671 }
@@ -2605,9 +2676,18 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
26052676 return -1 ;
26062677 }
26072678
2679+ /*
2680+ * packed_object_info() does not follow the delta chain to
2681+ * find out the real type, unless it is given oi->typep.
2682+ */
2683+ if (oi -> typename && !oi -> typep )
2684+ oi -> typep = & real_type ;
2685+
26082686 rtype = packed_object_info (e .p , e .offset , oi );
26092687 if (rtype < 0 ) {
26102688 mark_bad_packed_object (e .p , real );
2689+ if (oi -> typep == & real_type )
2690+ oi -> typep = NULL ;
26112691 return sha1_object_info_extended (real , oi , 0 );
26122692 } else if (in_delta_base_cache (e .p , e .offset )) {
26132693 oi -> whence = OI_DBCACHED ;
@@ -2618,6 +2698,10 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
26182698 oi -> u .packed .is_delta = (rtype == OBJ_REF_DELTA ||
26192699 rtype == OBJ_OFS_DELTA );
26202700 }
2701+ if (oi -> typename )
2702+ strbuf_addstr (oi -> typename , typename (* oi -> typep ));
2703+ if (oi -> typep == & real_type )
2704+ oi -> typep = NULL ;
26212705
26222706 return 0 ;
26232707}
0 commit comments