@@ -305,42 +305,127 @@ static void read_config(void)
305305 git_config (handle_config );
306306}
307307
308- struct refspec * parse_ref_spec (int nr_refspec , const char * * refspec )
308+ static struct refspec * parse_refspec_internal (int nr_refspec , const char * * refspec , int fetch )
309309{
310310 int i ;
311+ int st ;
311312 struct refspec * rs = xcalloc (sizeof (* rs ), nr_refspec );
313+
312314 for (i = 0 ; i < nr_refspec ; i ++ ) {
313- const char * sp , * ep , * gp ;
314- sp = refspec [i ];
315- if (* sp == '+' ) {
315+ size_t llen , rlen ;
316+ int is_glob ;
317+ const char * lhs , * rhs ;
318+
319+ llen = rlen = is_glob = 0 ;
320+
321+ lhs = refspec [i ];
322+ if (* lhs == '+' ) {
316323 rs [i ].force = 1 ;
317- sp ++ ;
324+ lhs ++ ;
325+ }
326+
327+ rhs = strrchr (lhs , ':' );
328+ if (rhs ) {
329+ rhs ++ ;
330+ rlen = strlen (rhs );
331+ is_glob = (2 <= rlen && !strcmp (rhs + rlen - 2 , "/*" ));
332+ if (is_glob )
333+ rlen -= 2 ;
334+ rs [i ].dst = xstrndup (rhs , rlen );
318335 }
319- gp = strchr (sp , '*' );
320- ep = strchr (sp , ':' );
321- if (gp && ep && gp > ep )
322- gp = NULL ;
323- if (ep ) {
324- if (ep [1 ]) {
325- const char * glob = strchr (ep + 1 , '*' );
326- if (!glob )
327- gp = NULL ;
328- if (gp )
329- rs [i ].dst = xstrndup (ep + 1 ,
330- glob - ep - 1 );
331- else
332- rs [i ].dst = xstrdup (ep + 1 );
336+
337+ llen = (rhs ? (rhs - lhs - 1 ) : strlen (lhs ));
338+ if (2 <= llen && !memcmp (lhs + llen - 2 , "/*" , 2 )) {
339+ if ((rhs && !is_glob ) || (!rhs && fetch ))
340+ goto invalid ;
341+ is_glob = 1 ;
342+ llen -= 2 ;
343+ } else if (rhs && is_glob ) {
344+ goto invalid ;
345+ }
346+
347+ rs [i ].pattern = is_glob ;
348+ rs [i ].src = xstrndup (lhs , llen );
349+
350+ if (fetch ) {
351+ /*
352+ * LHS
353+ * - empty is allowed; it means HEAD.
354+ * - otherwise it must be a valid looking ref.
355+ */
356+ if (!* rs [i ].src )
357+ ; /* empty is ok */
358+ else {
359+ st = check_ref_format (rs [i ].src );
360+ if (st && st != CHECK_REF_FORMAT_ONELEVEL )
361+ goto invalid ;
362+ }
363+ /*
364+ * RHS
365+ * - missing is ok, and is same as empty.
366+ * - empty is ok; it means not to store.
367+ * - otherwise it must be a valid looking ref.
368+ */
369+ if (!rs [i ].dst ) {
370+ ; /* ok */
371+ } else if (!* rs [i ].dst ) {
372+ ; /* ok */
373+ } else {
374+ st = check_ref_format (rs [i ].dst );
375+ if (st && st != CHECK_REF_FORMAT_ONELEVEL )
376+ goto invalid ;
333377 }
334378 } else {
335- ep = sp + strlen (sp );
336- }
337- if (gp ) {
338- rs [i ].pattern = 1 ;
339- ep = gp ;
379+ /*
380+ * LHS
381+ * - empty is allowed; it means delete.
382+ * - when wildcarded, it must be a valid looking ref.
383+ * - otherwise, it must be an extended SHA-1, but
384+ * there is no existing way to validate this.
385+ */
386+ if (!* rs [i ].src )
387+ ; /* empty is ok */
388+ else if (is_glob ) {
389+ st = check_ref_format (rs [i ].src );
390+ if (st && st != CHECK_REF_FORMAT_ONELEVEL )
391+ goto invalid ;
392+ }
393+ else
394+ ; /* anything goes, for now */
395+ /*
396+ * RHS
397+ * - missing is allowed, but LHS then must be a
398+ * valid looking ref.
399+ * - empty is not allowed.
400+ * - otherwise it must be a valid looking ref.
401+ */
402+ if (!rs [i ].dst ) {
403+ st = check_ref_format (rs [i ].src );
404+ if (st && st != CHECK_REF_FORMAT_ONELEVEL )
405+ goto invalid ;
406+ } else if (!* rs [i ].dst ) {
407+ goto invalid ;
408+ } else {
409+ st = check_ref_format (rs [i ].dst );
410+ if (st && st != CHECK_REF_FORMAT_ONELEVEL )
411+ goto invalid ;
412+ }
340413 }
341- rs [i ].src = xstrndup (sp , ep - sp );
342414 }
343415 return rs ;
416+
417+ invalid :
418+ die ("Invalid refspec '%s'" , refspec [i ]);
419+ }
420+
421+ struct refspec * parse_fetch_refspec (int nr_refspec , const char * * refspec )
422+ {
423+ return parse_refspec_internal (nr_refspec , refspec , 1 );
424+ }
425+
426+ struct refspec * parse_push_refspec (int nr_refspec , const char * * refspec )
427+ {
428+ return parse_refspec_internal (nr_refspec , refspec , 0 );
344429}
345430
346431static int valid_remote_nick (const char * name )
@@ -371,8 +456,8 @@ struct remote *remote_get(const char *name)
371456 add_url (ret , name );
372457 if (!ret -> url )
373458 return NULL ;
374- ret -> fetch = parse_ref_spec (ret -> fetch_refspec_nr , ret -> fetch_refspec );
375- ret -> push = parse_ref_spec (ret -> push_refspec_nr , ret -> push_refspec );
459+ ret -> fetch = parse_fetch_refspec (ret -> fetch_refspec_nr , ret -> fetch_refspec );
460+ ret -> push = parse_push_refspec (ret -> push_refspec_nr , ret -> push_refspec );
376461 return ret ;
377462}
378463
@@ -385,11 +470,11 @@ int for_each_remote(each_remote_fn fn, void *priv)
385470 if (!r )
386471 continue ;
387472 if (!r -> fetch )
388- r -> fetch = parse_ref_spec (r -> fetch_refspec_nr ,
389- r -> fetch_refspec );
473+ r -> fetch = parse_fetch_refspec (r -> fetch_refspec_nr ,
474+ r -> fetch_refspec );
390475 if (!r -> push )
391- r -> push = parse_ref_spec (r -> push_refspec_nr ,
392- r -> push_refspec );
476+ r -> push = parse_push_refspec (r -> push_refspec_nr ,
477+ r -> push_refspec );
393478 result = fn (r , priv );
394479 }
395480 return result ;
@@ -455,7 +540,8 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
455540 if (!fetch -> dst )
456541 continue ;
457542 if (fetch -> pattern ) {
458- if (!prefixcmp (needle , key )) {
543+ if (!prefixcmp (needle , key ) &&
544+ needle [strlen (key )] == '/' ) {
459545 * result = xmalloc (strlen (value ) +
460546 strlen (needle ) -
461547 strlen (key ) + 1 );
@@ -695,7 +781,9 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
695781{
696782 int i ;
697783 for (i = 0 ; i < rs_nr ; i ++ ) {
698- if (rs [i ].pattern && !prefixcmp (src -> name , rs [i ].src ))
784+ if (rs [i ].pattern &&
785+ !prefixcmp (src -> name , rs [i ].src ) &&
786+ src -> name [strlen (rs [i ].src )] == '/' )
699787 return rs + i ;
700788 }
701789 return NULL ;
@@ -710,7 +798,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
710798 int nr_refspec , const char * * refspec , int flags )
711799{
712800 struct refspec * rs =
713- parse_ref_spec (nr_refspec , (const char * * ) refspec );
801+ parse_push_refspec (nr_refspec , (const char * * ) refspec );
714802 int send_all = flags & MATCH_REFS_ALL ;
715803 int send_mirror = flags & MATCH_REFS_MIRROR ;
716804
@@ -894,7 +982,7 @@ int get_fetch_map(const struct ref *remote_refs,
894982 struct ref * * * tail ,
895983 int missing_ok )
896984{
897- struct ref * ref_map , * rm ;
985+ struct ref * ref_map , * * rmp ;
898986
899987 if (refspec -> pattern ) {
900988 ref_map = get_expanded_map (remote_refs , refspec );
@@ -911,10 +999,20 @@ int get_fetch_map(const struct ref *remote_refs,
911999 }
9121000 }
9131001
914- for (rm = ref_map ; rm ; rm = rm -> next ) {
915- if (rm -> peer_ref && check_ref_format (rm -> peer_ref -> name + 5 ))
916- die ("* refusing to create funny ref '%s' locally" ,
917- rm -> peer_ref -> name );
1002+ for (rmp = & ref_map ; * rmp ; ) {
1003+ if ((* rmp )-> peer_ref ) {
1004+ int st = check_ref_format ((* rmp )-> peer_ref -> name + 5 );
1005+ if (st && st != CHECK_REF_FORMAT_ONELEVEL ) {
1006+ struct ref * ignore = * rmp ;
1007+ error ("* Ignoring funny ref '%s' locally" ,
1008+ (* rmp )-> peer_ref -> name );
1009+ * rmp = (* rmp )-> next ;
1010+ free (ignore -> peer_ref );
1011+ free (ignore );
1012+ continue ;
1013+ }
1014+ }
1015+ rmp = & ((* rmp )-> next );
9181016 }
9191017
9201018 if (ref_map )
0 commit comments