| /* |
| * Copyright (C) the libgit2 contributors. All rights reserved. |
| * |
| * This file is part of libgit2, distributed under the GNU GPL v2 with |
| * a Linking Exception. For full terms see the included COPYING file. |
| */ |
| #include "common.h" |
| #include "git2/types.h" |
| #include "git2/remote.h" |
| #include "git2/net.h" |
| #include "git2/transport.h" |
| #include "path.h" |
| |
| typedef struct transport_definition { |
| char *prefix; |
| unsigned priority; |
| git_transport_cb fn; |
| void *param; |
| } transport_definition; |
| |
| static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 }; |
| static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 }; |
| #ifdef GIT_SSH |
| static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 }; |
| #endif |
| |
| static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL }; |
| #ifdef GIT_SSH |
| static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition }; |
| #else |
| static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL }; |
| #endif |
| |
| static transport_definition transports[] = { |
| {"git://", 1, git_transport_smart, &git_subtransport_definition}, |
| {"http://", 1, git_transport_smart, &http_subtransport_definition}, |
| {"https://", 1, git_transport_smart, &http_subtransport_definition}, |
| {"file://", 1, git_transport_local, NULL}, |
| #ifdef GIT_SSH |
| {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, |
| #endif |
| {NULL, 0, 0} |
| }; |
| |
| #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1 |
| |
| static int transport_find_fn(const char *url, git_transport_cb *callback, void **param) |
| { |
| size_t i = 0; |
| unsigned priority = 0; |
| transport_definition *definition = NULL, *definition_iter; |
| |
| // First, check to see if it's an obvious URL, which a URL scheme |
| for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) { |
| definition_iter = &transports[i]; |
| |
| if (strncasecmp(url, definition_iter->prefix, strlen(definition_iter->prefix))) |
| continue; |
| |
| if (definition_iter->priority > priority) |
| definition = definition_iter; |
| } |
| |
| #ifdef GIT_WIN32 |
| /* On Windows, it might not be possible to discern between absolute local |
| * and ssh paths - first check if this is a valid local path that points |
| * to a directory and if so assume local path, else assume SSH */ |
| |
| /* Check to see if the path points to a file on the local file system */ |
| if (!definition && git_path_exists(url) && git_path_isdir(url)) |
| definition = &local_transport_definition; |
| |
| /* It could be a SSH remote path. Check to see if there's a : |
| * SSH is an unsupported transport mechanism in this version of libgit2 */ |
| if (!definition && strrchr(url, ':')) |
| definition = &dummy_transport_definition; |
| #else |
| /* For other systems, perform the SSH check first, to avoid going to the |
| * filesystem if it is not necessary */ |
| |
| /* It could be a SSH remote path. Check to see if there's a : |
| * SSH is an unsupported transport mechanism in this version of libgit2 */ |
| if (!definition && strrchr(url, ':')) |
| #ifdef GIT_SSH |
| definition = &ssh_transport_definition; |
| #else |
| definition = &dummy_transport_definition; |
| #endif |
| |
| /* Check to see if the path points to a file on the local file system */ |
| if (!definition && git_path_exists(url) && git_path_isdir(url)) |
| definition = &local_transport_definition; |
| #endif |
| |
| if (!definition) |
| return -1; |
| |
| *callback = definition->fn; |
| *param = definition->param; |
| |
| return 0; |
| } |
| |
| /************** |
| * Public API * |
| **************/ |
| |
| int git_transport_dummy(git_transport **transport, git_remote *owner, void *param) |
| { |
| GIT_UNUSED(transport); |
| GIT_UNUSED(owner); |
| GIT_UNUSED(param); |
| giterr_set(GITERR_NET, "This transport isn't implemented. Sorry"); |
| return -1; |
| } |
| |
| int git_transport_new(git_transport **out, git_remote *owner, const char *url) |
| { |
| git_transport_cb fn; |
| git_transport *transport; |
| void *param; |
| int error; |
| |
| if (transport_find_fn(url, &fn, ¶m) < 0) { |
| giterr_set(GITERR_NET, "Unsupported URL protocol"); |
| return -1; |
| } |
| |
| error = fn(&transport, owner, param); |
| if (error < 0) |
| return error; |
| |
| *out = transport; |
| |
| return 0; |
| } |
| |
| /* from remote.h */ |
| int git_remote_valid_url(const char *url) |
| { |
| git_transport_cb fn; |
| void *param; |
| |
| return !transport_find_fn(url, &fn, ¶m); |
| } |
| |
| int git_remote_supported_url(const char* url) |
| { |
| git_transport_cb fn; |
| void *param; |
| |
| if (transport_find_fn(url, &fn, ¶m) < 0) |
| return 0; |
| |
| return fn != &git_transport_dummy; |
| } |