2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
8 #include "git2/types.h"
9 #include "git2/remote.h"
11 #include "git2/transport.h"
12 #include "git2/sys/transport.h"
15 typedef struct transport_definition
{
19 } transport_definition
;
21 static git_smart_subtransport_definition http_subtransport_definition
= { git_smart_subtransport_http
, 1 };
22 static git_smart_subtransport_definition git_subtransport_definition
= { git_smart_subtransport_git
, 0 };
24 static git_smart_subtransport_definition ssh_subtransport_definition
= { git_smart_subtransport_ssh
, 0 };
27 static transport_definition local_transport_definition
= { "file://", git_transport_local
, NULL
};
29 static transport_definition transports
[] = {
30 { "git://", git_transport_smart
, &git_subtransport_definition
},
31 { "http://", git_transport_smart
, &http_subtransport_definition
},
32 #if defined(GIT_SSL) || defined(GIT_WINHTTP)
33 { "https://", git_transport_smart
, &http_subtransport_definition
},
35 { "file://", git_transport_local
, NULL
},
37 { "ssh://", git_transport_smart
, &ssh_subtransport_definition
},
42 static git_vector custom_transports
= GIT_VECTOR_INIT
;
44 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
46 static transport_definition
* transport_find_by_url(const char *url
)
49 transport_definition
*d
;
51 /* Find a user transport who wants to deal with this URI */
52 git_vector_foreach(&custom_transports
, i
, d
) {
53 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
58 /* Find a system transport for this URI */
59 for (i
= 0; i
< GIT_TRANSPORT_COUNT
; ++i
) {
62 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
70 static int transport_find_fn(
71 git_transport_cb
*out
,
75 transport_definition
*definition
= transport_find_by_url(url
);
78 /* On Windows, it might not be possible to discern between absolute local
79 * and ssh paths - first check if this is a valid local path that points
80 * to a directory and if so assume local path, else assume SSH */
82 /* Check to see if the path points to a file on the local file system */
83 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
84 definition
= &local_transport_definition
;
87 /* For other systems, perform the SSH check first, to avoid going to the
88 * filesystem if it is not necessary */
90 /* It could be a SSH remote path. Check to see if there's a :
91 * SSH is an unsupported transport mechanism in this version of libgit2 */
92 if (!definition
&& strrchr(url
, ':')) {
93 // re-search transports again with ssh:// as url so that we can find a third party ssh transport
94 definition
= transport_find_by_url("ssh://");
98 /* Check to see if the path points to a file on the local file system */
99 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
100 definition
= &local_transport_definition
;
104 return GIT_ENOTFOUND
;
106 *out
= definition
->fn
;
107 *param
= definition
->param
;
116 int git_transport_new(git_transport
**out
, git_remote
*owner
, const char *url
)
119 git_transport
*transport
;
123 if ((error
= transport_find_fn(&fn
, url
, ¶m
)) == GIT_ENOTFOUND
) {
124 giterr_set(GITERR_NET
, "Unsupported URL protocol");
126 } else if (error
< 0)
129 if ((error
= fn(&transport
, owner
, param
)) < 0)
132 GITERR_CHECK_VERSION(transport
, GIT_TRANSPORT_VERSION
, "git_transport");
139 int git_transport_register(
144 git_buf prefix
= GIT_BUF_INIT
;
145 transport_definition
*d
, *definition
= NULL
;
152 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
155 git_vector_foreach(&custom_transports
, i
, d
) {
156 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
162 definition
= git__calloc(1, sizeof(transport_definition
));
163 GITERR_CHECK_ALLOC(definition
);
165 definition
->prefix
= git_buf_detach(&prefix
);
167 definition
->param
= param
;
169 if (git_vector_insert(&custom_transports
, definition
) < 0)
175 git_buf_free(&prefix
);
176 git__free(definition
);
180 int git_transport_unregister(const char *scheme
)
182 git_buf prefix
= GIT_BUF_INIT
;
183 transport_definition
*d
;
189 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
192 git_vector_foreach(&custom_transports
, i
, d
) {
193 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
194 if ((error
= git_vector_remove(&custom_transports
, i
)) < 0)
197 git__free(d
->prefix
);
200 if (!custom_transports
.length
)
201 git_vector_free(&custom_transports
);
208 error
= GIT_ENOTFOUND
;
211 git_buf_free(&prefix
);
215 int git_remote_supported_url(const char* url
)
220 /* The only error we expect is ENOTFOUND */
221 return !transport_find_fn(&fn
, url
, ¶m
);
224 int git_transport_init(git_transport
*opts
, unsigned int version
)
226 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
227 opts
, version
, git_transport
, GIT_TRANSPORT_INIT
);