@@ -212,26 +212,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
212212 return 0 ;
213213}
214214
215+ static int set_data (
216+ git_pkt_parse_data * data ,
217+ const char * line ,
218+ size_t len )
219+ {
220+ const char * caps , * format_str = NULL , * eos ;
221+ size_t format_len ;
222+ git_oid_t remote_oid_type ;
223+
224+ GIT_ASSERT_ARG (data );
225+
226+ if ((caps = memchr (line , '\0' , len )) != NULL ) {
227+ caps ++ ;
228+
229+ if (strncmp (caps , "object-format=" , CONST_STRLEN ("object-format=" )) == 0 )
230+ format_str = caps + CONST_STRLEN ("object-format=" );
231+ else if ((format_str = strstr (caps , " object-format=" )) != NULL )
232+ format_str += CONST_STRLEN (" object-format=" );
233+ }
234+
235+ if (format_str ) {
236+ if ((eos = strchr (format_str , ' ' )) == NULL )
237+ eos = strchr (format_str , '\0' );
238+
239+ GIT_ASSERT (eos );
240+
241+ format_len = eos - format_str ;
242+
243+ if ((remote_oid_type = git_oid_type_fromstrn (format_str , format_len )) == 0 ) {
244+ git_error_set (GIT_ERROR_INVALID , "unknown remote object format '%.*s'" , (int )format_len , format_str );
245+ return -1 ;
246+ }
247+ } else {
248+ remote_oid_type = GIT_OID_SHA1 ;
249+ }
250+
251+ if (!data -> oid_type ) {
252+ data -> oid_type = remote_oid_type ;
253+ } else if (data -> oid_type != remote_oid_type ) {
254+ git_error_set (GIT_ERROR_INVALID ,
255+ "the local object format '%s' does not match the remote object format '%s'" ,
256+ git_oid_type_name (data -> oid_type ),
257+ git_oid_type_name (remote_oid_type ));
258+ return -1 ;
259+ }
260+
261+ return 0 ;
262+ }
263+
215264/*
216265 * Parse an other-ref line.
217266 */
218- static int ref_pkt (git_pkt * * out , const char * line , size_t len )
267+ static int ref_pkt (
268+ git_pkt * * out ,
269+ const char * line ,
270+ size_t len ,
271+ git_pkt_parse_data * data )
219272{
220273 git_pkt_ref * pkt ;
221- size_t alloclen ;
274+ size_t alloclen , oid_hexsize ;
222275
223276 pkt = git__calloc (1 , sizeof (git_pkt_ref ));
224277 GIT_ERROR_CHECK_ALLOC (pkt );
225278 pkt -> type = GIT_PKT_REF ;
226279
227- if (len < GIT_OID_SHA1_HEXSIZE ||
228- git_oid__fromstr (& pkt -> head .oid , line , GIT_OID_SHA1 ) < 0 )
280+ /* Determine OID type from capabilities */
281+ if (!data -> seen_capabilities && set_data (data , line , len ) < 0 )
282+ return -1 ;
283+
284+ GIT_ASSERT (data -> oid_type );
285+ oid_hexsize = git_oid_hexsize (data -> oid_type );
286+
287+ if (len < oid_hexsize ||
288+ git_oid__fromstr (& pkt -> head .oid , line , data -> oid_type ) < 0 )
229289 goto out_err ;
230- line += GIT_OID_SHA1_HEXSIZE ;
231- len -= GIT_OID_SHA1_HEXSIZE ;
290+ line += oid_hexsize ;
291+ len -= oid_hexsize ;
232292
233293 if (git__prefixncmp (line , len , " " ))
234294 goto out_err ;
295+
235296 line ++ ;
236297 len -- ;
237298
@@ -248,8 +309,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
248309 memcpy (pkt -> head .name , line , len );
249310 pkt -> head .name [len ] = '\0' ;
250311
251- if (strlen (pkt -> head .name ) < len )
252- pkt -> capabilities = strchr (pkt -> head .name , '\0' ) + 1 ;
312+ if (strlen (pkt -> head .name ) < len ) {
313+ if (!data -> seen_capabilities )
314+ pkt -> capabilities = strchr (pkt -> head .name , '\0' ) + 1 ;
315+ else
316+ goto out_err ;
317+ }
318+
319+ data -> seen_capabilities = 1 ;
253320
254321 * out = (git_pkt * )pkt ;
255322 return 0 ;
@@ -418,7 +485,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen)
418485 */
419486
420487int git_pkt_parse_line (
421- git_pkt * * pkt , const char * * endptr , const char * line , size_t linelen )
488+ git_pkt * * pkt ,
489+ const char * * endptr ,
490+ const char * line ,
491+ size_t linelen ,
492+ git_pkt_parse_data * data )
422493{
423494 int error ;
424495 size_t len ;
@@ -493,7 +564,7 @@ int git_pkt_parse_line(
493564 else if (!git__prefixncmp (line , len , "unpack" ))
494565 error = unpack_pkt (pkt , line , len );
495566 else
496- error = ref_pkt (pkt , line , len );
567+ error = ref_pkt (pkt , line , len , data );
497568
498569 * endptr = line + len ;
499570
@@ -533,8 +604,11 @@ int git_pkt_buffer_flush(git_str *buf)
533604static int buffer_want_with_caps (const git_remote_head * head , transport_smart_caps * caps , git_str * buf )
534605{
535606 git_str str = GIT_STR_INIT ;
536- char oid [GIT_OID_SHA1_HEXSIZE + 1 ] = {0 };
537- size_t len ;
607+ char oid [GIT_OID_MAX_HEXSIZE + 1 ] = {0 };
608+ size_t oid_hexsize , len ;
609+
610+ oid_hexsize = git_oid_hexsize (head -> oid .type );
611+ git_oid_fmt (oid , & head -> oid );
538612
539613 /* Prefer multi_ack_detailed */
540614 if (caps -> multi_ack_detailed )
@@ -560,7 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
560634 if (git_str_oom (& str ))
561635 return -1 ;
562636
563- len = strlen ("XXXXwant " ) + GIT_OID_SHA1_HEXSIZE + 1 /* NUL */ +
637+ len = strlen ("XXXXwant " ) + oid_hexsize + 1 /* NUL */ +
564638 git_str_len (& str ) + 1 /* LF */ ;
565639
566640 if (len > 0xffff ) {
@@ -570,9 +644,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
570644 }
571645
572646 git_str_grow_by (buf , len );
573- git_oid_fmt (oid , & head -> oid );
574647 git_str_printf (buf ,
575- "%04xwant %s %s\n" , (unsigned int )len , oid , git_str_cstr (& str ));
648+ "%04xwant %.*s %s\n" , (unsigned int )len ,
649+ (int )oid_hexsize , oid , git_str_cstr (& str ));
576650 git_str_dispose (& str );
577651
578652 GIT_ERROR_CHECK_ALLOC_STR (buf );
@@ -608,16 +682,19 @@ int git_pkt_buffer_wants(
608682 }
609683
610684 for (; i < count ; ++ i ) {
611- char oid [GIT_OID_SHA1_HEXSIZE ];
685+ char oid [GIT_OID_MAX_HEXSIZE ];
612686
613687 head = refs [i ];
688+
614689 if (head -> local )
615690 continue ;
616691
617692 git_oid_fmt (oid , & head -> oid );
693+
618694 git_str_put (buf , pkt_want_prefix , strlen (pkt_want_prefix ));
619- git_str_put (buf , oid , GIT_OID_SHA1_HEXSIZE );
695+ git_str_put (buf , oid , git_oid_hexsize ( head -> oid . type ) );
620696 git_str_putc (buf , '\n' );
697+
621698 if (git_str_oom (buf ))
622699 return -1 ;
623700 }
0 commit comments