]> git.proxmox.com Git - libgit2.git/blame - src/transport.c
transport: distinguish between unknown and unsupported transports
[libgit2.git] / src / transport.c
CommitLineData
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 15typedef struct transport_definition {
8f866dae
CMN
16 char *prefix;
17 git_transport_cb fn;
41fb1ca0
PK
18 void *param;
19} transport_definition;
20
41fb1ca0
PK
21static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 };
22static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 };
297758dc 23static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 };
41fb1ca0 24
c180c065 25static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
7261d983 26
41fb1ca0 27static 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 36static git_vector custom_transports = GIT_VECTOR_INIT;
83786956 37
86360ffd 38#define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
2869f404 39
34e510ce 40static 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
64static 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 110int 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, &param)) == 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 133int 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
168on_error:
c180c065
ET
169 git_buf_free(&prefix);
170 git__free(definition);
171 return error;
83786956
PK
172}
173
c180c065 174int 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
204done:
205 git_buf_free(&prefix);
206 return error;
83786956
PK
207}
208
d88d4311
VM
209/* from remote.h */
210int 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, &param);
d88d4311
VM
216}
217
7a544966
RW
218int 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, &param) < 0)
41fb1ca0 224 return 0;
7a544966 225
dbc77850 226 return 1;
7a544966 227}
b9f81997 228
bc91347b 229int 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}