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