diff options
author | Torsten Bögershausen <tboegi@web.de> | 2013-11-28 20:50:03 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-12-09 14:54:48 -0800 |
commit | c59ab2e52a64abd7fded97e0983a9b7f3d0508a0 (patch) | |
tree | ec8fbc7ea0cc3a49ee0519425c486d03bb1325cc /connect.c | |
parent | 83b058752707a6ba4af51ebc98c47913bc7d2d25 (diff) | |
download | git-c59ab2e52a64abd7fded97e0983a9b7f3d0508a0.tar.gz |
connect.c: refactor url parsing
Make the function is_local() in transport.c public, rename it into
url_is_local_not_ssh() and use it in both transport.c and connect.c
Use a protocol "local" for URLs for the local file system.
One note about using file:// under Windows:
The (absolute) path on Unix like system typically starts with "/".
When the host is empty, it can be omitted, so that a shell scriptlet
url=file://$pwd
will give a URL like "file:///home/user/repo".
Windows does not have the same concept of a root directory located in "/".
When parsing the URL allow "file://C:/user/repo"
(even if RFC1738 indicates that "file:///C:/user/repo" should be used).
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'connect.c')
-rw-r--r-- | connect.c | 57 |
1 files changed, 30 insertions, 27 deletions
@@ -232,14 +232,24 @@ int server_supports(const char *feature) enum protocol { PROTO_LOCAL = 1, + PROTO_FILE, PROTO_SSH, PROTO_GIT }; +int url_is_local_not_ssh(const char *url) +{ + const char *colon = strchr(url, ':'); + const char *slash = strchr(url, '/'); + return !colon || (slash && slash < colon) || + has_dos_drive_prefix(url); +} + static const char *prot_name(enum protocol protocol) { switch (protocol) { case PROTO_LOCAL: + case PROTO_FILE: return "file"; case PROTO_SSH: return "ssh"; @@ -261,7 +271,7 @@ static enum protocol get_protocol(const char *name) if (!strcmp(name, "ssh+git")) return PROTO_SSH; if (!strcmp(name, "file")) - return PROTO_LOCAL; + return PROTO_FILE; die("I don't handle protocol '%s'", name); } @@ -564,9 +574,8 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host, char *url; char *host, *path; char *end; - int separator; + int separator = '/'; enum protocol protocol = PROTO_LOCAL; - int free_path = 0; if (is_url(url_orig)) url = url_decode(url_orig); @@ -578,10 +587,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host, *host = '\0'; protocol = get_protocol(url); host += 3; - separator = '/'; } else { host = url; - separator = ':'; + if (!url_is_local_not_ssh(url)) { + protocol = PROTO_SSH; + separator = ':'; + } } /* @@ -597,17 +608,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host, } else end = host; - path = strchr(end, separator); - if (path && !has_dos_drive_prefix(end)) { - if (separator == ':') { - if (host != url || path < strchrnul(host, '/')) { - protocol = PROTO_SSH; - *path++ = '\0'; - } else /* '/' in the host part, assume local path */ - path = end; - } - } else + if (protocol == PROTO_LOCAL) path = end; + else if (protocol == PROTO_FILE && has_dos_drive_prefix(end)) + path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */ + else + path = strchr(end, separator); if (!path || !*path) die("No path specified. See 'man git-pull' for valid url syntax"); @@ -616,23 +622,20 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host, * null-terminate hostname and point path to ~ for URL's like this: * ssh://host.xz/~user/repo */ - if (protocol != PROTO_LOCAL) { - char *ptr = path; + + end = path; /* Need to \0 terminate host here */ + if (separator == ':') + path++; /* path starts after ':' */ + if (protocol == PROTO_GIT || protocol == PROTO_SSH) { if (path[1] == '~') path++; - else { - path = xstrdup(ptr); - free_path = 1; - } - - *ptr = '\0'; } + path = xstrdup(path); + *end = '\0'; + *ret_host = xstrdup(host); - if (free_path) - *ret_path = path; - else - *ret_path = xstrdup(path); + *ret_path = path; free(url); return protocol; } |