]> git.proxmox.com Git - libgit2.git/blame - src/libgit2/transport.c
Merge https://salsa.debian.org/debian/libgit2 into proxmox/bullseye
[libgit2.git] / src / libgit2 / 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 */
eae0bfdc 7
8f866dae 8#include "common.h"
eae0bfdc 9
8f866dae 10#include "git2/types.h"
d88d4311 11#include "git2/remote.h"
8f866dae 12#include "git2/net.h"
41fb1ca0 13#include "git2/transport.h"
c180c065 14#include "git2/sys/transport.h"
e579e0f7 15#include "fs_path.h"
8f866dae 16
41fb1ca0 17typedef struct transport_definition {
8f866dae
CMN
18 char *prefix;
19 git_transport_cb fn;
41fb1ca0
PK
20 void *param;
21} transport_definition;
22
142e5379
LY
23static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1, NULL };
24static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0, NULL };
bd3854a0 25#ifdef GIT_SSH
142e5379 26static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0, NULL };
bd3854a0 27#endif
41fb1ca0 28
c180c065 29static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
7261d983 30
41fb1ca0 31static transport_definition transports[] = {
c180c065
ET
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 },
bd3854a0 36#ifdef GIT_SSH
c180c065 37 { "ssh://", git_transport_smart, &ssh_subtransport_definition },
813d73f6
CB
38 { "ssh+git://", git_transport_smart, &ssh_subtransport_definition },
39 { "git+ssh://", git_transport_smart, &ssh_subtransport_definition },
bd3854a0 40#endif
c180c065 41 { NULL, 0, 0 }
8f866dae
CMN
42};
43
c180c065 44static git_vector custom_transports = GIT_VECTOR_INIT;
83786956 45
86360ffd 46#define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
2869f404 47
34e510ce 48static transport_definition * transport_find_by_url(const char *url)
8f866dae 49{
2869f404 50 size_t i = 0;
34e510ce 51 transport_definition *d;
8f866dae 52
c180c065
ET
53 /* Find a user transport who wants to deal with this URI */
54 git_vector_foreach(&custom_transports, i, d) {
55 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
34e510ce 56 return d;
c180c065 57 }
8f866dae
CMN
58 }
59
c180c065 60 /* Find a system transport for this URI */
34e510ce
SS
61 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
62 d = &transports[i];
63
64 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
65 return d;
c180c065 66 }
83786956
PK
67 }
68
34e510ce
SS
69 return NULL;
70}
71
72static int transport_find_fn(
73 git_transport_cb *out,
74 const char *url,
75 void **param)
76{
77 transport_definition *definition = transport_find_by_url(url);
78
cb2ace69
JM
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 */
e579e0f7 85 if (!definition && git_fs_path_exists(url) && git_fs_path_isdir(url))
cb2ace69 86 definition = &local_transport_definition;
ed5b77b0 87#endif
cb2ace69 88
cb2ace69
JM
89 /* For other systems, perform the SSH check first, to avoid going to the
90 * filesystem if it is not necessary */
91
877282ea 92 /* It could be a SSH remote path. Check to see if there's a : */
34e510ce 93 if (!definition && strrchr(url, ':')) {
8b2ad593
RI
94 /* re-search transports again with ssh:// as url
95 * so that we can find a third party ssh transport */
34e510ce 96 definition = transport_find_by_url("ssh://");
34e510ce 97 }
cb2ace69 98
ed5b77b0 99#ifndef GIT_WIN32
cb2ace69 100 /* Check to see if the path points to a file on the local file system */
e579e0f7 101 if (!definition && git_fs_path_exists(url) && git_fs_path_isdir(url))
cb2ace69
JM
102 definition = &local_transport_definition;
103#endif
58448910 104
41fb1ca0 105 if (!definition)
c180c065 106 return GIT_ENOTFOUND;
58448910 107
c180c065 108 *out = definition->fn;
41fb1ca0 109 *param = definition->param;
a3c062db 110
41fb1ca0 111 return 0;
8f866dae
CMN
112}
113
114/**************
115 * Public API *
116 **************/
117
613d5eb9 118int git_transport_new(git_transport **out, git_remote *owner, const char *url)
8f866dae
CMN
119{
120 git_transport_cb fn;
121 git_transport *transport;
41fb1ca0 122 void *param;
8f866dae
CMN
123 int error;
124
c180c065 125 if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
ac3d33df 126 git_error_set(GIT_ERROR_NET, "unsupported URL protocol");
3fbcac89 127 return -1;
c180c065
ET
128 } else if (error < 0)
129 return error;
8f866dae 130
1697cd6f 131 if ((error = fn(&transport, owner, param)) < 0)
4376f7f6 132 return error;
d6258deb 133
ac3d33df 134 GIT_ERROR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
1697cd6f 135
8f866dae
CMN
136 *out = transport;
137
e172cf08 138 return 0;
8f866dae 139}
d88d4311 140
83786956 141int git_transport_register(
c180c065 142 const char *scheme,
83786956
PK
143 git_transport_cb cb,
144 void *param)
145{
e579e0f7 146 git_str prefix = GIT_STR_INIT;
c180c065
ET
147 transport_definition *d, *definition = NULL;
148 size_t i;
149 int error = 0;
83786956 150
c25aa7cd
PP
151 GIT_ASSERT_ARG(scheme);
152 GIT_ASSERT_ARG(cb);
83786956 153
e579e0f7 154 if ((error = git_str_printf(&prefix, "%s://", scheme)) < 0)
83786956
PK
155 goto on_error;
156
c180c065
ET
157 git_vector_foreach(&custom_transports, i, d) {
158 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
159 error = GIT_EEXISTS;
160 goto on_error;
161 }
162 }
163
164 definition = git__calloc(1, sizeof(transport_definition));
ac3d33df 165 GIT_ERROR_CHECK_ALLOC(definition);
c180c065 166
e579e0f7 167 definition->prefix = git_str_detach(&prefix);
c180c065
ET
168 definition->fn = cb;
169 definition->param = param;
83786956 170
c180c065 171 if (git_vector_insert(&custom_transports, definition) < 0)
83786956
PK
172 goto on_error;
173
174 return 0;
175
176on_error:
e579e0f7 177 git_str_dispose(&prefix);
c180c065
ET
178 git__free(definition);
179 return error;
83786956
PK
180}
181
c180c065 182int git_transport_unregister(const char *scheme)
83786956 183{
e579e0f7 184 git_str prefix = GIT_STR_INIT;
83786956 185 transport_definition *d;
c180c065
ET
186 size_t i;
187 int error = 0;
188
c25aa7cd 189 GIT_ASSERT_ARG(scheme);
83786956 190
e579e0f7 191 if ((error = git_str_printf(&prefix, "%s://", scheme)) < 0)
c180c065
ET
192 goto done;
193
194 git_vector_foreach(&custom_transports, i, d) {
195 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
196 if ((error = git_vector_remove(&custom_transports, i)) < 0)
197 goto done;
83786956
PK
198
199 git__free(d->prefix);
200 git__free(d);
201
c180c065
ET
202 if (!custom_transports.length)
203 git_vector_free(&custom_transports);
83786956 204
c180c065
ET
205 error = 0;
206 goto done;
83786956
PK
207 }
208 }
209
c180c065
ET
210 error = GIT_ENOTFOUND;
211
212done:
e579e0f7 213 git_str_dispose(&prefix);
c180c065 214 return error;
83786956
PK
215}
216
bc91347b 217int git_transport_init(git_transport *opts, unsigned int version)
b9f81997 218{
bc91347b
RB
219 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
220 opts, version, git_transport, GIT_TRANSPORT_INIT);
221 return 0;
b9f81997 222}