]> git.proxmox.com Git - libgit2.git/blob - src/transport.c
Merge pull request #2455 from ethomson/equal_oid
[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 "path.h"
13
14 typedef struct transport_definition {
15 char *prefix;
16 unsigned priority;
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://", 1, git_transport_local, NULL };
28 #ifdef GIT_SSH
29 static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition };
30 #else
31 static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL };
32 #endif
33
34 static transport_definition transports[] = {
35 {"git://", 1, git_transport_smart, &git_subtransport_definition},
36 {"http://", 1, git_transport_smart, &http_subtransport_definition},
37 {"https://", 1, git_transport_smart, &http_subtransport_definition},
38 {"file://", 1, git_transport_local, NULL},
39 #ifdef GIT_SSH
40 {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition},
41 #endif
42 {NULL, 0, 0}
43 };
44
45 static git_vector additional_transports = GIT_VECTOR_INIT;
46
47 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
48
49 static int transport_find_fn(const char *url, git_transport_cb *callback, void **param)
50 {
51 size_t i = 0;
52 unsigned priority = 0;
53 transport_definition *definition = NULL, *definition_iter;
54
55 // First, check to see if it's an obvious URL, which a URL scheme
56 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
57 definition_iter = &transports[i];
58
59 if (strncasecmp(url, definition_iter->prefix, strlen(definition_iter->prefix)))
60 continue;
61
62 if (definition_iter->priority > priority)
63 definition = definition_iter;
64 }
65
66 git_vector_foreach(&additional_transports, i, definition_iter) {
67 if (strncasecmp(url, definition_iter->prefix, strlen(definition_iter->prefix)))
68 continue;
69
70 if (definition_iter->priority > priority)
71 definition = definition_iter;
72 }
73
74 #ifdef GIT_WIN32
75 /* On Windows, it might not be possible to discern between absolute local
76 * and ssh paths - first check if this is a valid local path that points
77 * to a directory and if so assume local path, else assume SSH */
78
79 /* Check to see if the path points to a file on the local file system */
80 if (!definition && git_path_exists(url) && git_path_isdir(url))
81 definition = &local_transport_definition;
82 #endif
83
84 /* For other systems, perform the SSH check first, to avoid going to the
85 * filesystem if it is not necessary */
86
87 /* It could be a SSH remote path. Check to see if there's a :
88 * SSH is an unsupported transport mechanism in this version of libgit2 */
89 if (!definition && strrchr(url, ':'))
90 #ifdef GIT_SSH
91 definition = &ssh_transport_definition;
92 #else
93 definition = &dummy_transport_definition;
94 #endif
95
96 #ifndef GIT_WIN32
97 /* Check to see if the path points to a file on the local file system */
98 if (!definition && git_path_exists(url) && git_path_isdir(url))
99 definition = &local_transport_definition;
100 #endif
101
102 if (!definition)
103 return -1;
104
105 *callback = definition->fn;
106 *param = definition->param;
107
108 return 0;
109 }
110
111 /**************
112 * Public API *
113 **************/
114
115 int git_transport_dummy(git_transport **transport, git_remote *owner, void *param)
116 {
117 GIT_UNUSED(transport);
118 GIT_UNUSED(owner);
119 GIT_UNUSED(param);
120 giterr_set(GITERR_NET, "This transport isn't implemented. Sorry");
121 return -1;
122 }
123
124 int git_transport_new(git_transport **out, git_remote *owner, const char *url)
125 {
126 git_transport_cb fn;
127 git_transport *transport;
128 void *param;
129 int error;
130
131 if (transport_find_fn(url, &fn, &param) < 0) {
132 giterr_set(GITERR_NET, "Unsupported URL protocol");
133 return -1;
134 }
135
136 if ((error = fn(&transport, owner, param)) < 0)
137 return error;
138
139 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
140
141 *out = transport;
142
143 return 0;
144 }
145
146 int git_transport_register(
147 const char *prefix,
148 unsigned priority,
149 git_transport_cb cb,
150 void *param)
151 {
152 transport_definition *d;
153
154 d = git__calloc(sizeof(transport_definition), 1);
155 GITERR_CHECK_ALLOC(d);
156
157 d->prefix = git__strdup(prefix);
158
159 if (!d->prefix)
160 goto on_error;
161
162 d->priority = priority;
163 d->fn = cb;
164 d->param = param;
165
166 if (git_vector_insert(&additional_transports, d) < 0)
167 goto on_error;
168
169 return 0;
170
171 on_error:
172 git__free(d->prefix);
173 git__free(d);
174 return -1;
175 }
176
177 int git_transport_unregister(
178 const char *prefix,
179 unsigned priority)
180 {
181 transport_definition *d;
182 unsigned i;
183
184 git_vector_foreach(&additional_transports, i, d) {
185 if (d->priority == priority && !strcasecmp(d->prefix, prefix)) {
186 if (git_vector_remove(&additional_transports, i) < 0)
187 return -1;
188
189 git__free(d->prefix);
190 git__free(d);
191
192 if (!additional_transports.length)
193 git_vector_free(&additional_transports);
194
195 return 0;
196 }
197 }
198
199 return GIT_ENOTFOUND;
200 }
201
202 /* from remote.h */
203 int git_remote_valid_url(const char *url)
204 {
205 git_transport_cb fn;
206 void *param;
207
208 return !transport_find_fn(url, &fn, &param);
209 }
210
211 int git_remote_supported_url(const char* url)
212 {
213 git_transport_cb fn;
214 void *param;
215
216 if (transport_find_fn(url, &fn, &param) < 0)
217 return 0;
218
219 return fn != &git_transport_dummy;
220 }
221
222 int git_transport_init(git_transport *opts, unsigned int version)
223 {
224 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
225 opts, version, git_transport, GIT_TRANSPORT_INIT);
226 return 0;
227 }