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"
14 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://", 1, git_transport_local
, NULL
};
29 static transport_definition ssh_transport_definition
= { "ssh://", 1, git_transport_smart
, &ssh_subtransport_definition
};
31 static transport_definition dummy_transport_definition
= { NULL
, 1, git_transport_dummy
, NULL
};
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
},
40 {"ssh://", 1, git_transport_smart
, &ssh_subtransport_definition
},
45 static git_vector additional_transports
= GIT_VECTOR_INIT
;
47 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
49 static int transport_find_fn(const char *url
, git_transport_cb
*callback
, void **param
)
52 unsigned priority
= 0;
53 transport_definition
*definition
= NULL
, *definition_iter
;
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
];
59 if (strncasecmp(url
, definition_iter
->prefix
, strlen(definition_iter
->prefix
)))
62 if (definition_iter
->priority
> priority
)
63 definition
= definition_iter
;
66 git_vector_foreach(&additional_transports
, i
, definition_iter
) {
67 if (strncasecmp(url
, definition_iter
->prefix
, strlen(definition_iter
->prefix
)))
70 if (definition_iter
->priority
> priority
)
71 definition
= definition_iter
;
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 */
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
;
84 /* For other systems, perform the SSH check first, to avoid going to the
85 * filesystem if it is not necessary */
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
, ':'))
91 definition
= &ssh_transport_definition
;
93 definition
= &dummy_transport_definition
;
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
;
105 *callback
= definition
->fn
;
106 *param
= definition
->param
;
115 int git_transport_dummy(git_transport
**transport
, git_remote
*owner
, void *param
)
117 GIT_UNUSED(transport
);
120 giterr_set(GITERR_NET
, "This transport isn't implemented. Sorry");
124 int git_transport_new(git_transport
**out
, git_remote
*owner
, const char *url
)
127 git_transport
*transport
;
131 if (transport_find_fn(url
, &fn
, ¶m
) < 0) {
132 giterr_set(GITERR_NET
, "Unsupported URL protocol");
136 if ((error
= fn(&transport
, owner
, param
)) < 0)
139 GITERR_CHECK_VERSION(transport
, GIT_TRANSPORT_VERSION
, "git_transport");
146 int git_transport_register(
152 transport_definition
*d
;
154 d
= git__calloc(sizeof(transport_definition
), 1);
155 GITERR_CHECK_ALLOC(d
);
157 d
->prefix
= git__strdup(prefix
);
162 d
->priority
= priority
;
166 if (git_vector_insert(&additional_transports
, d
) < 0)
172 git__free(d
->prefix
);
177 int git_transport_unregister(
181 transport_definition
*d
;
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)
189 git__free(d
->prefix
);
192 if (!additional_transports
.length
)
193 git_vector_free(&additional_transports
);
199 return GIT_ENOTFOUND
;
203 int git_remote_valid_url(const char *url
)
208 return !transport_find_fn(url
, &fn
, ¶m
);
211 int git_remote_supported_url(const char* url
)
216 if (transport_find_fn(url
, &fn
, ¶m
) < 0)
219 return fn
!= &git_transport_dummy
;
222 int git_transport_init(git_transport
*opts
, unsigned int version
)
224 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
225 opts
, version
, git_transport
, GIT_TRANSPORT_INIT
);