Skip to content

Commit c59ab2e

Browse files
tboegigitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 83b0587 commit c59ab2e

File tree

5 files changed

+48
-37
lines changed

5 files changed

+48
-37
lines changed

connect.c

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,24 @@ int server_supports(const char *feature)
232232

233233
enum 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+
239248
static const char *prot_name(enum protocol protocol)
240249
{
241250
switch (protocol) {
242251
case PROTO_LOCAL:
252+
case PROTO_FILE:
243253
return "file";
244254
case PROTO_SSH:
245255
return "ssh";
@@ -261,7 +271,7 @@ static enum protocol get_protocol(const char *name)
261271
if (!strcmp(name, "ssh+git"))
262272
return PROTO_SSH;
263273
if (!strcmp(name, "file"))
264-
return PROTO_LOCAL;
274+
return PROTO_FILE;
265275
die("I don't handle protocol '%s'", name);
266276
}
267277

@@ -564,9 +574,8 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
564574
char *url;
565575
char *host, *path;
566576
char *end;
567-
int separator;
577+
int separator = '/';
568578
enum protocol protocol = PROTO_LOCAL;
569-
int free_path = 0;
570579

571580
if (is_url(url_orig))
572581
url = url_decode(url_orig);
@@ -578,10 +587,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
578587
*host = '\0';
579588
protocol = get_protocol(url);
580589
host += 3;
581-
separator = '/';
582590
} else {
583591
host = url;
584-
separator = ':';
592+
if (!url_is_local_not_ssh(url)) {
593+
protocol = PROTO_SSH;
594+
separator = ':';
595+
}
585596
}
586597

587598
/*
@@ -597,17 +608,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
597608
} else
598609
end = host;
599610

600-
path = strchr(end, separator);
601-
if (path && !has_dos_drive_prefix(end)) {
602-
if (separator == ':') {
603-
if (host != url || path < strchrnul(host, '/')) {
604-
protocol = PROTO_SSH;
605-
*path++ = '\0';
606-
} else /* '/' in the host part, assume local path */
607-
path = end;
608-
}
609-
} else
611+
if (protocol == PROTO_LOCAL)
610612
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);
611617

612618
if (!path || !*path)
613619
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,
616622
* null-terminate hostname and point path to ~ for URL's like this:
617623
* ssh://host.xz/~user/repo
618624
*/
619-
if (protocol != PROTO_LOCAL) {
620-
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) {
621630
if (path[1] == '~')
622631
path++;
623-
else {
624-
path = xstrdup(ptr);
625-
free_path = 1;
626-
}
627-
628-
*ptr = '\0';
629632
}
630633

634+
path = xstrdup(path);
635+
*end = '\0';
636+
631637
*ret_host = xstrdup(host);
632-
if (free_path)
633-
*ret_path = path;
634-
else
635-
*ret_path = xstrdup(path);
638+
*ret_path = path;
636639
free(url);
637640
return protocol;
638641
}

connect.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ extern int git_connection_is_socket(struct child_process *conn);
99
extern int server_supports(const char *feature);
1010
extern int parse_feature_request(const char *features, const char *feature);
1111
extern const char *server_feature_value(const char *feature, int *len_ret);
12+
extern int url_is_local_not_ssh(const char *url);
1213

1314
#endif

t/t5500-fetch-pack.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,4 +612,11 @@ do
612612
done
613613
done
614614

615+
test_expect_success MINGW 'fetch-pack --diag-url file://c:/repo' '
616+
check_prot_path file://c:/repo file c:/repo
617+
'
618+
test_expect_success MINGW 'fetch-pack --diag-url c:repo' '
619+
check_prot_path c:repo file c:repo
620+
'
621+
615622
test_done

t/t5601-clone.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,14 @@ do
362362
test_clone_url [::1]:$repo ::1 $repo
363363
'
364364
done
365+
#home directory
366+
test_expect_success "clone host:/~repo" '
367+
test_clone_url host:/~repo host "~repo"
368+
'
369+
370+
test_expect_success "clone [::1]:/~repo" '
371+
test_clone_url [::1]:/~repo ::1 "~repo"
372+
'
365373

366374
# Corner cases
367375
for url in foo/bar:baz [foo]bar/baz:qux [foo/bar]:baz

transport.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -885,14 +885,6 @@ void transport_take_over(struct transport *transport,
885885
transport->cannot_reuse = 1;
886886
}
887887

888-
static int is_local(const char *url)
889-
{
890-
const char *colon = strchr(url, ':');
891-
const char *slash = strchr(url, '/');
892-
return !colon || (slash && slash < colon) ||
893-
has_dos_drive_prefix(url);
894-
}
895-
896888
static int is_file(const char *url)
897889
{
898890
struct stat buf;
@@ -941,7 +933,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
941933
ret->fetch = fetch_objs_via_rsync;
942934
ret->push = rsync_transport_push;
943935
ret->smart_options = NULL;
944-
} else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
936+
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
945937
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
946938
ret->data = data;
947939
ret->get_refs_list = get_refs_from_bundle;
@@ -1297,7 +1289,7 @@ char *transport_anonymize_url(const char *url)
12971289
size_t anon_len, prefix_len = 0;
12981290

12991291
anon_part = strchr(url, '@');
1300-
if (is_local(url) || !anon_part)
1292+
if (url_is_local_not_ssh(url) || !anon_part)
13011293
goto literal_copy;
13021294

13031295
anon_len = strlen(++anon_part);

0 commit comments

Comments
 (0)