Line Flow Count Block(s) Source
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 -
8 - #include "common.h"
9 -
10 - #include "git2/types.h"
11 - #include "git2/remote.h"
12 - #include "git2/net.h"
13 - #include "git2/transport.h"
14 - #include "git2/sys/transport.h"
15 - #include "path.h"
16 -
17 - typedef struct transport_definition {
18 - char *prefix;
19 - git_transport_cb fn;
20 - void *param;
21 - } transport_definition;
22 -
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 };
25 - #ifdef GIT_SSH
26 - static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0, NULL };
27 - #endif
28 -
29 - static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
30 -
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 },
36 - #ifdef GIT_SSH
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 },
40 - #endif
41 - { NULL, 0, 0 }
42 - };
43 -
44 - static git_vector custom_transports = GIT_VECTOR_INIT;
45 -
46 - #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
47 -
48 193 2 static transport_definition * transport_find_by_url(const char *url)
49 - {
50 193 2 size_t i = 0;
51 - transport_definition *d;
52 -
53 - /* Find a user transport who wants to deal with this URI */
54 194 2,5-7 git_vector_foreach(&custom_transports, i, d) {
55 3 3 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
56 2 4 return d;
57 - }
58 - }
59 -
60 - /* Find a system transport for this URI */
61 689 8,11,12 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
62 620 9 d = &transports[i];
63 -
64 620 9 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
65 122 10 return d;
66 - }
67 - }
68 -
69 69 13 return NULL;
70 - }
71 -
72 179 2 static int transport_find_fn(
73 - git_transport_cb *out,
74 - const char *url,
75 - void **param)
76 - {
77 179 2 transport_definition *definition = transport_find_by_url(url);
78 -
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;
87 - #endif
88 -
89 - /* For other systems, perform the SSH check first, to avoid going to the
90 - * filesystem if it is not necessary */
91 -
92 - /* It could be a SSH remote path. Check to see if there's a : */
93 179 3,4 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 14 5 definition = transport_find_by_url("ssh://");
97 - }
98 -
99 - #ifndef GIT_WIN32
100 - /* Check to see if the path points to a file on the local file system */
101 179 6-10 if (!definition && git_path_exists(url) && git_path_isdir(url))
102 38 11 definition = &local_transport_definition;
103 - #endif
104 -
105 179 12 if (!definition)
106 17 13 return GIT_ENOTFOUND;
107 -
108 162 14 *out = definition->fn;
109 162 14 *param = definition->param;
110 -
111 162 14 return 0;
112 - }
113 -
114 - /**************
115 - * Public API *
116 - **************/
117 -
118 179 2 int git_transport_new(git_transport **out, git_remote *owner, const char *url)
119 - {
120 - git_transport_cb fn;
121 - git_transport *transport;
122 - void *param;
123 - int error;
124 -
125 179 2,3 if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
126 17 4 git_error_set(GIT_ERROR_NET, "unsupported URL protocol");
127 17 5 return -1;
128 162 6 } else if (error < 0)
129 ##### 7 return error;
130 -
131 162 8,9 if ((error = fn(&transport, owner, param)) < 0)
132 ##### 10 return error;
133 -
134 162 11-13 GIT_ERROR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
135 -
136 162 14 *out = transport;
137 -
138 162 14 return 0;
139 - }
140 -
141 4 2 int git_transport_register(
142 - const char *scheme,
143 - git_transport_cb cb,
144 - void *param)
145 - {
146 4 2 git_buf prefix = GIT_BUF_INIT;
147 4 2 transport_definition *d, *definition = NULL;
148 - size_t i;
149 4 2 int error = 0;
150 -
151 4 2,3 assert(scheme);
152 4 4,5 assert(cb);
153 -
154 4 6,7 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
155 ##### 8 goto on_error;
156 -
157 4 9,12-14 git_vector_foreach(&custom_transports, i, d) {
158 1 10 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
159 1 11 error = GIT_EEXISTS;
160 1 11 goto on_error;
161 - }
162 - }
163 -
164 3 15 definition = git__calloc(1, sizeof(transport_definition));
165 3 16,17 GIT_ERROR_CHECK_ALLOC(definition);
166 -
167 3 18 definition->prefix = git_buf_detach(&prefix);
168 3 19 definition->fn = cb;
169 3 19 definition->param = param;
170 -
171 3 19,20 if (git_vector_insert(&custom_transports, definition) < 0)
172 ##### 21 goto on_error;
173 -
174 3 22 return 0;
175 -
176 - on_error:
177 1 23 git_buf_dispose(&prefix);
178 1 24 git__free(definition);
179 1 25 return error;
180 - }
181 -
182 4 2 int git_transport_unregister(const char *scheme)
183 - {
184 4 2 git_buf prefix = GIT_BUF_INIT;
185 - transport_definition *d;
186 - size_t i;
187 4 2 int error = 0;
188 -
189 4 2,3 assert(scheme);
190 -
191 4 4,5 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
192 ##### 6 goto done;
193 -
194 4 7,17-19 git_vector_foreach(&custom_transports, i, d) {
195 3 8 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
196 3 9,10 if ((error = git_vector_remove(&custom_transports, i)) < 0)
197 ##### 11 goto done;
198 -
199 3 12 git__free(d->prefix);
200 3 13 git__free(d);
201 -
202 3 14 if (!custom_transports.length)
203 3 15 git_vector_free(&custom_transports);
204 -
205 3 16 error = 0;
206 3 16 goto done;
207 - }
208 - }
209 -
210 1 20 error = GIT_ENOTFOUND;
211 -
212 - done:
213 4 21 git_buf_dispose(&prefix);
214 4 22 return error;
215 - }
216 -
217 1 2 int git_transport_init(git_transport *opts, unsigned int version)
218 - {
219 1 2-4 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
220 - opts, version, git_transport, GIT_TRANSPORT_INIT);
221 1 5 return 0;
222 - }