]> git.proxmox.com Git - libgit2.git/blob - src/transport.c
Custom transport: minor cleanups
[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 int transport_find_fn(
50 git_transport_cb *out,
51 const char *url,
52 void **param)
53 {
54 size_t i = 0;
55 transport_definition *d, *definition = NULL;
56
57 /* Find a user transport who wants to deal with this URI */
58 git_vector_foreach(&custom_transports, i, d) {
59 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
60 definition = d;
61 break;
62 }
63 }
64
65 /* Find a system transport for this URI */
66 if (!definition) {
67 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
68 d = &transports[i];
69
70 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
71 definition = d;
72 break;
73 }
74 }
75 }
76
77 #ifdef GIT_WIN32
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 */
81
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;
85 #endif
86
87 /* For other systems, perform the SSH check first, to avoid going to the
88 * filesystem if it is not necessary */
89
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 #ifdef GIT_SSH
94 definition = &ssh_transport_definition;
95 #else
96 definition = &dummy_transport_definition;
97 #endif
98
99 #ifndef GIT_WIN32
100 /* Check to see if the path points to a file on the local file system */
101 if (!definition && git_path_exists(url) && git_path_isdir(url))
102 definition = &local_transport_definition;
103 #endif
104
105 if (!definition)
106 return GIT_ENOTFOUND;
107
108 *out = definition->fn;
109 *param = definition->param;
110
111 return 0;
112 }
113
114 /**************
115 * Public API *
116 **************/
117
118 int git_transport_dummy(git_transport **transport, git_remote *owner, void *param)
119 {
120 GIT_UNUSED(transport);
121 GIT_UNUSED(owner);
122 GIT_UNUSED(param);
123 giterr_set(GITERR_NET, "This transport isn't implemented. Sorry");
124 return -1;
125 }
126
127 int git_transport_new(git_transport **out, git_remote *owner, const char *url)
128 {
129 git_transport_cb fn;
130 git_transport *transport;
131 void *param;
132 int error;
133
134 if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
135 giterr_set(GITERR_NET, "Unsupported URL protocol");
136 return -1;
137 } else if (error < 0)
138 return error;
139
140 if ((error = fn(&transport, owner, param)) < 0)
141 return error;
142
143 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
144
145 *out = transport;
146
147 return 0;
148 }
149
150 int git_transport_register(
151 const char *scheme,
152 git_transport_cb cb,
153 void *param)
154 {
155 git_buf prefix = GIT_BUF_INIT;
156 transport_definition *d, *definition = NULL;
157 size_t i;
158 int error = 0;
159
160 assert(scheme);
161 assert(cb);
162
163 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
164 goto on_error;
165
166 git_vector_foreach(&custom_transports, i, d) {
167 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
168 error = GIT_EEXISTS;
169 goto on_error;
170 }
171 }
172
173 definition = git__calloc(1, sizeof(transport_definition));
174 GITERR_CHECK_ALLOC(definition);
175
176 definition->prefix = git_buf_detach(&prefix);
177 definition->fn = cb;
178 definition->param = param;
179
180 if (git_vector_insert(&custom_transports, definition) < 0)
181 goto on_error;
182
183 return 0;
184
185 on_error:
186 git_buf_free(&prefix);
187 git__free(definition);
188 return error;
189 }
190
191 int git_transport_unregister(const char *scheme)
192 {
193 git_buf prefix = GIT_BUF_INIT;
194 transport_definition *d;
195 size_t i;
196 int error = 0;
197
198 assert(scheme);
199
200 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
201 goto done;
202
203 git_vector_foreach(&custom_transports, i, d) {
204 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
205 if ((error = git_vector_remove(&custom_transports, i)) < 0)
206 goto done;
207
208 git__free(d->prefix);
209 git__free(d);
210
211 if (!custom_transports.length)
212 git_vector_free(&custom_transports);
213
214 error = 0;
215 goto done;
216 }
217 }
218
219 error = GIT_ENOTFOUND;
220
221 done:
222 git_buf_free(&prefix);
223 return error;
224 }
225
226 /* from remote.h */
227 int git_remote_valid_url(const char *url)
228 {
229 git_transport_cb fn;
230 void *param;
231
232 return !transport_find_fn(&fn, url, &param);
233 }
234
235 int git_remote_supported_url(const char* url)
236 {
237 git_transport_cb fn;
238 void *param;
239
240 if (transport_find_fn(&fn, url, &param) < 0)
241 return 0;
242
243 return fn != &git_transport_dummy;
244 }
245
246 int git_transport_init(git_transport *opts, unsigned int version)
247 {
248 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
249 opts, version, git_transport, GIT_TRANSPORT_INIT);
250 return 0;
251 }