mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 10:53:16 +00:00
Download pack
Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
This commit is contained in:
parent
7e1a94db11
commit
da2902204b
32
src/fetch.c
32
src/fetch.c
@ -131,22 +131,6 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Push any (OID) ref it gets into the walker */
|
||||
static int push_stuff(const char *name, void *data)
|
||||
{
|
||||
git_revwalk *walk = (git_revwalk *) data;
|
||||
git_reference *ref;
|
||||
git_repository *repo;
|
||||
int error;
|
||||
|
||||
repo = git_revwalk_repository(walk);
|
||||
error = git_reference_lookup(&ref, repo, name);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
return git_revwalk_push(walk, git_reference_oid(ref));
|
||||
}
|
||||
|
||||
/*
|
||||
* In this first version, we push all our refs in and start sending
|
||||
* them out. When we get an ACK we hide that commit and continue
|
||||
@ -157,12 +141,14 @@ int git_fetch_negotiate(git_headarray *list, git_repository *repo, git_remote *r
|
||||
git_revwalk *walk;
|
||||
int error;
|
||||
unsigned int i;
|
||||
char local[1024];
|
||||
git_refspec *spec;
|
||||
git_reference *ref;
|
||||
git_strarray refs;
|
||||
git_oid oid;
|
||||
|
||||
/* Don't try to negotiate when we don't want anything */
|
||||
if (list->len == 0)
|
||||
return GIT_EINVALIDARGS;
|
||||
|
||||
/*
|
||||
* Now we have everything set up so we can start tell the server
|
||||
* what we want and what we have.
|
||||
@ -201,17 +187,15 @@ int git_fetch_negotiate(git_headarray *list, git_repository *repo, git_remote *r
|
||||
error = GIT_SUCCESS;
|
||||
|
||||
/* TODO: git_pkt_send_flush(fd), or git_transport_flush() */
|
||||
printf("Wound send 0000\n");
|
||||
git_transport_send_flush(remote->transport);
|
||||
git_transport_send_done(remote->transport);
|
||||
|
||||
cleanup:
|
||||
git_revwalk_free(walk);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_fetch_download_pack(git_remote *remote)
|
||||
int git_fetch_download_pack(git_remote *remote, git_repository *repo)
|
||||
{
|
||||
/*
|
||||
* First, we ignore any ACKs we receive and wait for a NACK
|
||||
*/
|
||||
return GIT_ENOTIMPLEMENTED;
|
||||
return git_transport_download_pack(remote->transport, repo);
|
||||
}
|
||||
|
51
src/pkt.c
51
src/pkt.c
@ -52,9 +52,12 @@ static int flush_pkt(git_pkt **out)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int ack_pkt(git_pkt **out, const char *line, size_t len)
|
||||
/* the rest of the line will be useful for multi_ack */
|
||||
static int ack_pkt(git_pkt **out, const char *GIT_UNUSED(line), size_t GIT_UNUSED(len))
|
||||
{
|
||||
git_pkt *pkt;
|
||||
GIT_UNUSED_ARG(line);
|
||||
GIT_UNUSED_ARG(len);
|
||||
|
||||
pkt = git__malloc(sizeof(git_pkt));
|
||||
if (pkt == NULL)
|
||||
@ -66,7 +69,7 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int nack_pkt(git_pkt **out)
|
||||
static int nak_pkt(git_pkt **out)
|
||||
{
|
||||
git_pkt *pkt;
|
||||
|
||||
@ -74,7 +77,21 @@ static int nack_pkt(git_pkt **out)
|
||||
if (pkt == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
pkt->type = GIT_PKT_NACK;
|
||||
pkt->type = GIT_PKT_NAK;
|
||||
*out = pkt;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int pack_pkt(git_pkt **out)
|
||||
{
|
||||
git_pkt *pkt;
|
||||
|
||||
pkt = git__malloc(sizeof(git_pkt));
|
||||
if (pkt == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
pkt->type = GIT_PKT_PACK;
|
||||
*out = pkt;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
@ -184,6 +201,15 @@ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_
|
||||
|
||||
error = parse_len(line);
|
||||
if (error < GIT_SUCCESS) {
|
||||
/*
|
||||
* If we fail to parse the length, it might be because the
|
||||
* server is trying to send us the packfile already.
|
||||
*/
|
||||
if (bufflen >= 4 && !git__prefixcmp(line, "PACK")) {
|
||||
*out = line;
|
||||
return pack_pkt(head);
|
||||
}
|
||||
|
||||
return git__throw(error, "Failed to parse pkt length");
|
||||
}
|
||||
|
||||
@ -216,8 +242,8 @@ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_
|
||||
/* Assming the minimal size is actually 4 */
|
||||
if (!git__prefixcmp(line, "ACK"))
|
||||
error = ack_pkt(head, line, len);
|
||||
else if (!git__prefixcmp(line, "NACK"))
|
||||
error = nack_pkt(head);
|
||||
else if (!git__prefixcmp(line, "NAK"))
|
||||
error = nak_pkt(head);
|
||||
else
|
||||
error = ref_pkt(head, line, len);
|
||||
|
||||
@ -266,11 +292,10 @@ int git_pkt_send_wants(git_headarray *refs, int fd)
|
||||
continue;
|
||||
|
||||
git_oid_fmt(buf + STRLEN(WANT_PREFIX), &head->oid);
|
||||
printf("would send %s", buf);
|
||||
gitno_send(fd, buf, STRLEN(buf), 0);
|
||||
}
|
||||
|
||||
/* TODO: git_pkt_send_flush(fd) */
|
||||
printf("Would send 0000\n");
|
||||
git_pkt_send_flush(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -283,19 +308,15 @@ int git_pkt_send_wants(git_headarray *refs, int fd)
|
||||
|
||||
int git_pkt_send_have(git_oid *oid, int fd)
|
||||
{
|
||||
int ret = GIT_SUCCESS;
|
||||
char buf[] = "0032have 0000000000000000000000000000000000000000\n";
|
||||
|
||||
git_oid_fmt(buf + STRLEN(HAVE_PREFIX), oid);
|
||||
printf("would send %s", buf);
|
||||
|
||||
return ret;
|
||||
return gitno_send(fd, buf, STRLEN(buf), 0);
|
||||
}
|
||||
|
||||
int git_pkt_send_have(int fd)
|
||||
int git_pkt_send_done(int fd)
|
||||
{
|
||||
char buf[] = "0009done\n";
|
||||
printf("Would send %s", buf);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return gitno_send(fd, buf, STRLEN(buf), 0);
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ enum git_pkt_type {
|
||||
GIT_PKT_REF,
|
||||
GIT_PKT_HAVE,
|
||||
GIT_PKT_ACK,
|
||||
GIT_PKT_NACK,
|
||||
GIT_PKT_NAK,
|
||||
GIT_PKT_PACK,
|
||||
};
|
||||
|
||||
/* Used for multi-ack */
|
||||
@ -74,6 +75,7 @@ typedef struct {
|
||||
|
||||
int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
|
||||
int git_pkt_send_flush(int s);
|
||||
int git_pkt_send_done(int s);
|
||||
int git_pkt_send_wants(git_headarray *refs, int fd);
|
||||
int git_pkt_send_have(git_oid *oid, int fd);
|
||||
void git_pkt_free(git_pkt *pkt);
|
||||
|
@ -90,10 +90,21 @@ int git_transport_send_have(struct git_transport *transport, git_oid *oid)
|
||||
return transport->send_have(transport, oid);
|
||||
}
|
||||
|
||||
int git_transport_send_flush(struct git_transport *transport)
|
||||
{
|
||||
return transport->send_flush(transport);
|
||||
}
|
||||
|
||||
int git_transport_send_done(struct git_transport *transport)
|
||||
{
|
||||
return transport->send_done(transport);
|
||||
}
|
||||
|
||||
int git_transport_download_pack(git_transport *transport, git_repository *repo)
|
||||
{
|
||||
return transport->download_pack(transport, repo);
|
||||
}
|
||||
|
||||
int git_transport_close(git_transport *transport)
|
||||
{
|
||||
return transport->close(transport);
|
||||
|
@ -64,6 +64,18 @@ struct git_transport {
|
||||
* Send the list of 'have' refs
|
||||
*/
|
||||
int (*send_have)(struct git_transport *transport, git_oid *oid);
|
||||
/**
|
||||
* Send a 'done' message
|
||||
*/
|
||||
int (*send_done)(struct git_transport *transport);
|
||||
/**
|
||||
* Send a flush
|
||||
*/
|
||||
int (*send_flush)(struct git_transport *transport);
|
||||
/**
|
||||
* Download the packfile
|
||||
*/
|
||||
int (*download_pack)(struct git_transport *transport, git_repository *repo);
|
||||
/**
|
||||
* Fetch the changes
|
||||
*/
|
||||
@ -85,5 +97,7 @@ int git_transport_dummy(struct git_transport **transport);
|
||||
int git_transport_send_wants(struct git_transport *transport, git_headarray *array);
|
||||
int git_transport_send_have(struct git_transport *transport, git_oid *oid);
|
||||
int git_transport_send_done(struct git_transport *transport);
|
||||
int git_transport_send_flush(struct git_transport *transport);
|
||||
int git_transport_download_pack(git_transport *transport, git_repository *repo);
|
||||
|
||||
#endif
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "pkt.h"
|
||||
#include "common.h"
|
||||
#include "netops.h"
|
||||
#include "filebuf.h"
|
||||
#include "repository.h"
|
||||
|
||||
typedef struct {
|
||||
git_transport parent;
|
||||
@ -288,6 +290,13 @@ static int git_send_have(git_transport *transport, git_oid *oid)
|
||||
return git_pkt_send_have(oid, t->socket);
|
||||
}
|
||||
|
||||
static int git_send_flush(git_transport *transport)
|
||||
{
|
||||
transport_git *t = (transport_git *) transport;
|
||||
|
||||
return git_pkt_send_flush(t->socket);
|
||||
}
|
||||
|
||||
static int git_send_done(git_transport *transport)
|
||||
{
|
||||
transport_git *t = (transport_git *) transport;
|
||||
@ -295,6 +304,88 @@ static int git_send_done(git_transport *transport)
|
||||
return git_pkt_send_done(t->socket);
|
||||
}
|
||||
|
||||
static int store_pack(gitno_buffer *buf, git_repository *repo)
|
||||
{
|
||||
git_filebuf file;
|
||||
int error;
|
||||
char path[GIT_PATH_MAX], suff[] = "/objects/pack/pack-XXXX.pack\0";
|
||||
off_t off = 0;
|
||||
|
||||
memcpy(path, repo->path_repository, GIT_PATH_MAX - off);
|
||||
off += strlen(repo->path_repository);
|
||||
memcpy(path + off, suff, GIT_PATH_MAX - off - STRLEN(suff));
|
||||
|
||||
error = git_filebuf_open(&file, path, GIT_FILEBUF_TEMPORARY);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
while (1) {
|
||||
if (buf->offset == 0)
|
||||
break;
|
||||
|
||||
error = git_filebuf_write(&file, buf->data, buf->offset);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
gitno_consume_n(buf, buf->offset);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (error < GIT_SUCCESS)
|
||||
git_filebuf_cleanup(&file);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int git_download_pack(git_transport *transport, git_repository *repo)
|
||||
{
|
||||
transport_git *t = (transport_git *) transport;
|
||||
int s = t->socket, error = GIT_SUCCESS, pack = 0;
|
||||
gitno_buffer buf;
|
||||
char buffer[1024];
|
||||
git_pkt *pkt;
|
||||
const char *line_end, *ptr;
|
||||
|
||||
gitno_buffer_setup(&buf, buffer, sizeof(buffer), s);
|
||||
/*
|
||||
* First, we ignore any ACKs and wait for a NACK
|
||||
*/
|
||||
while (1) {
|
||||
error = gitno_recv(&buf);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(GIT_EOSERR, "Failed to receive data");
|
||||
if (error < GIT_SUCCESS) /* Orderly shutdown */
|
||||
return GIT_SUCCESS;
|
||||
|
||||
ptr = buf.data;
|
||||
/* Whilst we're searching for the pack */
|
||||
while (!pack) {
|
||||
if (buf.offset == 0)
|
||||
break;
|
||||
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset);
|
||||
if (error == GIT_ESHORTBUFFER)
|
||||
break;
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
gitno_consume(&buf, line_end);
|
||||
if (pkt->type == GIT_PKT_PACK)
|
||||
pack = 1;
|
||||
/* For now we don't care about anything */
|
||||
free(pkt);
|
||||
}
|
||||
|
||||
/*
|
||||
* No we have the packet, let's just put anything we get now
|
||||
* into a packfile
|
||||
*/
|
||||
|
||||
return store_pack(&buf, repo);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int git_close(git_transport *transport)
|
||||
{
|
||||
transport_git *t = (transport_git*) transport;
|
||||
@ -341,7 +432,9 @@ int git_transport_git(git_transport **out)
|
||||
t->parent.ls = git_ls;
|
||||
t->parent.send_wants = git_send_wants;
|
||||
t->parent.send_have = git_send_have;
|
||||
t->parent.send_flush = git_send_flush;
|
||||
t->parent.send_done = git_send_done;
|
||||
t->parent.download_pack = git_download_pack;
|
||||
t->parent.close = git_close;
|
||||
t->parent.free = git_free;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user