Make the function is_local() from 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 <tbo...@web.de>
---
 connect.c             | 57 +++++++++++++++++++++++++++------------------------
 connect.h             |  1 +
 t/t5500-fetch-pack.sh |  7 +++++++
 t/t5601-clone.sh      |  8 ++++++++
 transport.c           | 12 ++---------
 5 files changed, 48 insertions(+), 37 deletions(-)

diff --git a/connect.c b/connect.c
index 7874530..04093c4 100644
--- a/connect.c
+++ b/connect.c
@@ -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;
 }
diff --git a/connect.h b/connect.h
index 527d58a..c41a685 100644
--- a/connect.h
+++ b/connect.h
@@ -9,5 +9,6 @@ extern int git_connection_is_socket(struct child_process *conn);
 extern int server_supports(const char *feature);
 extern int parse_feature_request(const char *features, const char *feature);
 extern const char *server_feature_value(const char *feature, int *len_ret);
+extern int url_is_local_not_ssh(const char *url);
 
 #endif
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index f4a2a38..5ad3505 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -612,4 +612,11 @@ do
        done
 done
 
+test_expect_success MINGW 'fetch-pack --diag-url file://c:/repo' '
+       check_prot_path file://c:/repo file c:/repo
+'
+test_expect_success MINGW 'fetch-pack --diag-url c:repo' '
+       check_prot_path c:repo file c:repo
+'
+
 test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 53a1de9..62fbd7e 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -362,6 +362,14 @@ do
                test_clone_url [::1]:$repo ::1 $repo
        '
 done
+#home directory
+test_expect_success "clone host:/~repo" '
+       test_clone_url host:/~repo host "~repo"
+'
+
+test_expect_success "clone [::1]:/~repo" '
+       test_clone_url [::1]:/~repo ::1 "~repo"
+'
 
 # Corner cases
 for url in foo/bar:baz [foo]bar/baz:qux [foo/bar]:baz
diff --git a/transport.c b/transport.c
index 7202b77..5485e2a 100644
--- a/transport.c
+++ b/transport.c
@@ -885,14 +885,6 @@ void transport_take_over(struct transport *transport,
        transport->cannot_reuse = 1;
 }
 
-static int is_local(const char *url)
-{
-       const char *colon = strchr(url, ':');
-       const char *slash = strchr(url, '/');
-       return !colon || (slash && slash < colon) ||
-               has_dos_drive_prefix(url);
-}
-
 static int is_file(const char *url)
 {
        struct stat buf;
@@ -941,7 +933,7 @@ struct transport *transport_get(struct remote *remote, 
const char *url)
                ret->fetch = fetch_objs_via_rsync;
                ret->push = rsync_transport_push;
                ret->smart_options = NULL;
-       } else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
+       } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 
1)) {
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                ret->data = data;
                ret->get_refs_list = get_refs_from_bundle;
@@ -1297,7 +1289,7 @@ char *transport_anonymize_url(const char *url)
        size_t anon_len, prefix_len = 0;
 
        anon_part = strchr(url, '@');
-       if (is_local(url) || !anon_part)
+       if (url_is_local_not_ssh(url) || !anon_part)
                goto literal_copy;
 
        anon_len = strlen(++anon_part);
-- 
1.8.5.rc0.23.gaa27064


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to