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