Commit fc3e3c55 by Carlos Martín Nieto Committed by Vicent Marti

git transport: don't loose received data

Using a different buffer in each function means that some data might
get lost. Store all the data in a buffer in the transport object.

Take this opportunity to use the generic download-pack function.

Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
parent 2c982daa
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "netops.h" #include "netops.h"
#include "filebuf.h" #include "filebuf.h"
#include "repository.h" #include "repository.h"
#include "fetch.h"
typedef struct { typedef struct {
git_transport parent; git_transport parent;
...@@ -26,6 +27,8 @@ typedef struct { ...@@ -26,6 +27,8 @@ typedef struct {
git_vector refs; git_vector refs;
git_remote_head **heads; git_remote_head **heads;
git_transport_caps caps; git_transport_caps caps;
char buff[1024];
gitno_buffer buf;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
WSADATA wsd; WSADATA wsd;
#endif #endif
...@@ -122,28 +125,25 @@ static int do_connect(transport_git *t, const char *url) ...@@ -122,28 +125,25 @@ static int do_connect(transport_git *t, const char *url)
*/ */
static int store_refs(transport_git *t) static int store_refs(transport_git *t)
{ {
gitno_buffer buf; gitno_buffer *buf = &t->buf;
int s = t->socket;
git_vector *refs = &t->refs; git_vector *refs = &t->refs;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
char buffer[1024];
const char *line_end, *ptr; const char *line_end, *ptr;
git_pkt *pkt; git_pkt *pkt;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), s);
while (1) { while (1) {
error = gitno_recv(&buf); error = gitno_recv(buf);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(GIT_EOSERR, "Failed to receive data"); return git__rethrow(GIT_EOSERR, "Failed to receive data");
if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */ if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */
return GIT_SUCCESS; return GIT_SUCCESS;
ptr = buf.data; ptr = buf->data;
while (1) { while (1) {
if (buf.offset == 0) if (buf->offset == 0)
break; break;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset); error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
/* /*
* If the error is GIT_ESHORTBUFFER, it means the buffer * If the error is GIT_ESHORTBUFFER, it means the buffer
* isn't long enough to satisfy the request. Break out and * isn't long enough to satisfy the request. Break out and
...@@ -158,7 +158,7 @@ static int store_refs(transport_git *t) ...@@ -158,7 +158,7 @@ static int store_refs(transport_git *t)
} }
/* Get rid of the part we've used already */ /* Get rid of the part we've used already */
gitno_consume(&buf, line_end); gitno_consume(buf, line_end);
error = git_vector_insert(refs, pkt); error = git_vector_insert(refs, pkt);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -225,6 +225,8 @@ static int git_connect(git_transport *transport, int direction) ...@@ -225,6 +225,8 @@ static int git_connect(git_transport *transport, int direction)
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
gitno_buffer_setup(&t->buf, t->buff, sizeof(t->buff), t->socket);
t->parent.connected = 1; t->parent.connected = 1;
error = store_refs(t); error = store_refs(t);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -274,15 +276,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -274,15 +276,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
git_oid oid; git_oid oid;
int error; int error;
unsigned int i; unsigned int i;
char buff[128]; gitno_buffer *buf = &t->buf;
gitno_buffer buf;
error = git_pkt_send_wants(wants, &t->caps, t->socket); error = git_pkt_send_wants(wants, &t->caps, t->socket);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send wants list"); return git__rethrow(error, "Failed to send wants list");
gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
if (error < GIT_ERROR) if (error < GIT_ERROR)
return git__rethrow(error, "Failed to list all references"); return git__rethrow(error, "Failed to list all references");
...@@ -325,12 +324,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -325,12 +324,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
error = git_pkt_send_have(&oid, t->socket); error = git_pkt_send_have(&oid, t->socket);
i++; i++;
if (i % 20 == 0) { if (i % 20 == 0) {
const char *ptr = buf.data, *line_end; const char *ptr = buf->data, *line_end;
git_pkt *pkt; git_pkt *pkt;
git_pkt_send_flush(t->socket); git_pkt_send_flush(t->socket);
while (1) { while (1) {
/* Wait for max. 1 second */ /* Wait for max. 1 second */
error = gitno_select_in(&buf, 1, 0); error = gitno_select_in(buf, 1, 0);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS) {
error = git__throw(GIT_EOSERR, "Error in select"); error = git__throw(GIT_EOSERR, "Error in select");
} else if (error == 0) { } else if (error == 0) {
...@@ -342,12 +341,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -342,12 +341,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
break; break;
} }
error = gitno_recv(&buf); error = gitno_recv(buf);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS) {
error = git__rethrow(error, "Error receiving data"); error = git__rethrow(error, "Error receiving data");
goto cleanup; goto cleanup;
} }
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset); error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
if (error == GIT_ESHORTBUFFER) if (error == GIT_ESHORTBUFFER)
continue; continue;
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS) {
...@@ -355,7 +354,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -355,7 +354,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
goto cleanup; goto cleanup;
} }
gitno_consume(&buf, line_end); gitno_consume(buf, line_end);
if (pkt->type == GIT_PKT_ACK) { if (pkt->type == GIT_PKT_ACK) {
error = GIT_SUCCESS; error = GIT_SUCCESS;
...@@ -378,6 +377,7 @@ done: ...@@ -378,6 +377,7 @@ done:
cleanup: cleanup:
git_revwalk_free(walk); git_revwalk_free(walk);
return error; return error;
} }
...@@ -395,93 +395,48 @@ static int git_send_done(git_transport *transport) ...@@ -395,93 +395,48 @@ static int git_send_done(git_transport *transport)
return git_pkt_send_done(t->socket); return git_pkt_send_done(t->socket);
} }
static int store_pack(char **out, gitno_buffer *buf, git_repository *repo)
{
git_filebuf file;
int error;
char path[GIT_PATH_MAX], suff[] = "/objects/pack/pack-received\0";
off_t off = 0;
strcpy(path, repo->path_repository);
off += strlen(repo->path_repository);
strcat(path, suff);
//memcpy(path + off, suff, GIT_PATH_MAX - off - strlen(suff) - 1);
if (memcmp(buf->data, "PACK", strlen("PACK"))) {
return git__throw(GIT_ERROR, "The pack doesn't start with the signature");
}
error = git_filebuf_open(&file, path, GIT_FILEBUF_TEMPORARY);
if (error < GIT_SUCCESS)
goto cleanup;
while (1) {
/* Part of the packfile has been received, don't loose it */
error = git_filebuf_write(&file, buf->data, buf->offset);
if (error < GIT_SUCCESS)
goto cleanup;
gitno_consume_n(buf, buf->offset);
error = gitno_recv(buf);
if (error < GIT_SUCCESS)
goto cleanup;
if (error == 0) /* Orderly shutdown */
break;
}
*out = git__strdup(file.path_lock);
if (*out == NULL) {
error = GIT_ENOMEM;
goto cleanup;
}
/* A bit dodgy, but we need to keep the pack at the temporary path */
error = git_filebuf_commit_at(&file, file.path_lock);
cleanup:
if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file);
return error;
}
static int git_download_pack(char **out, git_transport *transport, git_repository *repo) static int git_download_pack(char **out, git_transport *transport, git_repository *repo)
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
int s = t->socket, error = GIT_SUCCESS; int error = GIT_SUCCESS;
gitno_buffer buf; gitno_buffer *buf = &t->buf;
char buffer[1024];
git_pkt *pkt; git_pkt *pkt;
const char *line_end, *ptr; const char *line_end, *ptr;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), s);
/* /*
* For now, we ignore everything and wait for the pack * For now, we ignore everything and wait for the pack
*/ */
while (1) { while (1) {
error = gitno_recv(&buf); ptr = buf->data;
if (error < GIT_SUCCESS)
return git__rethrow(GIT_EOSERR, "Failed to receive data");
if (error == 0) /* Orderly shutdown */
return GIT_SUCCESS;
ptr = buf.data;
/* Whilst we're searching for the pack */ /* Whilst we're searching for the pack */
while (1) { while (1) {
if (buf.offset == 0) if (buf->offset == 0) {
break; break;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset); }
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
if (error == GIT_ESHORTBUFFER) if (error == GIT_ESHORTBUFFER)
break; break;
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
if (pkt->type == GIT_PKT_PACK) if (pkt->type == GIT_PKT_PACK) {
return store_pack(out, &buf, repo); return git_fetch__download_pack(out, buf->data, buf->offset, t->socket, repo);
}
/* For now we don't care about anything */ /* For now we don't care about anything */
free(pkt); free(pkt);
gitno_consume(&buf, line_end); gitno_consume(buf, line_end);
}
error = gitno_recv(buf);
if (error < GIT_SUCCESS)
return git__rethrow(GIT_EOSERR, "Failed to receive data");
if (error == 0) { /* Orderly shutdown */
return GIT_SUCCESS;
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment