@@ -232,10 +232,34 @@ int server_supports(const char *feature)
232
232
233
233
enum protocol {
234
234
PROTO_LOCAL = 1 ,
235
+ PROTO_FILE ,
235
236
PROTO_SSH ,
236
237
PROTO_GIT
237
238
};
238
239
240
+ int url_is_local_not_ssh (const char * url )
241
+ {
242
+ const char * colon = strchr (url , ':' );
243
+ const char * slash = strchr (url , '/' );
244
+ return !colon || (slash && slash < colon ) ||
245
+ has_dos_drive_prefix (url );
246
+ }
247
+
248
+ static const char * prot_name (enum protocol protocol )
249
+ {
250
+ switch (protocol ) {
251
+ case PROTO_LOCAL :
252
+ case PROTO_FILE :
253
+ return "file" ;
254
+ case PROTO_SSH :
255
+ return "ssh" ;
256
+ case PROTO_GIT :
257
+ return "git" ;
258
+ default :
259
+ return "unkown protocol" ;
260
+ }
261
+ }
262
+
239
263
static enum protocol get_protocol (const char * name )
240
264
{
241
265
if (!strcmp (name , "ssh" ))
@@ -247,7 +271,7 @@ static enum protocol get_protocol(const char *name)
247
271
if (!strcmp (name , "ssh+git" ))
248
272
return PROTO_SSH ;
249
273
if (!strcmp (name , "file" ))
250
- return PROTO_LOCAL ;
274
+ return PROTO_FILE ;
251
275
die ("I don't handle protocol '%s'" , name );
252
276
}
253
277
@@ -527,55 +551,31 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
527
551
return proxy ;
528
552
}
529
553
530
- #define MAX_CMD_LEN 1024
531
-
532
- static char * get_port (char * host )
554
+ static const char * get_port_numeric (const char * p )
533
555
{
534
556
char * end ;
535
- char * p = strchr (host , ':' );
536
-
537
557
if (p ) {
538
558
long port = strtol (p + 1 , & end , 10 );
539
559
if (end != p + 1 && * end == '\0' && 0 <= port && port < 65536 ) {
540
- * p = '\0' ;
541
- return p + 1 ;
560
+ return p ;
542
561
}
543
562
}
544
563
545
564
return NULL ;
546
565
}
547
566
548
- static struct child_process no_fork ;
549
-
550
567
/*
551
- * This returns a dummy child_process if the transport protocol does not
552
- * need fork(2), or a struct child_process object if it does. Once done,
553
- * finish the connection with finish_connect() with the value returned from
554
- * this function (it is safe to call finish_connect() with NULL to support
555
- * the former case).
556
- *
557
- * If it returns, the connect is successful; it just dies on errors (this
558
- * will hopefully be changed in a libification effort, to return NULL when
559
- * the connection failed).
568
+ * Extract protocol and relevant parts from the specified connection URL.
569
+ * The caller must free() the returned strings.
560
570
*/
561
- struct child_process * git_connect ( int fd [ 2 ], const char * url_orig ,
562
- const char * prog , int flags )
571
+ static enum protocol parse_connect_url ( const char * url_orig , char * * ret_host ,
572
+ char * * ret_path )
563
573
{
564
574
char * url ;
565
575
char * host , * path ;
566
576
char * end ;
567
- int c ;
568
- struct child_process * conn = & no_fork ;
577
+ int separator = '/' ;
569
578
enum protocol protocol = PROTO_LOCAL ;
570
- int free_path = 0 ;
571
- char * port = NULL ;
572
- const char * * arg ;
573
- struct strbuf cmd ;
574
-
575
- /* Without this we cannot rely on waitpid() to tell
576
- * what happened to our children.
577
- */
578
- signal (SIGCHLD , SIG_DFL );
579
579
580
580
if (is_url (url_orig ))
581
581
url = url_decode (url_orig );
@@ -587,40 +587,33 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
587
587
* host = '\0' ;
588
588
protocol = get_protocol (url );
589
589
host += 3 ;
590
- c = '/' ;
591
590
} else {
592
591
host = url ;
593
- c = ':' ;
592
+ if (!url_is_local_not_ssh (url )) {
593
+ protocol = PROTO_SSH ;
594
+ separator = ':' ;
595
+ }
594
596
}
595
597
596
598
/*
597
- * Don't do destructive transforms with git:// as that
598
- * protocol code does '[]' unwrapping of its own.
599
+ * Don't do destructive transforms as protocol code does
600
+ * '[]' unwrapping in get_host_and_port()
599
601
*/
600
602
if (host [0 ] == '[' ) {
601
603
end = strchr (host + 1 , ']' );
602
604
if (end ) {
603
- if (protocol != PROTO_GIT ) {
604
- * end = 0 ;
605
- host ++ ;
606
- }
607
605
end ++ ;
608
606
} else
609
607
end = host ;
610
608
} else
611
609
end = host ;
612
610
613
- path = strchr (end , c );
614
- if (path && !has_dos_drive_prefix (end )) {
615
- if (c == ':' ) {
616
- if (host != url || path < strchrnul (host , '/' )) {
617
- protocol = PROTO_SSH ;
618
- * path ++ = '\0' ;
619
- } else /* '/' in the host part, assume local path */
620
- path = end ;
621
- }
622
- } else
611
+ if (protocol == PROTO_LOCAL )
623
612
path = end ;
613
+ else if (protocol == PROTO_FILE && has_dos_drive_prefix (end ))
614
+ path = end ; /* "file://$(pwd)" may be "file://C:/projects/repo" */
615
+ else
616
+ path = strchr (end , separator );
624
617
625
618
if (!path || !* path )
626
619
die ("No path specified. See 'man git-pull' for valid url syntax" );
@@ -629,33 +622,67 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
629
622
* null-terminate hostname and point path to ~ for URL's like this:
630
623
* ssh://host.xz/~user/repo
631
624
*/
632
- if (protocol != PROTO_LOCAL && host != url ) {
633
- char * ptr = path ;
625
+
626
+ end = path ; /* Need to \0 terminate host here */
627
+ if (separator == ':' )
628
+ path ++ ; /* path starts after ':' */
629
+ if (protocol == PROTO_GIT || protocol == PROTO_SSH ) {
634
630
if (path [1 ] == '~' )
635
631
path ++ ;
636
- else {
637
- path = xstrdup (ptr );
638
- free_path = 1 ;
639
- }
640
-
641
- * ptr = '\0' ;
642
632
}
643
633
644
- /*
645
- * Add support for ssh port: ssh://host.xy:<port>/...
634
+ path = xstrdup (path );
635
+ * end = '\0' ;
636
+
637
+ * ret_host = xstrdup (host );
638
+ * ret_path = path ;
639
+ free (url );
640
+ return protocol ;
641
+ }
642
+
643
+ static struct child_process no_fork ;
644
+
645
+ /*
646
+ * This returns a dummy child_process if the transport protocol does not
647
+ * need fork(2), or a struct child_process object if it does. Once done,
648
+ * finish the connection with finish_connect() with the value returned from
649
+ * this function (it is safe to call finish_connect() with NULL to support
650
+ * the former case).
651
+ *
652
+ * If it returns, the connect is successful; it just dies on errors (this
653
+ * will hopefully be changed in a libification effort, to return NULL when
654
+ * the connection failed).
655
+ */
656
+ struct child_process * git_connect (int fd [2 ], const char * url ,
657
+ const char * prog , int flags )
658
+ {
659
+ char * hostandport , * path ;
660
+ struct child_process * conn = & no_fork ;
661
+ enum protocol protocol ;
662
+ const char * * arg ;
663
+ struct strbuf cmd = STRBUF_INIT ;
664
+
665
+ /* Without this we cannot rely on waitpid() to tell
666
+ * what happened to our children.
646
667
*/
647
- if (protocol == PROTO_SSH && host != url )
648
- port = get_port (end );
668
+ signal (SIGCHLD , SIG_DFL );
649
669
650
- if (protocol == PROTO_GIT ) {
670
+ protocol = parse_connect_url (url , & hostandport , & path );
671
+ if (flags & CONNECT_DIAG_URL ) {
672
+ printf ("Diag: url=%s\n" , url ? url : "NULL" );
673
+ printf ("Diag: protocol=%s\n" , prot_name (protocol ));
674
+ printf ("Diag: hostandport=%s\n" , hostandport ? hostandport : "NULL" );
675
+ printf ("Diag: path=%s\n" , path ? path : "NULL" );
676
+ conn = NULL ;
677
+ } else if (protocol == PROTO_GIT ) {
651
678
/* These underlying connection commands die() if they
652
679
* cannot connect.
653
680
*/
654
- char * target_host = xstrdup (host );
655
- if (git_use_proxy (host ))
656
- conn = git_proxy_connect (fd , host );
681
+ char * target_host = xstrdup (hostandport );
682
+ if (git_use_proxy (hostandport ))
683
+ conn = git_proxy_connect (fd , hostandport );
657
684
else
658
- git_tcp_connect (fd , host , flags );
685
+ git_tcp_connect (fd , hostandport , flags );
659
686
/*
660
687
* Separate original protocol components prog and path
661
688
* from extended host header with a NUL byte.
@@ -668,55 +695,51 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
668
695
prog , path , 0 ,
669
696
target_host , 0 );
670
697
free (target_host );
671
- free (url );
672
- if (free_path )
673
- free (path );
674
- return conn ;
675
- }
676
-
677
- conn = xcalloc (1 , sizeof (* conn ));
678
-
679
- strbuf_init (& cmd , MAX_CMD_LEN );
680
- strbuf_addstr (& cmd , prog );
681
- strbuf_addch (& cmd , ' ' );
682
- sq_quote_buf (& cmd , path );
683
- if (cmd .len >= MAX_CMD_LEN )
684
- die ("command line too long" );
685
-
686
- conn -> in = conn -> out = -1 ;
687
- conn -> argv = arg = xcalloc (7 , sizeof (* arg ));
688
- if (protocol == PROTO_SSH ) {
689
- const char * ssh = getenv ("GIT_SSH" );
690
- int putty = ssh && strcasestr (ssh , "plink" );
691
- if (!ssh ) ssh = "ssh" ;
692
-
693
- * arg ++ = ssh ;
694
- if (putty && !strcasestr (ssh , "tortoiseplink" ))
695
- * arg ++ = "-batch" ;
696
- if (port ) {
697
- /* P is for PuTTY, p is for OpenSSH */
698
- * arg ++ = putty ? "-P" : "-p" ;
699
- * arg ++ = port ;
698
+ } else {
699
+ conn = xcalloc (1 , sizeof (* conn ));
700
+
701
+ strbuf_addstr (& cmd , prog );
702
+ strbuf_addch (& cmd , ' ' );
703
+ sq_quote_buf (& cmd , path );
704
+
705
+ conn -> in = conn -> out = -1 ;
706
+ conn -> argv = arg = xcalloc (7 , sizeof (* arg ));
707
+ if (protocol == PROTO_SSH ) {
708
+ const char * ssh = getenv ("GIT_SSH" );
709
+ int putty = ssh && strcasestr (ssh , "plink" );
710
+ char * ssh_host = hostandport ;
711
+ const char * port = NULL ;
712
+ get_host_and_port (& ssh_host , & port );
713
+ port = get_port_numeric (port );
714
+
715
+ if (!ssh ) ssh = "ssh" ;
716
+
717
+ * arg ++ = ssh ;
718
+ if (putty && !strcasestr (ssh , "tortoiseplink" ))
719
+ * arg ++ = "-batch" ;
720
+ if (port ) {
721
+ /* P is for PuTTY, p is for OpenSSH */
722
+ * arg ++ = putty ? "-P" : "-p" ;
723
+ * arg ++ = port ;
724
+ }
725
+ * arg ++ = ssh_host ;
726
+ } else {
727
+ /* remove repo-local variables from the environment */
728
+ conn -> env = local_repo_env ;
729
+ conn -> use_shell = 1 ;
700
730
}
701
- * arg ++ = host ;
702
- }
703
- else {
704
- /* remove repo-local variables from the environment */
705
- conn -> env = local_repo_env ;
706
- conn -> use_shell = 1 ;
707
- }
708
- * arg ++ = cmd .buf ;
709
- * arg = NULL ;
731
+ * arg ++ = cmd .buf ;
732
+ * arg = NULL ;
710
733
711
- if (start_command (conn ))
712
- die ("unable to fork" );
734
+ if (start_command (conn ))
735
+ die ("unable to fork" );
713
736
714
- fd [0 ] = conn -> out ; /* read from child's stdout */
715
- fd [1 ] = conn -> in ; /* write to child's stdin */
716
- strbuf_release (& cmd );
717
- free ( url );
718
- if ( free_path )
719
- free (path );
737
+ fd [0 ] = conn -> out ; /* read from child's stdout */
738
+ fd [1 ] = conn -> in ; /* write to child's stdin */
739
+ strbuf_release (& cmd );
740
+ }
741
+ free ( hostandport );
742
+ free (path );
720
743
return conn ;
721
744
}
722
745
0 commit comments