]> git.proxmox.com Git - libgit2.git/blob - src/transport.c
d390e14225c1b9e75fb730625cf299a7f0e84777
[libgit2.git] / src / transport.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
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.
6 */
7 #include "common.h"
8 #include "git2/types.h"
9 #include "git2/remote.h"
10 #include "git2/net.h"
11 #include "git2/transport.h"
12 #include "git2/sys/transport.h"
13 #include "path.h"
14
15 typedef struct transport_definition {
16 char *prefix;
17 git_transport_cb fn;
18 void *param;
19 } transport_definition;
20
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 };
23 #ifdef GIT_SSH
24 static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 };
25 #endif
26
27 static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
28 #ifdef GIT_SSH
29 static transport_definition ssh_transport_definition = { "ssh://", git_transport_smart, &ssh_subtransport_definition };
30 #else
31 static transport_definition dummy_transport_definition = { NULL, git_transport_dummy, NULL };
32 #endif
33
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 },
39 #ifdef GIT_SSH
40 { "ssh://", git_transport_smart, &ssh_subtransport_definition },
41 #endif
42 { NULL, 0, 0 }
43 };
44
45 static git_vector custom_transports = GIT_VECTOR_INIT;
46
47 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
48
49 static transport_definition * transport_find_by_url(const char *url)
50 {
51 size_t i = 0;
52 transport_definition *d;
53
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) {
57 return d;
58 }
59 }
60
61 /* Find a system transport for this URI */
62 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
63 d = &transports[i];
64
65 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
66 return d;
67 }
68 }
69
70 return NULL;
71 }
72
73 static int transport_find_fn(
74 git_transport_cb *out,
75 const char *url,
76 void **param)
77 {
78 transport_definition *definition = transport_find_by_url(url);
79
80 #ifdef GIT_WIN32
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 */
84
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;
88 #endif
89
90 /* For other systems, perform the SSH check first, to avoid going to the
91 * filesystem if it is not necessary */
92
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://");
98 #ifndef GIT_SSH
99 if (!definition) {
100 definition = &dummy_transport_definition;
101 }
102 #endif
103 }
104
105 #ifndef GIT_WIN32
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;
109 #endif
110
111 if (!definition)
112 return GIT_ENOTFOUND;
113
114 *out = definition->fn;
115 *param = definition->param;
116
117 return 0;
118 }
119
120 /**************
121 * Public API *
122 **************/
123
124 int git_transport_dummy(git_transport **transport, git_remote *owner, void *param)
125 {
126 GIT_UNUSED(transport);
127 GIT_UNUSED(owner);
128 GIT_UNUSED(param);
129 giterr_set(GITERR_NET, "This transport isn't implemented. Sorry");
130 return -1;
131 }
132
133 int git_transport_new(git_transport **out, git_remote *owner, const char *url)
134 {
135 git_transport_cb fn;
136 git_transport *transport;
137 void *param;
138 int error;
139
140 if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
141 giterr_set(GITERR_NET, "Unsupported URL protocol");
142 return -1;
143 } else if (error < 0)
144 return error;
145
146 if ((error = fn(&transport, owner, param)) < 0)
147 return error;
148
149 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
150
151 *out = transport;
152
153 return 0;
154 }
155
156 int git_transport_register(
157 const char *scheme,
158 git_transport_cb cb,
159 void *param)
160 {
161 git_buf prefix = GIT_BUF_INIT;
162 transport_definition *d, *definition = NULL;
163 size_t i;
164 int error = 0;
165
166 assert(scheme);
167 assert(cb);
168
169 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
170 goto on_error;
171
172 git_vector_foreach(&custom_transports, i, d) {
173 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
174 error = GIT_EEXISTS;
175 goto on_error;
176 }
177 }
178
179 definition = git__calloc(1, sizeof(transport_definition));
180 GITERR_CHECK_ALLOC(definition);
181
182 definition->prefix = git_buf_detach(&prefix);
183 definition->fn = cb;
184 definition->param = param;
185
186 if (git_vector_insert(&custom_transports, definition) < 0)
187 goto on_error;
188
189 return 0;
190
191 on_error:
192 git_buf_free(&prefix);
193 git__free(definition);
194 return error;
195 }
196
197 int git_transport_unregister(const char *scheme)
198 {
199 git_buf prefix = GIT_BUF_INIT;
200 transport_definition *d;
201 size_t i;
202 int error = 0;
203
204 assert(scheme);
205
206 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
207 goto done;
208
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)
212 goto done;
213
214 git__free(d->prefix);
215 git__free(d);
216
217 if (!custom_transports.length)
218 git_vector_free(&custom_transports);
219
220 error = 0;
221 goto done;
222 }
223 }
224
225 error = GIT_ENOTFOUND;
226
227 done:
228 git_buf_free(&prefix);
229 return error;
230 }
231
232 /* from remote.h */
233 int git_remote_valid_url(const char *url)
234 {
235 git_transport_cb fn;
236 void *param;
237
238 return !transport_find_fn(&fn, url, &param);
239 }
240
241 int git_remote_supported_url(const char* url)
242 {
243 git_transport_cb fn;
244 void *param;
245
246 if (transport_find_fn(&fn, url, &param) < 0)
247 return 0;
248
249 return fn != &git_transport_dummy;
250 }
251
252 int git_transport_init(git_transport *opts, unsigned int version)
253 {
254 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
255 opts, version, git_transport, GIT_TRANSPORT_INIT);
256 return 0;
257 }