@@ -1306,6 +1306,26 @@ static int git_open_noatime(const char *name)
13061306 }
13071307}
13081308
1309+ static int stat_sha1_file (const unsigned char * sha1 , struct stat * st )
1310+ {
1311+ char * name = sha1_file_name (sha1 );
1312+ struct alternate_object_database * alt ;
1313+
1314+ if (!lstat (name , st ))
1315+ return 0 ;
1316+
1317+ prepare_alt_odb ();
1318+ errno = ENOENT ;
1319+ for (alt = alt_odb_list ; alt ; alt = alt -> next ) {
1320+ name = alt -> name ;
1321+ fill_sha1_path (name , sha1 );
1322+ if (!lstat (alt -> base , st ))
1323+ return 0 ;
1324+ }
1325+
1326+ return -1 ;
1327+ }
1328+
13091329static int open_sha1_file (const unsigned char * sha1 )
13101330{
13111331 int fd ;
@@ -1693,52 +1713,21 @@ static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset)
16931713 return type ;
16941714}
16951715
1696-
16971716#define POI_STACK_PREALLOC 64
16981717
1699- static int packed_object_info (struct packed_git * p , off_t obj_offset ,
1700- unsigned long * sizep , int * rtype ,
1701- unsigned long * disk_sizep )
1718+ static enum object_type packed_to_object_type (struct packed_git * p ,
1719+ off_t obj_offset ,
1720+ enum object_type type ,
1721+ struct pack_window * * w_curs ,
1722+ off_t curpos )
17021723{
1703- struct pack_window * w_curs = NULL ;
1704- unsigned long size ;
1705- off_t curpos = obj_offset ;
1706- enum object_type type ;
17071724 off_t small_poi_stack [POI_STACK_PREALLOC ];
17081725 off_t * poi_stack = small_poi_stack ;
17091726 int poi_stack_nr = 0 , poi_stack_alloc = POI_STACK_PREALLOC ;
17101727
1711- type = unpack_object_header (p , & w_curs , & curpos , & size );
1712-
1713- if (rtype )
1714- * rtype = type ; /* representation type */
1715-
1716- if (sizep ) {
1717- if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA ) {
1718- off_t tmp_pos = curpos ;
1719- off_t base_offset = get_delta_base (p , & w_curs , & tmp_pos ,
1720- type , obj_offset );
1721- if (!base_offset ) {
1722- type = OBJ_BAD ;
1723- goto out ;
1724- }
1725- * sizep = get_size_from_delta (p , & w_curs , tmp_pos );
1726- if (* sizep == 0 ) {
1727- type = OBJ_BAD ;
1728- goto out ;
1729- }
1730- } else {
1731- * sizep = size ;
1732- }
1733- }
1734-
1735- if (disk_sizep ) {
1736- struct revindex_entry * revidx = find_pack_revindex (p , obj_offset );
1737- * disk_sizep = revidx [1 ].offset - obj_offset ;
1738- }
1739-
17401728 while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA ) {
17411729 off_t base_offset ;
1730+ unsigned long size ;
17421731 /* Push the object we're going to leave behind */
17431732 if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack ) {
17441733 poi_stack_alloc = alloc_nr (poi_stack_nr );
@@ -1749,11 +1738,11 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
17491738 }
17501739 poi_stack [poi_stack_nr ++ ] = obj_offset ;
17511740 /* If parsing the base offset fails, just unwind */
1752- base_offset = get_delta_base (p , & w_curs , & curpos , type , obj_offset );
1741+ base_offset = get_delta_base (p , w_curs , & curpos , type , obj_offset );
17531742 if (!base_offset )
17541743 goto unwind ;
17551744 curpos = obj_offset = base_offset ;
1756- type = unpack_object_header (p , & w_curs , & curpos , & size );
1745+ type = unpack_object_header (p , w_curs , & curpos , & size );
17571746 if (type <= OBJ_NONE ) {
17581747 /* If getting the base itself fails, we first
17591748 * retry the base, otherwise unwind */
@@ -1780,7 +1769,6 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
17801769out :
17811770 if (poi_stack != small_poi_stack )
17821771 free (poi_stack );
1783- unuse_pack (& w_curs );
17841772 return type ;
17851773
17861774unwind :
@@ -1794,6 +1782,57 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
17941782 goto out ;
17951783}
17961784
1785+ static int packed_object_info (struct packed_git * p , off_t obj_offset ,
1786+ struct object_info * oi )
1787+ {
1788+ struct pack_window * w_curs = NULL ;
1789+ unsigned long size ;
1790+ off_t curpos = obj_offset ;
1791+ enum object_type type ;
1792+
1793+ /*
1794+ * We always get the representation type, but only convert it to
1795+ * a "real" type later if the caller is interested.
1796+ */
1797+ type = unpack_object_header (p , & w_curs , & curpos , & size );
1798+
1799+ if (oi -> sizep ) {
1800+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA ) {
1801+ off_t tmp_pos = curpos ;
1802+ off_t base_offset = get_delta_base (p , & w_curs , & tmp_pos ,
1803+ type , obj_offset );
1804+ if (!base_offset ) {
1805+ type = OBJ_BAD ;
1806+ goto out ;
1807+ }
1808+ * oi -> sizep = get_size_from_delta (p , & w_curs , tmp_pos );
1809+ if (* oi -> sizep == 0 ) {
1810+ type = OBJ_BAD ;
1811+ goto out ;
1812+ }
1813+ } else {
1814+ * oi -> sizep = size ;
1815+ }
1816+ }
1817+
1818+ if (oi -> disk_sizep ) {
1819+ struct revindex_entry * revidx = find_pack_revindex (p , obj_offset );
1820+ * oi -> disk_sizep = revidx [1 ].offset - obj_offset ;
1821+ }
1822+
1823+ if (oi -> typep ) {
1824+ * oi -> typep = packed_to_object_type (p , obj_offset , type , & w_curs , curpos );
1825+ if (* oi -> typep < 0 ) {
1826+ type = OBJ_BAD ;
1827+ goto out ;
1828+ }
1829+ }
1830+
1831+ out :
1832+ unuse_pack (& w_curs );
1833+ return type ;
1834+ }
1835+
17971836static void * unpack_compressed_entry (struct packed_git * p ,
17981837 struct pack_window * * w_curs ,
17991838 off_t curpos ,
@@ -2363,68 +2402,84 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
23632402
23642403}
23652404
2366- static int sha1_loose_object_info (const unsigned char * sha1 , unsigned long * sizep ,
2367- unsigned long * disk_sizep )
2405+ static int sha1_loose_object_info (const unsigned char * sha1 ,
2406+ struct object_info * oi )
23682407{
23692408 int status ;
23702409 unsigned long mapsize , size ;
23712410 void * map ;
23722411 git_zstream stream ;
23732412 char hdr [32 ];
23742413
2414+ /*
2415+ * If we don't care about type or size, then we don't
2416+ * need to look inside the object at all.
2417+ */
2418+ if (!oi -> typep && !oi -> sizep ) {
2419+ if (oi -> disk_sizep ) {
2420+ struct stat st ;
2421+ if (stat_sha1_file (sha1 , & st ) < 0 )
2422+ return -1 ;
2423+ * oi -> disk_sizep = st .st_size ;
2424+ }
2425+ return 0 ;
2426+ }
2427+
23752428 map = map_sha1_file (sha1 , & mapsize );
23762429 if (!map )
23772430 return -1 ;
2378- if (disk_sizep )
2379- * disk_sizep = mapsize ;
2431+ if (oi -> disk_sizep )
2432+ * oi -> disk_sizep = mapsize ;
23802433 if (unpack_sha1_header (& stream , map , mapsize , hdr , sizeof (hdr )) < 0 )
23812434 status = error ("unable to unpack %s header" ,
23822435 sha1_to_hex (sha1 ));
23832436 else if ((status = parse_sha1_header (hdr , & size )) < 0 )
23842437 status = error ("unable to parse %s header" , sha1_to_hex (sha1 ));
2385- else if (sizep )
2386- * sizep = size ;
2438+ else if (oi -> sizep )
2439+ * oi -> sizep = size ;
23872440 git_inflate_end (& stream );
23882441 munmap (map , mapsize );
2389- return status ;
2442+ if (oi -> typep )
2443+ * oi -> typep = status ;
2444+ return 0 ;
23902445}
23912446
23922447/* returns enum object_type or negative */
23932448int sha1_object_info_extended (const unsigned char * sha1 , struct object_info * oi )
23942449{
23952450 struct cached_object * co ;
23962451 struct pack_entry e ;
2397- int status , rtype ;
2452+ int rtype ;
23982453
23992454 co = find_cached_object (sha1 );
24002455 if (co ) {
2456+ if (oi -> typep )
2457+ * (oi -> typep ) = co -> type ;
24012458 if (oi -> sizep )
24022459 * (oi -> sizep ) = co -> size ;
24032460 if (oi -> disk_sizep )
24042461 * (oi -> disk_sizep ) = 0 ;
24052462 oi -> whence = OI_CACHED ;
2406- return co -> type ;
2463+ return 0 ;
24072464 }
24082465
24092466 if (!find_pack_entry (sha1 , & e )) {
24102467 /* Most likely it's a loose object. */
2411- status = sha1_loose_object_info (sha1 , oi -> sizep , oi -> disk_sizep );
2412- if (status >= 0 ) {
2468+ if (!sha1_loose_object_info (sha1 , oi )) {
24132469 oi -> whence = OI_LOOSE ;
2414- return status ;
2470+ return 0 ;
24152471 }
24162472
24172473 /* Not a loose object; someone else may have just packed it. */
24182474 reprepare_packed_git ();
24192475 if (!find_pack_entry (sha1 , & e ))
2420- return status ;
2476+ return -1 ;
24212477 }
24222478
2423- status = packed_object_info (e .p , e .offset , oi -> sizep , & rtype ,
2424- oi -> disk_sizep );
2425- if (status < 0 ) {
2479+ rtype = packed_object_info (e .p , e .offset , oi );
2480+ if (rtype < 0 ) {
24262481 mark_bad_packed_object (e .p , sha1 );
2427- status = sha1_object_info_extended (sha1 , oi );
2482+ return sha1_object_info_extended (sha1 , oi );
24282483 } else if (in_delta_base_cache (e .p , e .offset )) {
24292484 oi -> whence = OI_DBCACHED ;
24302485 } else {
@@ -2435,15 +2490,19 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
24352490 rtype == OBJ_OFS_DELTA );
24362491 }
24372492
2438- return status ;
2493+ return 0 ;
24392494}
24402495
24412496int sha1_object_info (const unsigned char * sha1 , unsigned long * sizep )
24422497{
2443- struct object_info oi = {0 };
2498+ enum object_type type ;
2499+ struct object_info oi = {NULL };
24442500
2501+ oi .typep = & type ;
24452502 oi .sizep = sizep ;
2446- return sha1_object_info_extended (sha1 , & oi );
2503+ if (sha1_object_info_extended (sha1 , & oi ) < 0 )
2504+ return -1 ;
2505+ return type ;
24472506}
24482507
24492508static void * read_packed_sha1 (const unsigned char * sha1 ,
0 commit comments