2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
8 #include "git2/types.h"
9 #include "git2/remote.h"
11 #include "git2/transport.h"
12 #include "git2/sys/transport.h"
15 typedef struct transport_definition
{
19 } transport_definition
;
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 };
24 static git_smart_subtransport_definition ssh_subtransport_definition
= { git_smart_subtransport_ssh
, 0 };
27 static transport_definition local_transport_definition
= { "file://", git_transport_local
, NULL
};
29 static transport_definition ssh_transport_definition
= { "ssh://", git_transport_smart
, &ssh_subtransport_definition
};
31 static transport_definition dummy_transport_definition
= { NULL
, git_transport_dummy
, NULL
};
34 static transport_definition transports
[] = {
35 { "git://", git_transport_smart
, &git_subtransport_definition
},
36 { "http://", git_transport_smart
, &http_subtransport_definition
},
37 { "https://", git_transport_smart
, &http_subtransport_definition
},
38 { "file://", git_transport_local
, NULL
},
40 { "ssh://", git_transport_smart
, &ssh_subtransport_definition
},
45 static git_vector custom_transports
= GIT_VECTOR_INIT
;
47 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
49 static int transport_find_fn(
50 git_transport_cb
*out
,
55 transport_definition
*d
, *definition
= NULL
;
57 /* Find a user transport who wants to deal with this URI */
58 git_vector_foreach(&custom_transports
, i
, d
) {
59 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
65 /* Find a system transport for this URI */
67 for (i
= 0; i
< GIT_TRANSPORT_COUNT
; ++i
) {
70 if (strncasecmp(url
, d
->prefix
, strlen(d
->prefix
)) == 0) {
78 /* On Windows, it might not be possible to discern between absolute local
79 * and ssh paths - first check if this is a valid local path that points
80 * to a directory and if so assume local path, else assume SSH */
82 /* Check to see if the path points to a file on the local file system */
83 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
84 definition
= &local_transport_definition
;
87 /* For other systems, perform the SSH check first, to avoid going to the
88 * filesystem if it is not necessary */
90 /* It could be a SSH remote path. Check to see if there's a :
91 * SSH is an unsupported transport mechanism in this version of libgit2 */
92 if (!definition
&& strrchr(url
, ':'))
94 definition
= &ssh_transport_definition
;
96 definition
= &dummy_transport_definition
;
100 /* Check to see if the path points to a file on the local file system */
101 if (!definition
&& git_path_exists(url
) && git_path_isdir(url
))
102 definition
= &local_transport_definition
;
106 return GIT_ENOTFOUND
;
108 *out
= definition
->fn
;
109 *param
= definition
->param
;
118 int git_transport_dummy(git_transport
**transport
, git_remote
*owner
, void *param
)
120 GIT_UNUSED(transport
);
123 giterr_set(GITERR_NET
, "This transport isn't implemented. Sorry");
127 int git_transport_new(git_transport
**out
, git_remote
*owner
, const char *url
)
130 git_transport
*transport
;
134 if ((error
= transport_find_fn(&fn
, url
, ¶m
)) == GIT_ENOTFOUND
) {
135 giterr_set(GITERR_NET
, "Unsupported URL protocol");
137 } else if (error
< 0)
140 if ((error
= fn(&transport
, owner
, param
)) < 0)
143 GITERR_CHECK_VERSION(transport
, GIT_TRANSPORT_VERSION
, "git_transport");
150 int git_transport_register(
155 git_buf prefix
= GIT_BUF_INIT
;
156 transport_definition
*d
, *definition
= NULL
;
163 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
166 git_vector_foreach(&custom_transports
, i
, d
) {
167 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
173 definition
= git__calloc(1, sizeof(transport_definition
));
174 GITERR_CHECK_ALLOC(definition
);
176 definition
->prefix
= git_buf_detach(&prefix
);
178 definition
->param
= param
;
180 if (git_vector_insert(&custom_transports
, definition
) < 0)
186 git_buf_free(&prefix
);
187 git__free(definition
);
191 int git_transport_unregister(const char *scheme
)
193 git_buf prefix
= GIT_BUF_INIT
;
194 transport_definition
*d
;
200 if ((error
= git_buf_printf(&prefix
, "%s://", scheme
)) < 0)
203 git_vector_foreach(&custom_transports
, i
, d
) {
204 if (strcasecmp(d
->prefix
, prefix
.ptr
) == 0) {
205 if ((error
= git_vector_remove(&custom_transports
, i
)) < 0)
208 git__free(d
->prefix
);
211 if (!custom_transports
.length
)
212 git_vector_free(&custom_transports
);
219 error
= GIT_ENOTFOUND
;
222 git_buf_free(&prefix
);
227 int git_remote_valid_url(const char *url
)
232 return !transport_find_fn(&fn
, url
, ¶m
);
235 int git_remote_supported_url(const char* url
)
240 if (transport_find_fn(&fn
, url
, ¶m
) < 0)
243 return fn
!= &git_transport_dummy
;
246 int git_transport_init(git_transport
*opts
, unsigned int version
)
248 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
249 opts
, version
, git_transport
, GIT_TRANSPORT_INIT
);