]>
Commit | Line | Data |
---|---|---|
bb742ede | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
bb742ede VM |
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 | */ | |
8f866dae CMN |
7 | #include "common.h" |
8 | #include "git2/types.h" | |
d88d4311 | 9 | #include "git2/remote.h" |
8f866dae | 10 | #include "git2/net.h" |
41fb1ca0 | 11 | #include "git2/transport.h" |
c180c065 | 12 | #include "git2/sys/transport.h" |
253d6df5 | 13 | #include "path.h" |
8f866dae | 14 | |
41fb1ca0 | 15 | typedef struct transport_definition { |
8f866dae CMN |
16 | char *prefix; |
17 | git_transport_cb fn; | |
41fb1ca0 PK |
18 | void *param; |
19 | } transport_definition; | |
20 | ||
142e5379 LY |
21 | static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1, NULL }; |
22 | static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0, NULL }; | |
bd3854a0 | 23 | #ifdef GIT_SSH |
142e5379 | 24 | static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0, NULL }; |
bd3854a0 | 25 | #endif |
41fb1ca0 | 26 | |
c180c065 | 27 | static transport_definition local_transport_definition = { "file://", git_transport_local, NULL }; |
7261d983 | 28 | |
41fb1ca0 | 29 | static transport_definition transports[] = { |
c180c065 ET |
30 | { "git://", git_transport_smart, &git_subtransport_definition }, |
31 | { "http://", git_transport_smart, &http_subtransport_definition }, | |
24e53d2f | 32 | #if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) |
c180c065 | 33 | { "https://", git_transport_smart, &http_subtransport_definition }, |
bd3854a0 | 34 | #endif |
c180c065 | 35 | { "file://", git_transport_local, NULL }, |
bd3854a0 | 36 | #ifdef GIT_SSH |
c180c065 | 37 | { "ssh://", git_transport_smart, &ssh_subtransport_definition }, |
813d73f6 CB |
38 | { "ssh+git://", git_transport_smart, &ssh_subtransport_definition }, |
39 | { "git+ssh://", git_transport_smart, &ssh_subtransport_definition }, | |
bd3854a0 | 40 | #endif |
c180c065 | 41 | { NULL, 0, 0 } |
8f866dae CMN |
42 | }; |
43 | ||
c180c065 | 44 | static git_vector custom_transports = GIT_VECTOR_INIT; |
83786956 | 45 | |
86360ffd | 46 | #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1 |
2869f404 | 47 | |
34e510ce | 48 | static transport_definition * transport_find_by_url(const char *url) |
8f866dae | 49 | { |
2869f404 | 50 | size_t i = 0; |
34e510ce | 51 | transport_definition *d; |
8f866dae | 52 | |
c180c065 ET |
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) { | |
34e510ce | 56 | return d; |
c180c065 | 57 | } |
8f866dae CMN |
58 | } |
59 | ||
c180c065 | 60 | /* Find a system transport for this URI */ |
34e510ce SS |
61 | for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) { |
62 | d = &transports[i]; | |
63 | ||
64 | if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) { | |
65 | return d; | |
c180c065 | 66 | } |
83786956 PK |
67 | } |
68 | ||
34e510ce SS |
69 | return NULL; |
70 | } | |
71 | ||
72 | static int transport_find_fn( | |
73 | git_transport_cb *out, | |
74 | const char *url, | |
75 | void **param) | |
76 | { | |
77 | transport_definition *definition = transport_find_by_url(url); | |
78 | ||
cb2ace69 JM |
79 | #ifdef GIT_WIN32 |
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 */ | |
83 | ||
84 | /* Check to see if the path points to a file on the local file system */ | |
85 | if (!definition && git_path_exists(url) && git_path_isdir(url)) | |
86 | definition = &local_transport_definition; | |
ed5b77b0 | 87 | #endif |
cb2ace69 | 88 | |
cb2ace69 JM |
89 | /* For other systems, perform the SSH check first, to avoid going to the |
90 | * filesystem if it is not necessary */ | |
91 | ||
f0a2def5 JM |
92 | /* It could be a SSH remote path. Check to see if there's a : |
93 | * SSH is an unsupported transport mechanism in this version of libgit2 */ | |
34e510ce SS |
94 | if (!definition && strrchr(url, ':')) { |
95 | // re-search transports again with ssh:// as url so that we can find a third party ssh transport | |
96 | definition = transport_find_by_url("ssh://"); | |
34e510ce | 97 | } |
cb2ace69 | 98 | |
ed5b77b0 | 99 | #ifndef GIT_WIN32 |
cb2ace69 JM |
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 | |
58448910 | 104 | |
41fb1ca0 | 105 | if (!definition) |
c180c065 | 106 | return GIT_ENOTFOUND; |
58448910 | 107 | |
c180c065 | 108 | *out = definition->fn; |
41fb1ca0 | 109 | *param = definition->param; |
a3c062db | 110 | |
41fb1ca0 | 111 | return 0; |
8f866dae CMN |
112 | } |
113 | ||
114 | /************** | |
115 | * Public API * | |
116 | **************/ | |
117 | ||
613d5eb9 | 118 | int git_transport_new(git_transport **out, git_remote *owner, const char *url) |
8f866dae CMN |
119 | { |
120 | git_transport_cb fn; | |
121 | git_transport *transport; | |
41fb1ca0 | 122 | void *param; |
8f866dae CMN |
123 | int error; |
124 | ||
c180c065 | 125 | if ((error = transport_find_fn(&fn, url, ¶m)) == GIT_ENOTFOUND) { |
3fbcac89 VM |
126 | giterr_set(GITERR_NET, "Unsupported URL protocol"); |
127 | return -1; | |
c180c065 ET |
128 | } else if (error < 0) |
129 | return error; | |
8f866dae | 130 | |
1697cd6f | 131 | if ((error = fn(&transport, owner, param)) < 0) |
4376f7f6 | 132 | return error; |
d6258deb | 133 | |
1697cd6f PK |
134 | GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport"); |
135 | ||
8f866dae CMN |
136 | *out = transport; |
137 | ||
e172cf08 | 138 | return 0; |
8f866dae | 139 | } |
d88d4311 | 140 | |
83786956 | 141 | int git_transport_register( |
c180c065 | 142 | const char *scheme, |
83786956 PK |
143 | git_transport_cb cb, |
144 | void *param) | |
145 | { | |
c180c065 ET |
146 | git_buf prefix = GIT_BUF_INIT; |
147 | transport_definition *d, *definition = NULL; | |
148 | size_t i; | |
149 | int error = 0; | |
83786956 | 150 | |
c180c065 ET |
151 | assert(scheme); |
152 | assert(cb); | |
83786956 | 153 | |
c180c065 | 154 | if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0) |
83786956 PK |
155 | goto on_error; |
156 | ||
c180c065 ET |
157 | git_vector_foreach(&custom_transports, i, d) { |
158 | if (strcasecmp(d->prefix, prefix.ptr) == 0) { | |
159 | error = GIT_EEXISTS; | |
160 | goto on_error; | |
161 | } | |
162 | } | |
163 | ||
164 | definition = git__calloc(1, sizeof(transport_definition)); | |
165 | GITERR_CHECK_ALLOC(definition); | |
166 | ||
167 | definition->prefix = git_buf_detach(&prefix); | |
168 | definition->fn = cb; | |
169 | definition->param = param; | |
83786956 | 170 | |
c180c065 | 171 | if (git_vector_insert(&custom_transports, definition) < 0) |
83786956 PK |
172 | goto on_error; |
173 | ||
174 | return 0; | |
175 | ||
176 | on_error: | |
c180c065 ET |
177 | git_buf_free(&prefix); |
178 | git__free(definition); | |
179 | return error; | |
83786956 PK |
180 | } |
181 | ||
c180c065 | 182 | int git_transport_unregister(const char *scheme) |
83786956 | 183 | { |
c180c065 | 184 | git_buf prefix = GIT_BUF_INIT; |
83786956 | 185 | transport_definition *d; |
c180c065 ET |
186 | size_t i; |
187 | int error = 0; | |
188 | ||
189 | assert(scheme); | |
83786956 | 190 | |
c180c065 ET |
191 | if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0) |
192 | goto done; | |
193 | ||
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) | |
197 | goto done; | |
83786956 PK |
198 | |
199 | git__free(d->prefix); | |
200 | git__free(d); | |
201 | ||
c180c065 ET |
202 | if (!custom_transports.length) |
203 | git_vector_free(&custom_transports); | |
83786956 | 204 | |
c180c065 ET |
205 | error = 0; |
206 | goto done; | |
83786956 PK |
207 | } |
208 | } | |
209 | ||
c180c065 ET |
210 | error = GIT_ENOTFOUND; |
211 | ||
212 | done: | |
213 | git_buf_free(&prefix); | |
214 | return error; | |
83786956 PK |
215 | } |
216 | ||
bc91347b | 217 | int git_transport_init(git_transport *opts, unsigned int version) |
b9f81997 | 218 | { |
bc91347b RB |
219 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( |
220 | opts, version, git_transport, GIT_TRANSPORT_INIT); | |
221 | return 0; | |
b9f81997 | 222 | } |