source src/transport.c
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, ¶m)) == 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 | - | } |