File Coverage

deps/libgit2/src/libgit2/transport.c
Criterion Covered Total %
statement 24 77 31.1
branch 17 56 30.3
condition n/a
subroutine n/a
pod n/a
total 41 133 30.8


line stmt bran cond sub pod time code
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 "fs_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 2           static transport_definition * transport_find_by_url(const char *url)
49             {
50 2           size_t i = 0;
51             transport_definition *d;
52              
53             /* Find a user transport who wants to deal with this URI */
54 2 50         git_vector_foreach(&custom_transports, i, d) {
55 0 0         if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
56 0           return d;
57             }
58             }
59              
60             /* Find a system transport for this URI */
61 9 100         for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
62 8           d = &transports[i];
63              
64 8 100         if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
65 1           return d;
66             }
67             }
68              
69 1           return NULL;
70             }
71              
72 2           static int transport_find_fn(
73             git_transport_cb *out,
74             const char *url,
75             void **param)
76             {
77 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_fs_path_exists(url) && git_fs_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 2 100         if (!definition && strrchr(url, ':')) {
    50          
94             /* re-search transports again with ssh:// as url
95             * so that we can find a third party ssh transport */
96 0           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 2 100         if (!definition && git_fs_path_exists(url) && git_fs_path_isdir(url))
    50          
    50          
102 1           definition = &local_transport_definition;
103             #endif
104              
105 2 50         if (!definition)
106 0           return GIT_ENOTFOUND;
107              
108 2           *out = definition->fn;
109 2           *param = definition->param;
110              
111 2           return 0;
112             }
113              
114             /**************
115             * Public API *
116             **************/
117              
118 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 2 50         if ((error = transport_find_fn(&fn, url, ¶m)) == GIT_ENOTFOUND) {
126 0           git_error_set(GIT_ERROR_NET, "unsupported URL protocol");
127 0           return -1;
128 2 50         } else if (error < 0)
129 0           return error;
130              
131 2 50         if ((error = fn(&transport, owner, param)) < 0)
132 0           return error;
133              
134 2 50         GIT_ERROR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
135              
136 2           *out = transport;
137              
138 2           return 0;
139             }
140              
141 0           int git_transport_register(
142             const char *scheme,
143             git_transport_cb cb,
144             void *param)
145             {
146 0           git_str prefix = GIT_STR_INIT;
147 0           transport_definition *d, *definition = NULL;
148             size_t i;
149 0           int error = 0;
150              
151 0 0         GIT_ASSERT_ARG(scheme);
152 0 0         GIT_ASSERT_ARG(cb);
153              
154 0 0         if ((error = git_str_printf(&prefix, "%s://", scheme)) < 0)
155 0           goto on_error;
156              
157 0 0         git_vector_foreach(&custom_transports, i, d) {
158 0 0         if (strcasecmp(d->prefix, prefix.ptr) == 0) {
159 0           error = GIT_EEXISTS;
160 0           goto on_error;
161             }
162             }
163              
164 0           definition = git__calloc(1, sizeof(transport_definition));
165 0 0         GIT_ERROR_CHECK_ALLOC(definition);
166              
167 0           definition->prefix = git_str_detach(&prefix);
168 0           definition->fn = cb;
169 0           definition->param = param;
170              
171 0 0         if (git_vector_insert(&custom_transports, definition) < 0)
172 0           goto on_error;
173              
174 0           return 0;
175              
176             on_error:
177 0           git_str_dispose(&prefix);
178 0           git__free(definition);
179 0           return error;
180             }
181              
182 0           int git_transport_unregister(const char *scheme)
183             {
184 0           git_str prefix = GIT_STR_INIT;
185             transport_definition *d;
186             size_t i;
187 0           int error = 0;
188              
189 0 0         GIT_ASSERT_ARG(scheme);
190              
191 0 0         if ((error = git_str_printf(&prefix, "%s://", scheme)) < 0)
192 0           goto done;
193              
194 0 0         git_vector_foreach(&custom_transports, i, d) {
195 0 0         if (strcasecmp(d->prefix, prefix.ptr) == 0) {
196 0 0         if ((error = git_vector_remove(&custom_transports, i)) < 0)
197 0           goto done;
198              
199 0           git__free(d->prefix);
200 0           git__free(d);
201              
202 0 0         if (!custom_transports.length)
203 0           git_vector_free(&custom_transports);
204              
205 0           error = 0;
206 0           goto done;
207             }
208             }
209              
210 0           error = GIT_ENOTFOUND;
211              
212             done:
213 0           git_str_dispose(&prefix);
214 0           return error;
215             }
216              
217 0           int git_transport_init(git_transport *opts, unsigned int version)
218             {
219 0 0         GIT_INIT_STRUCTURE_FROM_TEMPLATE(
220             opts, version, git_transport, GIT_TRANSPORT_INIT);
221 0           return 0;
222             }