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.
10 #include "git2/types.h"
11 #include "git2/remote.h"
13 #include "git2/transport.h"
14 #include "git2/sys/transport.h"
17 typedef struct transport_definition
{
21 } transport_definition
;
23 static git_smart_subtransport_definition http_subtransport_definition
= { git_smart_subtransport_http
, 1, NULL
};
24 static git_smart_subtransport_definition git_subtransport_definition
= { git_smart_subtransport_git
, 0, NULL
};
26 static git_smart_subtransport_definition ssh_subtransport_definition
= { git_smart_subtransport_ssh
, 0, NULL
};
29 static transport_definition local_transport_definition
= { "file://", git_transport_local
, NULL
};
31 static transport_definition transports
[] = {
32 { "git://", git_transport_smart
, &git_subtransport_definition
},
33 { "http://", git_transport_smart
, &http_subtransport_definition
},
34 { "https://", git_transport_smart
, &http_subtransport_definition
},
35 { "file://", git_transport_local
, NULL
},
37 { "ssh://", git_transport_smart
, &ssh_subtransport_definition
},
38 { "ssh+git://", git_transport_smart
, &ssh_subtransport_definition
},
39 { "git+ssh://", git_transport_smart
, &ssh_subtransport_definition
},
44 static git_vector custom_transports
= GIT_VECTOR_INIT
;
46 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
48 static transport_definition
* transport_find_by_url(const char *url
)
51 transport_definition
*d
;
53 /* Find a user transport who wants to deal with this URI */
54 git_vector_foreach(&custom_transports
, i
, d
) {
55 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
60 /* Find a system transport for this URI */
61 for (i
= 0; i
< GIT_TRANSPORT_COUNT
; ++i
) {
64 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
72 static int transport_find_fn(
73 git_transport_cb
*out
,
77 transport_definition
*definition
= transport_find_by_url(url
);
80 /* On Windows, it might not be possible to discern between absolute local
81 * and ssh paths - first check if this is a valid local path that points
82 * to a directory and if so assume local path, else assume SSH */
84 /* Check to see if the path points to a file on the local file system */
85 if (!definition
&& git_fs_path_exists(url
) && git_fs_path_isdir(url
))
86 definition
= &local_transport_definition
;
89 /* For other systems, perform the SSH check first, to avoid going to the
90 * filesystem if it is not necessary */
92 /* It could be a SSH remote path. Check to see if there's a : */
93 if (!definition
&& strrchr(url
, ':')) {
94 /* re-search transports again with ssh:// as url
95 * so that we can find a third party ssh transport */
96 definition
= transport_find_by_url("ssh://");
100 /* Check to see if the path points to a file on the local file system */
101 if (!definition
&& git_fs_path_exists(url
) && git_fs_path_isdir(url
))
102 definition
= &local_transport_definition
;
106 return GIT_ENOTFOUND
;
108 *out
= definition
->fn
;
109 *param
= definition
->param
;
118 int git_transport_new(git_transport
**out
, git_remote
*owner
, const char *url
)
121 git_transport
*transport
;
125 if ((error
= transport_find_fn(&fn
, url
, ¶m
)) == GIT_ENOTFOUND
) {
126 git_error_set(GIT_ERROR_NET
, "unsupported URL protocol");
128 } else if (error
< 0)
131 if ((error
= fn(&transport
, owner
, param
)) < 0)
134 GIT_ERROR_CHECK_VERSION(transport
, GIT_TRANSPORT_VERSION
, "git_transport");
141 int git_transport_register(
146 git_str prefix
= GIT_STR_INIT
;
147 transport_definition
*d
, *definition
= NULL
;
151 GIT_ASSERT_ARG(scheme
);
154 if ((error
= git_str_printf(&prefix
, "%s://", scheme
)) < 0)
157 git_vector_foreach(&custom_transports
, i
, d
) {
158 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
164 definition
= git__calloc(1, sizeof(transport_definition
));
165 GIT_ERROR_CHECK_ALLOC(definition
);
167 definition
->prefix
= git_str_detach(&prefix
);
169 definition
->param
= param
;
171 if (git_vector_insert(&custom_transports
, definition
) < 0)
177 git_str_dispose(&prefix
);
178 git__free(definition
);
182 int git_transport_unregister(const char *scheme
)
184 git_str prefix
= GIT_STR_INIT
;
185 transport_definition
*d
;
189 GIT_ASSERT_ARG(scheme
);
191 if ((error
= git_str_printf(&prefix
, "%s://", scheme
)) < 0)
194 git_vector_foreach(&custom_transports
, i
, d
) {
195 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
196 if ((error
= git_vector_remove(&custom_transports
, i
)) < 0)
199 git__free(d
->prefix
);
202 if (!custom_transports
.length
)
203 git_vector_free(&custom_transports
);
210 error
= GIT_ENOTFOUND
;
213 git_str_dispose(&prefix
);
217 int git_transport_init(git_transport
*opts
, unsigned int version
)
219 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
220 opts
, version
, git_transport
, GIT_TRANSPORT_INIT
);