Skip to content

Commit 46f0344

Browse files
KarthikNayakgitster
authored andcommitted
sha1_file: support reading from a loose object of unknown type
Update sha1_loose_object_info() to optionally allow it to read from a loose object file of unknown/bogus type; as the function usually returns the type of the object it read in the form of enum for known types, add an optional "typename" field to receive the name of the type in textual form and a flag to indicate the reading of a loose object file of unknown/bogus type. Add parse_sha1_header_extended() which acts as a wrapper around parse_sha1_header() allowing more information to be obtained. Add unpack_sha1_header_to_strbuf() to unpack sha1 headers of unknown/corrupt objects which have a unknown sha1 header size to a strbuf structure. This was written by Junio C Hamano but tested by me. Helped-by: Junio C Hamano <[email protected]> Helped-by: Eric Sunshine <[email protected]> Helped-by: Ramsay Jones <[email protected]> Hepled-by: Jeff King <[email protected]> Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2dfb2e0 commit 46f0344

File tree

2 files changed

+108
-22
lines changed

2 files changed

+108
-22
lines changed

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ extern int is_ntfs_dotgit(const char *name);
838838

839839
/* object replacement */
840840
#define LOOKUP_REPLACE_OBJECT 1
841+
#define LOOKUP_UNKNOWN_OBJECT 2
841842
extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
842843
static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
843844
{
@@ -1304,6 +1305,7 @@ struct object_info {
13041305
unsigned long *sizep;
13051306
unsigned long *disk_sizep;
13061307
unsigned char *delta_base_sha1;
1308+
struct strbuf *typename;
13071309

13081310
/* Response */
13091311
enum {

sha1_file.c

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
15671601
static 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

16631720
static 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

25262583
static 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

Comments
 (0)