@@ -232,10 +232,34 @@ int server_supports(const char *feature)
232232
233233enum protocol {
234234 PROTO_LOCAL = 1 ,
235+ PROTO_FILE ,
235236 PROTO_SSH ,
236237 PROTO_GIT
237238};
238239
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+
239263static enum protocol get_protocol (const char * name )
240264{
241265 if (!strcmp (name , "ssh" ))
@@ -247,7 +271,7 @@ static enum protocol get_protocol(const char *name)
247271 if (!strcmp (name , "ssh+git" ))
248272 return PROTO_SSH ;
249273 if (!strcmp (name , "file" ))
250- return PROTO_LOCAL ;
274+ return PROTO_FILE ;
251275 die ("I don't handle protocol '%s'" , name );
252276}
253277
@@ -527,55 +551,31 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
527551 return proxy ;
528552}
529553
530- #define MAX_CMD_LEN 1024
531-
532- static char * get_port (char * host )
554+ static const char * get_port_numeric (const char * p )
533555{
534556 char * end ;
535- char * p = strchr (host , ':' );
536-
537557 if (p ) {
538558 long port = strtol (p + 1 , & end , 10 );
539559 if (end != p + 1 && * end == '\0' && 0 <= port && port < 65536 ) {
540- * p = '\0' ;
541- return p + 1 ;
560+ return p ;
542561 }
543562 }
544563
545564 return NULL ;
546565}
547566
548- static struct child_process no_fork ;
549-
550567/*
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.
560570 */
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 )
563573{
564574 char * url ;
565575 char * host , * path ;
566576 char * end ;
567- int c ;
568- struct child_process * conn = & no_fork ;
577+ int separator = '/' ;
569578 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 );
579579
580580 if (is_url (url_orig ))
581581 url = url_decode (url_orig );
@@ -587,40 +587,33 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
587587 * host = '\0' ;
588588 protocol = get_protocol (url );
589589 host += 3 ;
590- c = '/' ;
591590 } else {
592591 host = url ;
593- c = ':' ;
592+ if (!url_is_local_not_ssh (url )) {
593+ protocol = PROTO_SSH ;
594+ separator = ':' ;
595+ }
594596 }
595597
596598 /*
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()
599601 */
600602 if (host [0 ] == '[' ) {
601603 end = strchr (host + 1 , ']' );
602604 if (end ) {
603- if (protocol != PROTO_GIT ) {
604- * end = 0 ;
605- host ++ ;
606- }
607605 end ++ ;
608606 } else
609607 end = host ;
610608 } else
611609 end = host ;
612610
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 )
623612 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 );
624617
625618 if (!path || !* path )
626619 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,
629622 * null-terminate hostname and point path to ~ for URL's like this:
630623 * ssh://host.xz/~user/repo
631624 */
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 ) {
634630 if (path [1 ] == '~' )
635631 path ++ ;
636- else {
637- path = xstrdup (ptr );
638- free_path = 1 ;
639- }
640-
641- * ptr = '\0' ;
642632 }
643633
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.
646667 */
647- if (protocol == PROTO_SSH && host != url )
648- port = get_port (end );
668+ signal (SIGCHLD , SIG_DFL );
649669
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 ) {
651678 /* These underlying connection commands die() if they
652679 * cannot connect.
653680 */
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 );
657684 else
658- git_tcp_connect (fd , host , flags );
685+ git_tcp_connect (fd , hostandport , flags );
659686 /*
660687 * Separate original protocol components prog and path
661688 * from extended host header with a NUL byte.
@@ -668,55 +695,51 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
668695 prog , path , 0 ,
669696 target_host , 0 );
670697 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 ;
700730 }
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 ;
710733
711- if (start_command (conn ))
712- die ("unable to fork" );
734+ if (start_command (conn ))
735+ die ("unable to fork" );
713736
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 );
720743 return conn ;
721744}
722745
0 commit comments