]>
git.proxmox.com Git - libgit2.git/blob - src/transports/git.c
2 * Copyright (C) 2009-2011 the libgit2 contributors
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.
9 #include "git2/common.h"
10 #include "git2/types.h"
11 #include "git2/errors.h"
13 #include "git2/revwalk.h"
16 #include "transport.h"
21 #include "repository.h"
30 git_remote_head
**heads
;
31 git_transport_caps caps
;
40 * Create a git procol request.
42 * For example: 0035git-upload-pack /libgit2/libgit2\0host=github.com\0
44 static int gen_proto(git_buf
*request
, const char *cmd
, const char *url
)
47 char default_command
[] = "git-upload-pack";
48 char host
[] = "host=";
51 delim
= strchr(url
, '/');
53 return git__throw(GIT_EOBJCORRUPTED
, "Failed to create proto-request: malformed URL");
57 delim
= strchr(url
, ':');
59 delim
= strchr(url
, '/');
62 cmd
= default_command
;
64 len
= 4 + strlen(cmd
) + 1 + strlen(repo
) + 1 + strlen(host
) + (delim
- url
) + 1;
66 git_buf_grow(request
, len
);
67 git_buf_printf(request
, "%04x%s %s%c%s", len
, cmd
, repo
, 0, host
);
68 git_buf_put(request
, url
, delim
- url
);
69 git_buf_putc(request
, '\0');
71 return git_buf_lasterror(request
);
74 static int send_request(GIT_SOCKET s
, const char *cmd
, const char *url
)
77 git_buf request
= GIT_BUF_INIT
;
79 error
= gen_proto(&request
, cmd
, url
);
80 if (error
< GIT_SUCCESS
)
83 error
= gitno_send(s
, request
.ptr
, request
.size
, 0);
86 git_buf_free(&request
);
91 * Parse the URL and connect to a server, storing the socket in
92 * out. For convenience this also takes care of asking for the remote
95 static int do_connect(transport_git
*t
, const char *url
)
99 const char prefix
[] = "git://";
100 int error
, connected
= 0;
102 if (!git__prefixcmp(url
, prefix
))
103 url
+= strlen(prefix
);
105 error
= gitno_extract_host_and_port(&host
, &port
, url
, GIT_DEFAULT_PORT
);
106 if (error
< GIT_SUCCESS
)
109 s
= gitno_connect(host
, port
);
111 error
= send_request(s
, NULL
, url
);
117 if (error
< GIT_SUCCESS
&& s
> 0)
120 error
= git__throw(GIT_EOSERR
, "Failed to connect to any of the addresses");
126 * Read from the socket and store the references in the vector
128 static int store_refs(transport_git
*t
)
130 gitno_buffer
*buf
= &t
->buf
;
131 int error
= GIT_SUCCESS
;
134 error
= gitno_recv(buf
);
135 if (error
< GIT_SUCCESS
)
136 return git__rethrow(GIT_EOSERR
, "Failed to receive data");
137 if (error
== GIT_SUCCESS
) /* Orderly shutdown, so exit */
140 error
= git_protocol_store_refs(&t
->proto
, buf
->data
, buf
->offset
);
141 if (error
== GIT_ESHORTBUFFER
) {
142 gitno_consume_n(buf
, buf
->len
);
146 if (error
< GIT_SUCCESS
)
147 return git__rethrow(error
, "Failed to store refs");
149 gitno_consume_n(buf
, buf
->offset
);
151 if (t
->proto
.flush
) { /* No more refs */
160 static int detect_caps(transport_git
*t
)
162 git_vector
*refs
= &t
->refs
;
164 git_transport_caps
*caps
= &t
->caps
;
167 pkt
= git_vector_get(refs
, 0);
168 /* No refs or capabilites, odd but not a problem */
169 if (pkt
== NULL
|| pkt
->capabilities
== NULL
)
172 ptr
= pkt
->capabilities
;
173 while (ptr
!= NULL
&& *ptr
!= '\0') {
177 if(!git__prefixcmp(ptr
, GIT_CAP_OFS_DELTA
)) {
178 caps
->common
= caps
->ofs_delta
= 1;
179 ptr
+= strlen(GIT_CAP_OFS_DELTA
);
183 /* We don't know this capability, so skip it */
184 ptr
= strchr(ptr
, ' ');
191 * Since this is a network connection, we need to parse and store the
192 * pkt-lines at this stage and keep them there.
194 static int git_connect(git_transport
*transport
, int direction
)
196 transport_git
*t
= (transport_git
*) transport
;
197 int error
= GIT_SUCCESS
;
199 if (direction
== GIT_DIR_PUSH
)
200 return git__throw(GIT_EINVALIDARGS
, "Pushing is not supported with the git protocol");
202 t
->parent
.direction
= direction
;
203 error
= git_vector_init(&t
->refs
, 16, NULL
);
204 if (error
< GIT_SUCCESS
)
207 /* Connect and ask for the refs */
208 error
= do_connect(t
, transport
->url
);
209 if (error
< GIT_SUCCESS
)
212 gitno_buffer_setup(&t
->buf
, t
->buff
, sizeof(t
->buff
), t
->socket
);
214 t
->parent
.connected
= 1;
215 error
= store_refs(t
);
216 if (error
< GIT_SUCCESS
)
219 error
= detect_caps(t
);
222 if (error
< GIT_SUCCESS
) {
223 git_vector_free(&t
->refs
);
229 static int git_ls(git_transport
*transport
, git_headlist_cb list_cb
, void *opaque
)
231 transport_git
*t
= (transport_git
*) transport
;
232 git_vector
*refs
= &t
->refs
;
236 git_vector_foreach(refs
, i
, p
) {
237 git_pkt_ref
*pkt
= NULL
;
239 if (p
->type
!= GIT_PKT_REF
)
242 pkt
= (git_pkt_ref
*)p
;
244 if (list_cb(&pkt
->head
, opaque
) < 0)
245 return git__throw(GIT_ERROR
,
246 "The user callback returned an error code");
252 static int git_negotiate_fetch(git_transport
*transport
, git_repository
*repo
, const git_vector
*wants
)
254 transport_git
*t
= (transport_git
*) transport
;
261 gitno_buffer
*buf
= &t
->buf
;
263 error
= git_pkt_send_wants(wants
, &t
->caps
, t
->socket
);
264 if (error
< GIT_SUCCESS
)
265 return git__rethrow(error
, "Failed to send wants list");
267 error
= git_reference_listall(&refs
, repo
, GIT_REF_LISTALL
);
268 if (error
< GIT_ERROR
)
269 return git__rethrow(error
, "Failed to list all references");
271 error
= git_revwalk_new(&walk
, repo
);
272 if (error
< GIT_ERROR
) {
273 error
= git__rethrow(error
, "Failed to list all references");
276 git_revwalk_sorting(walk
, GIT_SORT_TIME
);
278 for (i
= 0; i
< refs
.count
; ++i
) {
280 if (!git__prefixcmp(refs
.strings
[i
], GIT_REFS_TAGS_DIR
))
283 error
= git_reference_lookup(&ref
, repo
, refs
.strings
[i
]);
284 if (error
< GIT_ERROR
) {
285 error
= git__rethrow(error
, "Failed to lookup %s", refs
.strings
[i
]);
289 if (git_reference_type(ref
) == GIT_REF_SYMBOLIC
)
292 error
= git_revwalk_push(walk
, git_reference_oid(ref
));
293 if (error
< GIT_ERROR
) {
294 error
= git__rethrow(error
, "Failed to push %s", refs
.strings
[i
]);
298 git_strarray_free(&refs
);
301 * We don't support any kind of ACK extensions, so the negotiation
302 * boils down to sending what we have and listening for an ACK
303 * every once in a while.
306 while ((error
= git_revwalk_next(&oid
, walk
)) == GIT_SUCCESS
) {
307 error
= git_pkt_send_have(&oid
, t
->socket
);
310 const char *ptr
= buf
->data
, *line_end
;
312 git_pkt_send_flush(t
->socket
);
314 /* Wait for max. 1 second */
315 error
= gitno_select_in(buf
, 1, 0);
316 if (error
< GIT_SUCCESS
) {
317 error
= git__throw(GIT_EOSERR
, "Error in select");
318 } else if (error
== 0) {
320 * Some servers don't respond immediately, so if this
321 * happens, we keep sending information until it
327 error
= gitno_recv(buf
);
328 if (error
< GIT_SUCCESS
) {
329 error
= git__rethrow(error
, "Error receiving data");
332 error
= git_pkt_parse_line(&pkt
, ptr
, &line_end
, buf
->offset
);
333 if (error
== GIT_ESHORTBUFFER
)
335 if (error
< GIT_SUCCESS
) {
336 error
= git__rethrow(error
, "Failed to get answer");
340 gitno_consume(buf
, line_end
);
342 if (pkt
->type
== GIT_PKT_ACK
) {
346 } else if (pkt
->type
== GIT_PKT_NAK
) {
350 error
= git__throw(GIT_ERROR
, "Got unexpected pkt type");
356 if (error
== GIT_EREVWALKOVER
)
360 git_pkt_send_flush(t
->socket
);
361 git_pkt_send_done(t
->socket
);
364 git_revwalk_free(walk
);
369 static int git_send_flush(git_transport
*transport
)
371 transport_git
*t
= (transport_git
*) transport
;
373 return git_pkt_send_flush(t
->socket
);
376 static int git_send_done(git_transport
*transport
)
378 transport_git
*t
= (transport_git
*) transport
;
380 return git_pkt_send_done(t
->socket
);
383 static int git_download_pack(char **out
, git_transport
*transport
, git_repository
*repo
)
385 transport_git
*t
= (transport_git
*) transport
;
386 int error
= GIT_SUCCESS
;
387 gitno_buffer
*buf
= &t
->buf
;
389 const char *line_end
, *ptr
;
392 * For now, we ignore everything and wait for the pack
396 /* Whilst we're searching for the pack */
398 if (buf
->offset
== 0) {
402 error
= git_pkt_parse_line(&pkt
, ptr
, &line_end
, buf
->offset
);
403 if (error
== GIT_ESHORTBUFFER
)
406 if (error
< GIT_SUCCESS
)
409 if (pkt
->type
== GIT_PKT_PACK
) {
411 return git_fetch__download_pack(out
, buf
->data
, buf
->offset
, t
->socket
, repo
);
414 /* For now we don't care about anything */
416 gitno_consume(buf
, line_end
);
419 error
= gitno_recv(buf
);
420 if (error
< GIT_SUCCESS
)
421 return git__rethrow(GIT_EOSERR
, "Failed to receive data");
422 if (error
== 0) { /* Orderly shutdown */
430 static int git_close(git_transport
*transport
)
432 transport_git
*t
= (transport_git
*) transport
;
435 /* Can't do anything if there's an error, so don't bother checking */
436 git_pkt_send_flush(t
->socket
);
437 error
= gitno_close(t
->socket
);
440 error
= git__throw(GIT_EOSERR
, "Failed to close socket");
449 static void git_free(git_transport
*transport
)
451 transport_git
*t
= (transport_git
*) transport
;
452 git_vector
*refs
= &t
->refs
;
455 for (i
= 0; i
< refs
->length
; ++i
) {
456 git_pkt
*p
= git_vector_get(refs
, i
);
460 git_vector_free(refs
);
462 git_buf_free(&t
->proto
.buf
);
463 git__free(t
->parent
.url
);
467 int git_transport_git(git_transport
**out
)
474 t
= git__malloc(sizeof(transport_git
));
478 memset(t
, 0x0, sizeof(transport_git
));
480 t
->parent
.connect
= git_connect
;
481 t
->parent
.ls
= git_ls
;
482 t
->parent
.negotiate_fetch
= git_negotiate_fetch
;
483 t
->parent
.send_flush
= git_send_flush
;
484 t
->parent
.send_done
= git_send_done
;
485 t
->parent
.download_pack
= git_download_pack
;
486 t
->parent
.close
= git_close
;
487 t
->parent
.free
= git_free
;
488 t
->proto
.refs
= &t
->refs
;
489 t
->proto
.transport
= (git_transport
*) t
;
491 *out
= (git_transport
*) t
;
494 ret
= WSAStartup(MAKEWORD(2,2), &t
->wsd
);
497 return git__throw(GIT_EOSERR
, "Winsock init failed");