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 ssh_transport_definition
= { "ssh://", git_transport_smart
, &ssh_subtransport_definition
};
31 static transport_definition dummy_transport_definition
= { NULL
, git_transport_dummy
, NULL
};
34 static transport_definition transports
[] = {
35 { "git://", git_transport_smart
, &git_subtransport_definition
},
36 { "http://", git_transport_smart
, &http_subtransport_definition
},
37 { "https://", git_transport_smart
, &http_subtransport_definition
},
38 { "file://", git_transport_local
, NULL
},
40 { "ssh://", git_transport_smart
, &ssh_subtransport_definition
},
45 static git_vector custom_transports
= GIT_VECTOR_INIT
;
47 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
49 static transport_definition
* transport_find_by_url(const char *url
)
52 transport_definition
*d
;
54 /* Find a user transport who wants to deal with this URI */
55 git_vector_foreach(&custom_transports
, i
, d
) {
56 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
61 /* Find a system transport for this URI */
62 for (i
= 0; i
< GIT_TRANSPORT_COUNT
; ++i
) {
65 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
73 static int transport_find_fn(
74 git_transport_cb
*out
,
78 transport_definition
*definition
= transport_find_by_url(url
);
81 /* On Windows, it might not be possible to discern between absolute local
82 * and ssh paths - first check if this is a valid local path that points
83 * to a directory and if so assume local path, else assume SSH */
85 /* Check to see if the path points to a file on the local file system */
86 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
87 definition
= &local_transport_definition
;
90 /* For other systems, perform the SSH check first, to avoid going to the
91 * filesystem if it is not necessary */
93 /* It could be a SSH remote path. Check to see if there's a :
94 * SSH is an unsupported transport mechanism in this version of libgit2 */
95 if (!definition
&& strrchr(url
, ':')) {
96 // re-search transports again with ssh:// as url so that we can find a third party ssh transport
97 definition
= transport_find_by_url("ssh://");
100 definition
= &dummy_transport_definition
;
106 /* Check to see if the path points to a file on the local file system */
107 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
108 definition
= &local_transport_definition
;
112 return GIT_ENOTFOUND
;
114 *out
= definition
->fn
;
115 *param
= definition
->param
;
124 int git_transport_dummy(git_transport
**transport
, git_remote
*owner
, void *param
)
126 GIT_UNUSED(transport
);
129 giterr_set(GITERR_NET
, "This transport isn't implemented. Sorry");
133 int git_transport_new(git_transport
**out
, git_remote
*owner
, const char *url
)
136 git_transport
*transport
;
140 if ((error
= transport_find_fn(&fn
, url
, ¶m
)) == GIT_ENOTFOUND
) {
141 giterr_set(GITERR_NET
, "Unsupported URL protocol");
143 } else if (error
< 0)
146 if ((error
= fn(&transport
, owner
, param
)) < 0)
149 GITERR_CHECK_VERSION(transport
, GIT_TRANSPORT_VERSION
, "git_transport");
156 int git_transport_register(
161 git_buf prefix
= GIT_BUF_INIT
;
162 transport_definition
*d
, *definition
= NULL
;
169 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
172 git_vector_foreach(&custom_transports
, i
, d
) {
173 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
179 definition
= git__calloc(1, sizeof(transport_definition
));
180 GITERR_CHECK_ALLOC(definition
);
182 definition
->prefix
= git_buf_detach(&prefix
);
184 definition
->param
= param
;
186 if (git_vector_insert(&custom_transports
, definition
) < 0)
192 git_buf_free(&prefix
);
193 git__free(definition
);
197 int git_transport_unregister(const char *scheme
)
199 git_buf prefix
= GIT_BUF_INIT
;
200 transport_definition
*d
;
206 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
209 git_vector_foreach(&custom_transports
, i
, d
) {
210 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
211 if ((error
= git_vector_remove(&custom_transports
, i
)) < 0)
214 git__free(d
->prefix
);
217 if (!custom_transports
.length
)
218 git_vector_free(&custom_transports
);
225 error
= GIT_ENOTFOUND
;
228 git_buf_free(&prefix
);
233 int git_remote_valid_url(const char *url
)
238 return !transport_find_fn(&fn
, url
, ¶m
);
241 int git_remote_supported_url(const char* url
)
246 if (transport_find_fn(&fn
, url
, ¶m
) < 0)
249 return fn
!= &git_transport_dummy
;
252 int git_transport_init(git_transport
*opts
, unsigned int version
)
254 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
255 opts
, version
, git_transport
, GIT_TRANSPORT_INIT
);